agentic-flow-kit 1.8.7 → 2.1.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 (984) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +172 -138
  3. package/bin/flow-kit.mjs +7 -2
  4. package/locales/en/installer.json +110 -0
  5. package/locales/en/overrides/.agents/commands/deploy.md +52 -0
  6. package/locales/en/overrides/.agents/commands/maintain.md +76 -0
  7. package/locales/en/overrides/.agents/commands/new-task.md +89 -0
  8. package/locales/en/overrides/.agents/commands/pipeline-run.md +56 -0
  9. package/locales/en/overrides/.agents/commands/pr-review.md +30 -0
  10. package/locales/en/overrides/.agents/commands/review.md +93 -0
  11. package/locales/en/overrides/.agents/commands/stages.md +256 -0
  12. package/locales/en/overrides/.agents/notes/pr-review-cost-discipline.md +48 -0
  13. package/locales/en/overrides/.agents/notes/process-order-rule.md +21 -0
  14. package/locales/en/overrides/.agents/notes/runtime-env.local.example.md +21 -0
  15. package/locales/en/overrides/.agents/pipelines/_TEMPLATE.md +75 -0
  16. package/locales/en/overrides/.agents/pipelines/pipeline-closing.md +28 -0
  17. package/locales/en/overrides/.agents/roles/implementer.md +28 -0
  18. package/locales/en/overrides/.agents/roles/independent-reviewer.md +39 -0
  19. package/locales/en/overrides/.agents/roles/pr-adjudicator.md +27 -0
  20. package/locales/en/overrides/.agents/roles/pr-finder.md +51 -0
  21. package/locales/en/overrides/.agents/roles/pr-verifier.md +44 -0
  22. package/locales/en/overrides/.agents/roles/ui-verifier.md +22 -0
  23. package/locales/en/overrides/.agents/roles/wiki-compiler.md +47 -0
  24. package/locales/en/overrides/.agents/skills/arena/SKILL.md +50 -0
  25. package/locales/en/overrides/.agents/skills/autonomous-run/SKILL.md +45 -0
  26. package/locales/en/overrides/.agents/skills/blast-radius/SKILL.md +53 -0
  27. package/locales/en/overrides/.agents/skills/csharp-quality-gates/SKILL.md +109 -0
  28. package/locales/en/overrides/.agents/skills/dev-tour/SKILL.md +98 -0
  29. package/locales/en/overrides/.agents/skills/dream/SKILL.md +63 -0
  30. package/locales/en/overrides/.agents/skills/eval/SKILL.md +42 -0
  31. package/locales/en/overrides/.agents/skills/interrogate/SKILL.md +49 -0
  32. package/locales/en/overrides/.agents/skills/number-vetting/SKILL.md +35 -0
  33. package/locales/en/overrides/.agents/skills/page-refactor/SKILL.md +192 -0
  34. package/locales/en/overrides/.agents/skills/papercut-fix/SKILL.md +92 -0
  35. package/locales/en/overrides/.agents/skills/pause-safely/SKILL.md +31 -0
  36. package/locales/en/overrides/.agents/skills/perf/SKILL.md +42 -0
  37. package/locales/en/overrides/.agents/skills/review-method/SKILL.md +92 -0
  38. package/locales/en/overrides/.agents/skills/session-resume/SKILL.md +69 -0
  39. package/locales/en/overrides/.agents/skills/shipyard-workflow-closeout/SKILL.md +109 -0
  40. package/locales/en/overrides/.agents/skills/show-me-your-work/SKILL.md +57 -0
  41. package/locales/en/overrides/.agents/skills/tfs-pr/SKILL.md +95 -0
  42. package/locales/en/overrides/.agents/skills/verify-ui/SKILL.md +116 -0
  43. package/locales/en/overrides/.agents/skills/visual-parity/SKILL.md +35 -0
  44. package/locales/en/overrides/.agents/skills/why/SKILL.md +56 -0
  45. package/locales/en/overrides/.agents/skills/wiki/SKILL.md +53 -0
  46. package/locales/en/overrides/.claude/agents/implementer.md +9 -0
  47. package/locales/en/overrides/.claude/agents/independent-reviewer.md +10 -0
  48. package/locales/en/overrides/.claude/agents/pr-adjudicator.md +10 -0
  49. package/locales/en/overrides/.claude/agents/pr-finder.md +10 -0
  50. package/locales/en/overrides/.claude/agents/pr-verifier.md +10 -0
  51. package/locales/en/overrides/.claude/agents/ui-verifier.md +10 -0
  52. package/locales/en/overrides/.claude/agents/wiki-compiler.md +10 -0
  53. package/locales/en/overrides/.claude/commands/wf-deploy.md +8 -0
  54. package/locales/en/overrides/.claude/commands/wf-maintain.md +8 -0
  55. package/locales/en/overrides/.claude/commands/wf-new-task.md +8 -0
  56. package/locales/en/overrides/.claude/commands/wf-pipeline-run.md +8 -0
  57. package/locales/en/overrides/.claude/commands/wf-pr-review.md +8 -0
  58. package/locales/en/overrides/.claude/commands/wf-review.md +8 -0
  59. package/locales/en/overrides/.claude/commands/wf-stages.md +8 -0
  60. package/locales/en/overrides/.cline/agents/implementer.yml +13 -0
  61. package/locales/en/overrides/.cline/agents/independent-reviewer.yml +11 -0
  62. package/locales/en/overrides/.cline/agents/pr-adjudicator.yml +11 -0
  63. package/locales/en/overrides/.cline/agents/pr-finder.yml +11 -0
  64. package/locales/en/overrides/.cline/agents/pr-verifier.yml +11 -0
  65. package/locales/en/overrides/.cline/agents/ui-verifier.yml +8 -0
  66. package/locales/en/overrides/.cline/agents/wiki-compiler.yml +14 -0
  67. package/locales/en/overrides/.cline/workflows/wf-deploy.md +8 -0
  68. package/locales/en/overrides/.cline/workflows/wf-maintain.md +8 -0
  69. package/locales/en/overrides/.cline/workflows/wf-new-task.md +8 -0
  70. package/locales/en/overrides/.cline/workflows/wf-pipeline-run.md +8 -0
  71. package/locales/en/overrides/.cline/workflows/wf-pr-review.md +8 -0
  72. package/locales/en/overrides/.cline/workflows/wf-review.md +8 -0
  73. package/locales/en/overrides/.cline/workflows/wf-stages.md +8 -0
  74. package/locales/en/overrides/.codebuddy/CODEBUDDY.md +7 -0
  75. package/locales/en/overrides/.codebuddy/agents/implementer.md +9 -0
  76. package/locales/en/overrides/.codebuddy/agents/independent-reviewer.md +10 -0
  77. package/locales/en/overrides/.codebuddy/agents/pr-adjudicator.md +10 -0
  78. package/locales/en/overrides/.codebuddy/agents/pr-finder.md +10 -0
  79. package/locales/en/overrides/.codebuddy/agents/pr-verifier.md +10 -0
  80. package/locales/en/overrides/.codebuddy/agents/ui-verifier.md +11 -0
  81. package/locales/en/overrides/.codebuddy/agents/wiki-compiler.md +10 -0
  82. package/locales/en/overrides/.codebuddy/commands/wf-deploy.md +8 -0
  83. package/locales/en/overrides/.codebuddy/commands/wf-maintain.md +8 -0
  84. package/locales/en/overrides/.codebuddy/commands/wf-new-task.md +8 -0
  85. package/locales/en/overrides/.codebuddy/commands/wf-pipeline-run.md +8 -0
  86. package/locales/en/overrides/.codebuddy/commands/wf-pr-review.md +8 -0
  87. package/locales/en/overrides/.codebuddy/commands/wf-review.md +8 -0
  88. package/locales/en/overrides/.codebuddy/commands/wf-stages.md +8 -0
  89. package/locales/en/overrides/.codebuddy/rules/backend-scope.md +5 -0
  90. package/locales/en/overrides/.codebuddy/rules/frontend-scope.md +5 -0
  91. package/locales/en/overrides/.codebuddy/skills/tfs-pr/SKILL.md +6 -0
  92. package/locales/en/overrides/.commandcode/agents/implementer.md +10 -0
  93. package/locales/en/overrides/.commandcode/agents/independent-reviewer.md +9 -0
  94. package/locales/en/overrides/.commandcode/agents/pr-adjudicator.md +9 -0
  95. package/locales/en/overrides/.commandcode/agents/pr-finder.md +9 -0
  96. package/locales/en/overrides/.commandcode/agents/pr-verifier.md +9 -0
  97. package/locales/en/overrides/.commandcode/agents/ui-verifier.md +10 -0
  98. package/locales/en/overrides/.commandcode/agents/wiki-compiler.md +10 -0
  99. package/locales/en/overrides/.commandcode/commands/wf-deploy.md +7 -0
  100. package/locales/en/overrides/.commandcode/commands/wf-maintain.md +7 -0
  101. package/locales/en/overrides/.commandcode/commands/wf-new-task.md +7 -0
  102. package/locales/en/overrides/.commandcode/commands/wf-pipeline-run.md +7 -0
  103. package/locales/en/overrides/.commandcode/commands/wf-pr-review.md +7 -0
  104. package/locales/en/overrides/.commandcode/commands/wf-review.md +7 -0
  105. package/locales/en/overrides/.commandcode/commands/wf-stages.md +7 -0
  106. package/locales/en/overrides/.opencode/agents/implementer.md +51 -0
  107. package/locales/en/overrides/.opencode/agents/independent-reviewer.md +18 -0
  108. package/locales/en/overrides/.opencode/agents/pr-adjudicator.md +18 -0
  109. package/locales/en/overrides/.opencode/agents/pr-finder.md +18 -0
  110. package/locales/en/overrides/.opencode/agents/pr-verifier.md +18 -0
  111. package/locales/en/overrides/.opencode/agents/ui-verifier.md +45 -0
  112. package/locales/en/overrides/.opencode/agents/wiki-compiler.md +51 -0
  113. package/locales/en/overrides/.opencode/commands/wf-deploy.md +7 -0
  114. package/locales/en/overrides/.opencode/commands/wf-maintain.md +7 -0
  115. package/locales/en/overrides/.opencode/commands/wf-new-task.md +7 -0
  116. package/locales/en/overrides/.opencode/commands/wf-pipeline-run.md +7 -0
  117. package/locales/en/overrides/.opencode/commands/wf-pr-review.md +7 -0
  118. package/locales/en/overrides/.opencode/commands/wf-review.md +7 -0
  119. package/locales/en/overrides/.opencode/commands/wf-stages.md +7 -0
  120. package/locales/en/overrides/.pi/agents/implementer.md +11 -0
  121. package/locales/en/overrides/.pi/agents/independent-reviewer.md +12 -0
  122. package/locales/en/overrides/.pi/agents/pr-adjudicator.md +12 -0
  123. package/locales/en/overrides/.pi/agents/pr-finder.md +11 -0
  124. package/locales/en/overrides/.pi/agents/pr-verifier.md +11 -0
  125. package/locales/en/overrides/.pi/agents/ui-verifier.md +11 -0
  126. package/locales/en/overrides/.pi/agents/wiki-compiler.md +11 -0
  127. package/locales/en/overrides/.qoder/agents/implementer.md +9 -0
  128. package/locales/en/overrides/.qoder/agents/independent-reviewer.md +10 -0
  129. package/locales/en/overrides/.qoder/agents/pr-adjudicator.md +10 -0
  130. package/locales/en/overrides/.qoder/agents/pr-finder.md +10 -0
  131. package/locales/en/overrides/.qoder/agents/pr-verifier.md +10 -0
  132. package/locales/en/overrides/.qoder/agents/ui-verifier.md +10 -0
  133. package/locales/en/overrides/.qoder/agents/wiki-compiler.md +10 -0
  134. package/locales/en/overrides/.qoder/commands/wf-deploy.md +8 -0
  135. package/locales/en/overrides/.qoder/commands/wf-maintain.md +8 -0
  136. package/locales/en/overrides/.qoder/commands/wf-new-task.md +8 -0
  137. package/locales/en/overrides/.qoder/commands/wf-pipeline-run.md +8 -0
  138. package/locales/en/overrides/.qoder/commands/wf-pr-review.md +8 -0
  139. package/locales/en/overrides/.qoder/commands/wf-review.md +8 -0
  140. package/locales/en/overrides/.qoder/commands/wf-stages.md +8 -0
  141. package/locales/en/overrides/.qwen/agents/implementer.md +10 -0
  142. package/locales/en/overrides/.qwen/agents/independent-reviewer.md +10 -0
  143. package/locales/en/overrides/.qwen/agents/pr-adjudicator.md +10 -0
  144. package/locales/en/overrides/.qwen/agents/pr-finder.md +10 -0
  145. package/locales/en/overrides/.qwen/agents/pr-verifier.md +10 -0
  146. package/locales/en/overrides/.qwen/agents/ui-verifier.md +10 -0
  147. package/locales/en/overrides/.qwen/agents/wiki-compiler.md +13 -0
  148. package/locales/en/overrides/.qwen/commands/wf-deploy.md +7 -0
  149. package/locales/en/overrides/.qwen/commands/wf-maintain.md +7 -0
  150. package/locales/en/overrides/.qwen/commands/wf-new-task.md +7 -0
  151. package/locales/en/overrides/.qwen/commands/wf-pipeline-run.md +7 -0
  152. package/locales/en/overrides/.qwen/commands/wf-pr-review.md +7 -0
  153. package/locales/en/overrides/.qwen/commands/wf-review.md +7 -0
  154. package/locales/en/overrides/.qwen/commands/wf-stages.md +7 -0
  155. package/locales/en/overrides/.trae/agents/implementer.md +9 -0
  156. package/locales/en/overrides/.trae/agents/independent-reviewer.md +10 -0
  157. package/locales/en/overrides/.trae/agents/pr-adjudicator.md +10 -0
  158. package/locales/en/overrides/.trae/agents/pr-finder.md +10 -0
  159. package/locales/en/overrides/.trae/agents/pr-verifier.md +10 -0
  160. package/locales/en/overrides/.trae/agents/ui-verifier.md +10 -0
  161. package/locales/en/overrides/.trae/agents/wiki-compiler.md +10 -0
  162. package/locales/en/overrides/.trae/commands/wf-deploy.md +8 -0
  163. package/locales/en/overrides/.trae/commands/wf-maintain.md +8 -0
  164. package/locales/en/overrides/.trae/commands/wf-new-task.md +8 -0
  165. package/locales/en/overrides/.trae/commands/wf-pipeline-run.md +8 -0
  166. package/locales/en/overrides/.trae/commands/wf-pr-review.md +8 -0
  167. package/locales/en/overrides/.trae/commands/wf-review.md +8 -0
  168. package/locales/en/overrides/.trae/commands/wf-stages.md +8 -0
  169. package/locales/en/overrides/.trae/rules/backend-scope.md +5 -0
  170. package/locales/en/overrides/.trae/rules/frontend-scope.md +5 -0
  171. package/locales/en/overrides/.zcode/agents/implementer.md +8 -0
  172. package/locales/en/overrides/.zcode/agents/independent-reviewer.md +8 -0
  173. package/locales/en/overrides/.zcode/agents/ui-verifier.md +8 -0
  174. package/locales/en/overrides/.zcode/agents/wiki-compiler.md +8 -0
  175. package/locales/en/overrides/AGENTS.md +52 -0
  176. package/locales/en/overrides/CLAUDE.md +20 -0
  177. package/locales/en/overrides/wiki/INDEX.md +33 -0
  178. package/locales/en/overrides/wiki/drafts-archive/README.md +6 -0
  179. package/locales/en/overrides/wiki//346/225/260/346/215/256/347/273/264/346/212/244/README.md +22 -0
  180. package/locales/en/overrides/wiki//347/237/245/350/257/206/346/262/211/346/267/200/346/200/273/350/247/210.html +230 -0
  181. package/locales/en/overrides/workflow/INDEX.md +13 -0
  182. package/locales/en/overrides/workflow/README.md +69 -0
  183. package/locales/en/overrides/workflow/archive/README.md +3 -0
  184. package/locales/en/overrides/workflow/delegations.md +4 -0
  185. package/locales/en/overrides/workflow/effective-policy.md +4 -0
  186. package/locales/en/overrides/workflow/gate-cost.md +4 -0
  187. package/locales/en/overrides/workflow/incidents/_TEMPLATE.md +49 -0
  188. package/locales/en/overrides/workflow/intents/_TEMPLATE.md +43 -0
  189. package/locales/en/overrides/workflow/metrics.md +4 -0
  190. package/locales/en/overrides/workflow/papercuts.md +3 -0
  191. package/locales/en/overrides/workflow/plans/_TEMPLATE.md +47 -0
  192. package/locales/en/overrides/workflow/regression-checklist.md +3 -0
  193. package/locales/en/overrides/workflow/specs/_TEMPLATE.md +86 -0
  194. package/locales/en/overrides/workflow/verify-evidence.md +4 -0
  195. package/locales/zh-CN/installer.json +110 -0
  196. package/package.json +23 -36
  197. package/schemas/install-manifest.schema.json +26 -0
  198. package/schemas/project-profile.schema.json +28 -0
  199. package/src/cli/args.mjs +43 -0
  200. package/src/cli/main.mjs +79 -0
  201. package/src/commands/add-host.mjs +29 -0
  202. package/src/commands/doctor.mjs +126 -0
  203. package/src/commands/install.mjs +296 -0
  204. package/src/commands/upgrade.mjs +30 -0
  205. package/src/git/config.mjs +61 -0
  206. package/src/hosts/registry.mjs +170 -0
  207. package/src/i18n.mjs +35 -0
  208. package/src/install/apply.mjs +138 -0
  209. package/src/install/frontmatter.mjs +84 -0
  210. package/src/install/manifest.mjs +40 -0
  211. package/src/install/plan.mjs +241 -0
  212. package/src/models/known.mjs +13 -0
  213. package/src/models/probe.mjs +163 -0
  214. package/src/models/resolve.mjs +312 -0
  215. package/src/render/tokens.mjs +105 -0
  216. package/src/tui/ansi.mjs +55 -0
  217. package/src/tui/flows.mjs +306 -0
  218. package/src/tui/prompts.mjs +139 -0
  219. package/src/tui/screen.mjs +217 -0
  220. package/src/tui/widgets.mjs +111 -0
  221. package/src/tui/wizard.mjs +68 -0
  222. package/templates/engine/.agents/board/dev-tour.html +1940 -0
  223. package/templates/engine/.agents/board/index.html +835 -0
  224. package/templates/engine/.agents/commands/deploy.md +52 -0
  225. package/templates/engine/.agents/commands/maintain.md +76 -0
  226. package/templates/engine/.agents/commands/new-task.md +89 -0
  227. package/templates/engine/.agents/commands/pipeline-run.md +60 -0
  228. package/templates/engine/.agents/commands/pr-review.md +30 -0
  229. package/templates/engine/.agents/commands/review.md +93 -0
  230. package/templates/engine/.agents/commands/stages.md +257 -0
  231. package/templates/engine/.agents/config/agent-eval.json +17 -0
  232. package/templates/engine/.agents/config/commit-msg-rules.json +7 -0
  233. package/templates/engine/.agents/config/engine.json +11 -0
  234. package/templates/engine/.agents/config/gate-budgets.json +5 -0
  235. package/templates/engine/.agents/config/mechanism-registry.md +63 -0
  236. package/templates/engine/.agents/config/memory-tiers.json +13 -0
  237. package/templates/engine/.agents/config/model-roles.json +26 -0
  238. package/templates/engine/.agents/config/model-roles.local.example.json +7 -0
  239. package/templates/engine/.agents/config/pipeline.json +36 -0
  240. package/templates/engine/.agents/config/pr-review.json +67 -0
  241. package/templates/engine/.agents/config/principles.md +32 -0
  242. package/templates/engine/.agents/config/steering.json +28 -0
  243. package/templates/engine/.agents/config/workflow-enums.txt +25 -0
  244. package/templates/engine/.agents/evals/README.md +49 -0
  245. package/templates/engine/.agents/evals/tasks.tsv +6 -0
  246. package/templates/engine/.agents/hooks/check-architecture.mjs +168 -0
  247. package/templates/engine/.agents/hooks/check-audit-fields.mjs +56 -0
  248. package/templates/engine/.agents/hooks/check-commit-plan-ref.mjs +84 -0
  249. package/templates/engine/.agents/hooks/check-confirm-order.mjs +281 -0
  250. package/templates/engine/.agents/hooks/check-delete-guard.mjs +63 -0
  251. package/templates/engine/.agents/hooks/check-notify-guard.mjs +55 -0
  252. package/templates/engine/.agents/hooks/commit-check.cjs +208 -0
  253. package/templates/engine/.agents/hooks/gates.json +33 -0
  254. package/templates/engine/.agents/hooks/local-pre-commit.mjs +27 -0
  255. package/templates/engine/.agents/hooks/pre-shell-check.cjs +361 -0
  256. package/templates/engine/.agents/hooks/pre-write-check.cjs +247 -0
  257. package/templates/engine/.agents/notes/gate-diet.md +75 -0
  258. package/templates/engine/.agents/notes/injected-memory.md +14 -0
  259. package/templates/engine/.agents/notes/pr-review-cost-discipline.md +48 -0
  260. package/templates/engine/.agents/notes/process-order-rule.md +21 -0
  261. package/templates/engine/.agents/notes/runtime-env.local.example.md +21 -0
  262. package/templates/engine/.agents/notes/steering-tiers.md +28 -0
  263. package/templates/engine/.agents/pipelines/_TEMPLATE.md +75 -0
  264. package/templates/engine/.agents/pipelines/pipeline-closing.md +28 -0
  265. package/templates/engine/.agents/pipelines//347/244/272/344/276/213-/345/271/266/350/241/214/345/256/236/347/216/260/350/257/204/345/256/241.md +16 -0
  266. package/templates/engine/.agents/roles/implementer.md +28 -0
  267. package/templates/engine/.agents/roles/independent-reviewer.md +39 -0
  268. package/templates/engine/.agents/roles/pr-adjudicator.md +27 -0
  269. package/templates/engine/.agents/roles/pr-finder.md +51 -0
  270. package/templates/engine/.agents/roles/pr-verifier.md +44 -0
  271. package/templates/engine/.agents/roles/ui-verifier.md +22 -0
  272. package/templates/engine/.agents/roles/wiki-compiler.md +47 -0
  273. package/templates/engine/.agents/scripts/agent-eval.mjs +268 -0
  274. package/templates/engine/.agents/scripts/agg-delegations.mjs +439 -0
  275. package/templates/engine/.agents/scripts/agg-judgments.mjs +301 -0
  276. package/templates/engine/.agents/scripts/agg-kb-usage.mjs +196 -0
  277. package/templates/engine/.agents/scripts/append-compensation.mjs +109 -0
  278. package/templates/engine/.agents/scripts/archive-sweep.mjs +229 -0
  279. package/templates/engine/.agents/scripts/auto-tour.mjs +77 -0
  280. package/templates/engine/.agents/scripts/board-port.mjs +17 -0
  281. package/templates/engine/.agents/scripts/check-doc-body-drift.mjs +102 -0
  282. package/templates/engine/.agents/scripts/check-engine-artifacts.mjs +54 -0
  283. package/templates/engine/.agents/scripts/check-hook-wiring.mjs +75 -0
  284. package/templates/engine/.agents/scripts/check-lane-surface.mjs +393 -0
  285. package/templates/engine/.agents/scripts/check-ledger-doc-presence.mjs +71 -0
  286. package/templates/engine/.agents/scripts/check-ledger-invariant.mjs +873 -0
  287. package/templates/engine/.agents/scripts/check-local-gate-config.mjs +95 -0
  288. package/templates/engine/.agents/scripts/check-local-gates.mjs +248 -0
  289. package/templates/engine/.agents/scripts/check-loop-kit.mjs +550 -0
  290. package/templates/engine/.agents/scripts/check-loop-rev-semantics.mjs +59 -0
  291. package/templates/engine/.agents/scripts/check-loop-sections/s01-pairing.mjs +116 -0
  292. package/templates/engine/.agents/scripts/check-loop-sections/s03x-regr-evidence.mjs +38 -0
  293. package/templates/engine/.agents/scripts/check-loop-sections/s08-acceptance.mjs +130 -0
  294. package/templates/engine/.agents/scripts/check-loop-sections/s15-fingerprint.mjs +152 -0
  295. package/templates/engine/.agents/scripts/check-loop-sections/s23-convergence-audit.mjs +182 -0
  296. package/templates/engine/.agents/scripts/check-loop-sections/s29-regr-enforcer.mjs +69 -0
  297. package/templates/engine/.agents/scripts/check-loop.mjs +131 -0
  298. package/templates/engine/.agents/scripts/check-pipeline-state.mjs +85 -0
  299. package/templates/engine/.agents/scripts/check-regression-consistency.mjs +252 -0
  300. package/templates/engine/.agents/scripts/check-schema-residue.mjs +144 -0
  301. package/templates/engine/.agents/scripts/check-scope-range.mjs +156 -0
  302. package/templates/engine/.agents/scripts/check-scope.mjs +121 -0
  303. package/templates/engine/.agents/scripts/check-scripts-syntax.mjs +138 -0
  304. package/templates/engine/.agents/scripts/check-secrets-lite.mjs +239 -0
  305. package/templates/engine/.agents/scripts/check-secrets.mjs +104 -0
  306. package/templates/engine/.agents/scripts/check-test-impact-map.mjs +107 -0
  307. package/templates/engine/.agents/scripts/ci-assert-frontend-deps.mjs +42 -0
  308. package/templates/engine/.agents/scripts/ci-commit-hygiene.mjs +86 -0
  309. package/templates/engine/.agents/scripts/ci-install-gitleaks.mjs +75 -0
  310. package/templates/engine/.agents/scripts/ci-push-before.mjs +49 -0
  311. package/templates/engine/.agents/scripts/claims.mjs +166 -0
  312. package/templates/engine/.agents/scripts/closeout.mjs +127 -0
  313. package/templates/engine/.agents/scripts/compact-ledgers.mjs +70 -0
  314. package/templates/engine/.agents/scripts/confirm-doc.mjs +737 -0
  315. package/templates/engine/.agents/scripts/delegation-presence.mjs +38 -0
  316. package/templates/engine/.agents/scripts/dev-tour-model.mjs +1398 -0
  317. package/templates/engine/.agents/scripts/dream-run.mjs +358 -0
  318. package/templates/engine/.agents/scripts/ensure-board.mjs +187 -0
  319. package/templates/engine/.agents/scripts/failure-attribution.mjs +11 -0
  320. package/templates/engine/.agents/scripts/fill-intent.mjs +60 -0
  321. package/templates/engine/.agents/scripts/fill-plan.mjs +105 -0
  322. package/templates/engine/.agents/scripts/fill-spec.mjs +72 -0
  323. package/templates/engine/.agents/scripts/fix-task.mjs +77 -0
  324. package/templates/engine/.agents/scripts/gen-dev-tour.mjs +191 -0
  325. package/templates/engine/.agents/scripts/gen-effective-policy.mjs +113 -0
  326. package/templates/engine/.agents/scripts/gen-engine-map.mjs +292 -0
  327. package/templates/engine/.agents/scripts/gen-narrative-claims.mjs +275 -0
  328. package/templates/engine/.agents/scripts/gen-verify-evidence.mjs +115 -0
  329. package/templates/engine/.agents/scripts/gen-wiki-board.mjs +221 -0
  330. package/templates/engine/.agents/scripts/gen-workflow-index.mjs +201 -0
  331. package/templates/engine/.agents/scripts/gen-workflow-metrics.mjs +692 -0
  332. package/templates/engine/.agents/scripts/git-merge-jsonl.mjs +62 -0
  333. package/templates/engine/.agents/scripts/judgment-ledger.mjs +68 -0
  334. package/templates/engine/.agents/scripts/kb-cache-evict.mjs +50 -0
  335. package/templates/engine/.agents/scripts/kb-search.mjs +423 -0
  336. package/templates/engine/.agents/scripts/lane-surface-audit.mjs +145 -0
  337. package/templates/engine/.agents/scripts/ledger-loader.mjs +77 -0
  338. package/templates/engine/.agents/scripts/ledger-shards.mjs +346 -0
  339. package/templates/engine/.agents/scripts/memory-tier.mjs +196 -0
  340. package/templates/engine/.agents/scripts/memory-wiki.mjs +296 -0
  341. package/templates/engine/.agents/scripts/metrics-core.mjs +131 -0
  342. package/templates/engine/.agents/scripts/outcome-metrics.mjs +195 -0
  343. package/templates/engine/.agents/scripts/path-lease.mjs +177 -0
  344. package/templates/engine/.agents/scripts/pipeline-run.mjs +964 -0
  345. package/templates/engine/.agents/scripts/policy.mjs +250 -0
  346. package/templates/engine/.agents/scripts/pr-create.mjs +54 -0
  347. package/templates/engine/.agents/scripts/pr-review.mjs +1551 -0
  348. package/templates/engine/.agents/scripts/quote-grounding.mjs +233 -0
  349. package/templates/engine/.agents/scripts/regen-ledgers.mjs +59 -0
  350. package/templates/engine/.agents/scripts/rewrite-file.mjs +135 -0
  351. package/templates/engine/.agents/scripts/rule-budget.mjs +246 -0
  352. package/templates/engine/.agents/scripts/session-log.mjs +157 -0
  353. package/templates/engine/.agents/scripts/stage-gates.mjs +812 -0
  354. package/templates/engine/.agents/scripts/steering.mjs +75 -0
  355. package/templates/engine/.agents/scripts/test-impact-lib.mjs +451 -0
  356. package/templates/engine/.agents/scripts/test-impact.mjs +105 -0
  357. package/templates/engine/.agents/scripts/trust-mode.mjs +130 -0
  358. package/templates/engine/.agents/scripts/verify-scope.mjs +163 -0
  359. package/templates/engine/.agents/scripts/verify-wiki-consistency.mjs +264 -0
  360. package/templates/engine/.agents/scripts/verify.mjs +858 -0
  361. package/templates/engine/.agents/scripts/warn-format.mjs +57 -0
  362. package/templates/engine/.agents/scripts/wf-journal.mjs +230 -0
  363. package/templates/engine/.agents/scripts/workflow-board-server.mjs +696 -0
  364. package/templates/engine/.agents/scripts/workflow-enums.mjs +70 -0
  365. package/templates/engine/.agents/scripts/workflows-check.mjs +260 -0
  366. package/templates/engine/.agents/settings.json +33 -0
  367. package/templates/engine/.agents/skills/arena/SKILL.md +54 -0
  368. package/templates/engine/.agents/skills/autonomous-run/SKILL.md +45 -0
  369. package/templates/engine/.agents/skills/blast-radius/SKILL.md +53 -0
  370. package/templates/engine/.agents/skills/csharp-quality-gates/SKILL.md +109 -0
  371. package/templates/engine/.agents/skills/csharp-quality-gates/scripts/quality-gates.mjs +430 -0
  372. package/templates/engine/.agents/skills/dev-tour/SKILL.md +98 -0
  373. package/templates/engine/.agents/skills/dream/SKILL.md +82 -0
  374. package/templates/engine/.agents/skills/eval/SKILL.md +58 -0
  375. package/templates/engine/.agents/skills/eval/scripts/eval-score.mjs +59 -0
  376. package/templates/engine/.agents/skills/interrogate/SKILL.md +49 -0
  377. package/templates/engine/.agents/skills/interrogate/scripts/interrogate-plan.mjs +72 -0
  378. package/templates/engine/.agents/skills/model-upgrade/SKILL.md +41 -0
  379. package/templates/engine/.agents/skills/number-vetting/SKILL.md +35 -0
  380. package/templates/engine/.agents/skills/page-refactor/SKILL.md +192 -0
  381. package/templates/engine/.agents/skills/page-refactor/references/templates.md +989 -0
  382. package/templates/engine/.agents/skills/papercut-fix/SKILL.md +92 -0
  383. package/templates/engine/.agents/skills/papercut-fix/references/response-template.md +81 -0
  384. package/templates/engine/.agents/skills/pause-safely/SKILL.md +31 -0
  385. package/templates/engine/.agents/skills/perf/SKILL.md +42 -0
  386. package/templates/engine/.agents/skills/review-method/SKILL.md +92 -0
  387. package/templates/engine/.agents/skills/review-method/golden-set.md +61 -0
  388. package/templates/engine/.agents/skills/session-resume/SKILL.md +76 -0
  389. package/templates/engine/.agents/skills/session-resume/scripts/worktree-audit.mjs +110 -0
  390. package/templates/engine/.agents/skills/shipyard-workflow-closeout/SKILL.md +109 -0
  391. package/templates/engine/.agents/skills/show-me-your-work/SKILL.md +71 -0
  392. package/templates/engine/.agents/skills/show-me-your-work/references/decision-log-template.tsv +1 -0
  393. package/templates/engine/.agents/skills/show-me-your-work/scripts/decision-log.mjs +24 -0
  394. package/templates/engine/.agents/skills/tfs-pr/SKILL.md +95 -0
  395. package/templates/engine/.agents/skills/tfs-pr/scripts/tfs-pr.mjs +947 -0
  396. package/templates/engine/.agents/skills/verify-ui/SKILL.md +116 -0
  397. package/templates/engine/.agents/skills/verify-ui/features/.gitkeep +0 -0
  398. package/templates/engine/.agents/skills/verify-ui/scripts/gen-verify-feature.mjs +114 -0
  399. package/templates/engine/.agents/skills/visual-parity/SKILL.md +35 -0
  400. package/templates/engine/.agents/skills/why/SKILL.md +56 -0
  401. package/templates/engine/.agents/skills/why/scripts/why-evidence.mjs +74 -0
  402. package/templates/engine/.agents/skills/wiki/SKILL.md +56 -0
  403. package/templates/engine/.agents/tests/auto-tour.test.mjs +82 -0
  404. package/templates/engine/.agents/tests/dev-tour-model.test.mjs +452 -0
  405. package/templates/engine/.agents/tests/fill-plan-lite.test.mjs +46 -0
  406. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-bare-mid-path.md +14 -0
  407. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-bare-mid-path.model.json +179 -0
  408. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-fake-path-guard.md +21 -0
  409. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-fake-path-guard.model.json +194 -0
  410. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-h3-batches.md +20 -0
  411. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-h3-batches.model.json +207 -0
  412. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-issues.md +24 -0
  413. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-issues.model.json +225 -0
  414. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-l1-single-file.md +15 -0
  415. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-l1-single-file.model.json +160 -0
  416. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-layer-word-unique.md +29 -0
  417. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-layer-word-unique.model.json +266 -0
  418. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-layers-fallback.md +17 -0
  419. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-layers-fallback.model.json +207 -0
  420. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-numbered-steps.md +39 -0
  421. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-numbered-steps.model.json +359 -0
  422. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-path-guess.md +16 -0
  423. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-path-guess.model.json +131 -0
  424. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-table-rows.md +29 -0
  425. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-table-rows.model.json +190 -0
  426. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-task-checkboxes.md +39 -0
  427. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-task-checkboxes.model.json +362 -0
  428. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-union-label.md +24 -0
  429. package/templates/engine/.agents/tests/fixtures/dev-tour/plan-union-label.model.json +224 -0
  430. package/templates/engine/.agents/tests/tools/gen-synthetic-plan.mjs +108 -0
  431. package/templates/git/.gitattributes +23 -0
  432. package/templates/git/.githooks/commit-msg +72 -0
  433. package/templates/git/.githooks/package.json +3 -0
  434. package/templates/git/.githooks/post-commit +62 -0
  435. package/templates/git/.githooks/pre-commit +197 -0
  436. package/templates/git/.githooks/pre-merge-commit +28 -0
  437. package/templates/git/.githooks/pre-push +201 -0
  438. package/templates/git/.github/workflows/ci.yml +32 -0
  439. package/templates/git/.gitignore.engine +11 -0
  440. package/templates/git/azure-pipelines.yml +46 -0
  441. package/templates/host-meta/SKILLS.md +3 -0
  442. package/templates/host-meta/claude/skill-pointer.md +6 -0
  443. package/templates/host-meta/cline/skill-index.md +6 -0
  444. package/templates/host-meta/codebuddy/skill-pointer.md +6 -0
  445. package/templates/host-meta/commandcode/skill-index.md +5 -0
  446. package/templates/host-meta/opencode/skill-pointer.md +6 -0
  447. package/templates/host-meta/qoder/skill-index.md +5 -0
  448. package/templates/host-meta/qwen/skill-index.md +5 -0
  449. package/templates/host-meta/trae/skill-index.md +6 -0
  450. package/templates/hosts/claude/CLAUDE.md +55 -0
  451. package/templates/hosts/claude/agents/implementer.md +7 -0
  452. package/templates/hosts/claude/agents/independent-reviewer.md +8 -0
  453. package/templates/hosts/claude/agents/pr-adjudicator.md +8 -0
  454. package/templates/hosts/claude/agents/pr-finder.md +8 -0
  455. package/templates/hosts/claude/agents/pr-verifier.md +8 -0
  456. package/templates/hosts/claude/agents/ui-verifier.md +8 -0
  457. package/templates/hosts/claude/agents/wiki-compiler.md +8 -0
  458. package/templates/hosts/claude/commands/wf-deploy.md +10 -0
  459. package/templates/hosts/claude/commands/wf-maintain.md +10 -0
  460. package/templates/hosts/claude/commands/wf-new-task.md +10 -0
  461. package/templates/hosts/claude/commands/wf-pipeline-run.md +10 -0
  462. package/templates/hosts/claude/commands/wf-pr-review.md +10 -0
  463. package/templates/hosts/claude/commands/wf-review.md +10 -0
  464. package/templates/hosts/claude/commands/wf-stages.md +10 -0
  465. package/templates/hosts/claude/settings.hardened.json +94 -0
  466. package/templates/hosts/claude/settings.json +55 -0
  467. package/templates/hosts/cline/agents/implementer.yml +15 -0
  468. package/templates/hosts/cline/agents/independent-reviewer.yml +20 -0
  469. package/templates/hosts/cline/agents/pr-adjudicator.yml +18 -0
  470. package/templates/hosts/cline/agents/pr-finder.yml +19 -0
  471. package/templates/hosts/cline/agents/pr-verifier.yml +18 -0
  472. package/templates/hosts/cline/agents/ui-verifier.yml +17 -0
  473. package/templates/hosts/cline/agents/wiki-compiler.yml +20 -0
  474. package/templates/hosts/cline/hooks/PreToolUse.cjs +260 -0
  475. package/templates/hosts/cline/workflows/wf-deploy.md +8 -0
  476. package/templates/hosts/cline/workflows/wf-maintain.md +8 -0
  477. package/templates/hosts/cline/workflows/wf-new-task.md +8 -0
  478. package/templates/hosts/cline/workflows/wf-pipeline-run.md +8 -0
  479. package/templates/hosts/cline/workflows/wf-pr-review.md +8 -0
  480. package/templates/hosts/cline/workflows/wf-review.md +8 -0
  481. package/templates/hosts/cline/workflows/wf-stages.md +8 -0
  482. package/templates/hosts/codebuddy/CODEBUDDY.md +7 -0
  483. package/templates/hosts/codebuddy/agents/implementer.md +9 -0
  484. package/templates/hosts/codebuddy/agents/independent-reviewer.md +10 -0
  485. package/templates/hosts/codebuddy/agents/pr-adjudicator.md +10 -0
  486. package/templates/hosts/codebuddy/agents/pr-finder.md +10 -0
  487. package/templates/hosts/codebuddy/agents/pr-verifier.md +10 -0
  488. package/templates/hosts/codebuddy/agents/ui-verifier.md +11 -0
  489. package/templates/hosts/codebuddy/agents/wiki-compiler.md +10 -0
  490. package/templates/hosts/codebuddy/commands/wf-deploy.md +10 -0
  491. package/templates/hosts/codebuddy/commands/wf-maintain.md +10 -0
  492. package/templates/hosts/codebuddy/commands/wf-new-task.md +10 -0
  493. package/templates/hosts/codebuddy/commands/wf-pipeline-run.md +10 -0
  494. package/templates/hosts/codebuddy/commands/wf-pr-review.md +10 -0
  495. package/templates/hosts/codebuddy/commands/wf-review.md +10 -0
  496. package/templates/hosts/codebuddy/commands/wf-stages.md +10 -0
  497. package/templates/hosts/codebuddy/rules/backend-scope.md +5 -0
  498. package/templates/hosts/codebuddy/rules/frontend-scope.md +5 -0
  499. package/templates/hosts/codebuddy/settings.json +31 -0
  500. package/templates/hosts/codebuddy/skills/tfs-pr/SKILL.md +6 -0
  501. package/templates/hosts/commandcode/agents/implementer.md +10 -0
  502. package/templates/hosts/commandcode/agents/independent-reviewer.md +9 -0
  503. package/templates/hosts/commandcode/agents/pr-adjudicator.md +9 -0
  504. package/templates/hosts/commandcode/agents/pr-finder.md +9 -0
  505. package/templates/hosts/commandcode/agents/pr-verifier.md +9 -0
  506. package/templates/hosts/commandcode/agents/ui-verifier.md +11 -0
  507. package/templates/hosts/commandcode/agents/wiki-compiler.md +10 -0
  508. package/templates/hosts/commandcode/commands/wf-deploy.md +9 -0
  509. package/templates/hosts/commandcode/commands/wf-maintain.md +9 -0
  510. package/templates/hosts/commandcode/commands/wf-new-task.md +9 -0
  511. package/templates/hosts/commandcode/commands/wf-pipeline-run.md +9 -0
  512. package/templates/hosts/commandcode/commands/wf-pr-review.md +9 -0
  513. package/templates/hosts/commandcode/commands/wf-review.md +9 -0
  514. package/templates/hosts/commandcode/commands/wf-stages.md +9 -0
  515. package/templates/hosts/commandcode/settings.json +57 -0
  516. package/templates/hosts/opencode/agents/implementer.md +51 -0
  517. package/templates/hosts/opencode/agents/independent-reviewer.md +18 -0
  518. package/templates/hosts/opencode/agents/pr-adjudicator.md +18 -0
  519. package/templates/hosts/opencode/agents/pr-finder.md +18 -0
  520. package/templates/hosts/opencode/agents/pr-verifier.md +18 -0
  521. package/templates/hosts/opencode/agents/ui-verifier.md +45 -0
  522. package/templates/hosts/opencode/agents/wiki-compiler.md +51 -0
  523. package/templates/hosts/opencode/commands/wf-deploy.md +7 -0
  524. package/templates/hosts/opencode/commands/wf-maintain.md +7 -0
  525. package/templates/hosts/opencode/commands/wf-new-task.md +7 -0
  526. package/templates/hosts/opencode/commands/wf-pipeline-run.md +7 -0
  527. package/templates/hosts/opencode/commands/wf-pr-review.md +7 -0
  528. package/templates/hosts/opencode/commands/wf-review.md +7 -0
  529. package/templates/hosts/opencode/commands/wf-stages.md +7 -0
  530. package/templates/hosts/pi/agents/implementer.md +10 -0
  531. package/templates/hosts/pi/agents/independent-reviewer.md +11 -0
  532. package/templates/hosts/pi/agents/pr-adjudicator.md +11 -0
  533. package/templates/hosts/pi/agents/pr-finder.md +10 -0
  534. package/templates/hosts/pi/agents/pr-verifier.md +10 -0
  535. package/templates/hosts/pi/agents/ui-verifier.md +10 -0
  536. package/templates/hosts/pi/agents/wiki-compiler.md +10 -0
  537. package/templates/hosts/pi/extensions/lib/gates-core.cjs +196 -0
  538. package/templates/hosts/pi/extensions/shipyard-gates.ts +95 -0
  539. package/templates/hosts/pi/settings.json +5 -0
  540. package/templates/hosts/qoder/agents/implementer.md +9 -0
  541. package/templates/hosts/qoder/agents/independent-reviewer.md +10 -0
  542. package/templates/hosts/qoder/agents/pr-adjudicator.md +10 -0
  543. package/templates/hosts/qoder/agents/pr-finder.md +10 -0
  544. package/templates/hosts/qoder/agents/pr-verifier.md +10 -0
  545. package/templates/hosts/qoder/agents/ui-verifier.md +10 -0
  546. package/templates/hosts/qoder/agents/wiki-compiler.md +10 -0
  547. package/templates/hosts/qoder/commands/wf-deploy.md +8 -0
  548. package/templates/hosts/qoder/commands/wf-maintain.md +8 -0
  549. package/templates/hosts/qoder/commands/wf-new-task.md +8 -0
  550. package/templates/hosts/qoder/commands/wf-pipeline-run.md +8 -0
  551. package/templates/hosts/qoder/commands/wf-pr-review.md +8 -0
  552. package/templates/hosts/qoder/commands/wf-review.md +8 -0
  553. package/templates/hosts/qoder/commands/wf-stages.md +8 -0
  554. package/templates/hosts/qoder/settings.json +61 -0
  555. package/templates/hosts/qwen/agents/implementer.md +8 -0
  556. package/templates/hosts/qwen/agents/independent-reviewer.md +8 -0
  557. package/templates/hosts/qwen/agents/pr-adjudicator.md +8 -0
  558. package/templates/hosts/qwen/agents/pr-finder.md +8 -0
  559. package/templates/hosts/qwen/agents/pr-verifier.md +8 -0
  560. package/templates/hosts/qwen/agents/ui-verifier.md +8 -0
  561. package/templates/hosts/qwen/agents/wiki-compiler.md +11 -0
  562. package/templates/hosts/qwen/commands/wf-deploy.md +9 -0
  563. package/templates/hosts/qwen/commands/wf-maintain.md +9 -0
  564. package/templates/hosts/qwen/commands/wf-new-task.md +9 -0
  565. package/templates/hosts/qwen/commands/wf-pipeline-run.md +9 -0
  566. package/templates/hosts/qwen/commands/wf-pr-review.md +9 -0
  567. package/templates/hosts/qwen/commands/wf-review.md +9 -0
  568. package/templates/hosts/qwen/commands/wf-stages.md +9 -0
  569. package/templates/hosts/qwen/settings.json +57 -0
  570. package/templates/hosts/trae/agents/implementer.md +9 -0
  571. package/templates/hosts/trae/agents/independent-reviewer.md +10 -0
  572. package/templates/hosts/trae/agents/pr-adjudicator.md +10 -0
  573. package/templates/hosts/trae/agents/pr-finder.md +10 -0
  574. package/templates/hosts/trae/agents/pr-verifier.md +10 -0
  575. package/templates/hosts/trae/agents/ui-verifier.md +10 -0
  576. package/templates/hosts/trae/agents/wiki-compiler.md +10 -0
  577. package/templates/hosts/trae/commands/wf-deploy.md +8 -0
  578. package/templates/hosts/trae/commands/wf-maintain.md +8 -0
  579. package/templates/hosts/trae/commands/wf-new-task.md +8 -0
  580. package/templates/hosts/trae/commands/wf-pipeline-run.md +8 -0
  581. package/templates/hosts/trae/commands/wf-pr-review.md +8 -0
  582. package/templates/hosts/trae/commands/wf-review.md +8 -0
  583. package/templates/hosts/trae/commands/wf-stages.md +8 -0
  584. package/templates/hosts/trae/hooks.json +17 -0
  585. package/templates/hosts/trae/rules/backend-scope.md +5 -0
  586. package/templates/hosts/trae/rules/frontend-scope.md +5 -0
  587. package/templates/hosts/zcode/agents/implementer.md +8 -0
  588. package/templates/hosts/zcode/agents/independent-reviewer.md +8 -0
  589. package/templates/hosts/zcode/agents/ui-verifier.md +8 -0
  590. package/templates/hosts/zcode/agents/wiki-compiler.md +8 -0
  591. package/templates/hosts/zcode/config.json +31 -0
  592. package/templates/hosts/zcode/workflows/code-review.dwf.ts +428 -0
  593. package/templates/hosts/zcode/workflows/fullchain-flow-test.dwf.ts +898 -0
  594. package/templates/profiles/dotnet/.agents/config/lane-surfaces.txt +33 -0
  595. package/templates/profiles/dotnet/.agents/config/rule-budgets.txt +84 -0
  596. package/templates/profiles/dotnet/.agents/config/test-impact-map.json +590 -0
  597. package/templates/profiles/dotnet/.agents/config/workflow-modules.txt +18 -0
  598. package/templates/profiles/dotnet/.agents/hooks/commit-check.config.json +18 -0
  599. package/templates/profiles/dotnet/.agents/hooks/delete-guard-allowlist.txt +28 -0
  600. package/templates/profiles/dotnet/.agents/notes/runtime-env.md +178 -0
  601. package/templates/profiles/dotnet/AGENTS.md +52 -0
  602. package/templates/profiles/empty/.agents/config/lane-surfaces.txt +12 -0
  603. package/templates/profiles/empty/.agents/config/rule-budgets.txt +3 -0
  604. package/templates/profiles/empty/.agents/config/test-impact-map.json +8 -0
  605. package/templates/profiles/empty/.agents/config/workflow-modules.txt +2 -0
  606. package/templates/profiles/empty/.agents/hooks/commit-check.config.json +5 -0
  607. package/templates/profiles/empty/.agents/hooks/delete-guard-allowlist.txt +2 -0
  608. package/templates/profiles/empty/.agents/notes/runtime-env.md +44 -0
  609. package/templates/profiles/empty/AGENTS.md +52 -0
  610. package/templates/profiles/go/AGENTS.md +52 -0
  611. package/templates/profiles/java/AGENTS.md +52 -0
  612. package/templates/profiles/node/.agents/config/lane-surfaces.txt +12 -0
  613. package/templates/profiles/node/.agents/config/rule-budgets.txt +3 -0
  614. package/templates/profiles/node/.agents/config/test-impact-map.json +8 -0
  615. package/templates/profiles/node/.agents/config/workflow-modules.txt +2 -0
  616. package/templates/profiles/node/.agents/hooks/commit-check.config.json +5 -0
  617. package/templates/profiles/node/.agents/hooks/delete-guard-allowlist.txt +2 -0
  618. package/templates/profiles/node/.agents/notes/runtime-env.md +44 -0
  619. package/templates/profiles/node/AGENTS.md +52 -0
  620. package/templates/profiles/rust/AGENTS.md +52 -0
  621. package/templates/profiles/typescript/AGENTS.md +52 -0
  622. package/templates/scaffold/wiki/INDEX.md +33 -0
  623. package/templates/scaffold/wiki/drafts-archive/README.md +7 -0
  624. package/templates/scaffold/wiki//344/272/247/345/223/201/351/234/200/346/261/202/.gitkeep +0 -0
  625. package/templates/scaffold/wiki//345/274/200/345/217/221/346/226/271/346/241/210/.gitkeep +0 -0
  626. package/templates/scaffold/wiki//346/225/260/346/215/256/347/273/264/346/212/244/README.md +22 -0
  627. package/templates/scaffold/wiki//346/265/213/350/257/225/346/212/245/345/221/212/.gitkeep +0 -0
  628. package/templates/scaffold/wiki//347/224/250/346/210/267/345/212/237/350/203/275/.gitkeep +0 -0
  629. package/templates/scaffold/wiki//347/237/245/350/257/206/346/262/211/346/267/200/346/200/273/350/247/210.html +230 -0
  630. package/templates/scaffold/wiki//351/241/271/347/233/256/350/247/204/350/214/203/.gitkeep +0 -0
  631. package/templates/scaffold/workflow/INDEX.md +29 -0
  632. package/templates/scaffold/workflow/README.md +69 -0
  633. package/templates/scaffold/workflow/archive/README.md +3 -0
  634. package/templates/scaffold/workflow/artifact-sources.md +25 -0
  635. package/templates/scaffold/workflow/delegations.d/.gitkeep +0 -0
  636. package/templates/scaffold/workflow/delegations.md +4 -0
  637. package/templates/scaffold/workflow/effective-policy.md +4 -0
  638. package/templates/scaffold/workflow/evidence/.gitkeep +0 -0
  639. package/templates/scaffold/workflow/gate-cost.md +4 -0
  640. package/templates/scaffold/workflow/gate-metrics.d/.gitkeep +0 -0
  641. package/templates/scaffold/workflow/incidents/_TEMPLATE.md +49 -0
  642. package/templates/scaffold/workflow/intents/_TEMPLATE.md +43 -0
  643. package/templates/scaffold/workflow/metrics.md +4 -0
  644. package/templates/scaffold/workflow/non-engineer-intent.md +51 -0
  645. package/templates/scaffold/workflow/papercuts.d/.gitkeep +0 -0
  646. package/templates/scaffold/workflow/papercuts.md +3 -0
  647. package/templates/scaffold/workflow/plans/_TEMPLATE.md +47 -0
  648. package/templates/scaffold/workflow/regression-checklist.d/.gitkeep +0 -0
  649. package/templates/scaffold/workflow/regression-checklist.md +3 -0
  650. package/templates/scaffold/workflow/research/.gitkeep +0 -0
  651. package/templates/scaffold/workflow/reviews.d/.gitkeep +0 -0
  652. package/templates/scaffold/workflow/specs/_TEMPLATE.md +87 -0
  653. package/templates/scaffold/workflow/verify-evidence/.gitkeep +0 -0
  654. package/templates/scaffold/workflow/verify-evidence.md +4 -0
  655. package/modules/gates/README.md +0 -25
  656. package/modules/gates/dotnet-ca/README.md +0 -24
  657. package/modules/gates/dotnet-ca/check-architecture.sh +0 -150
  658. package/modules/gates/dotnet-ca/local-pre-commit.line +0 -1
  659. package/modules/gates/generated-readonly/README.md +0 -13
  660. package/modules/gates/generated-readonly/check-generated.mjs +0 -61
  661. package/modules/gates/generated-readonly/local-pre-commit.line +0 -1
  662. package/modules/gates/node-layer/README.md +0 -9
  663. package/modules/gates/node-layer/check-node-layer.mjs +0 -29
  664. package/modules/gates/node-layer/local-pre-commit.line +0 -1
  665. package/modules/gates/py-import/README.md +0 -9
  666. package/modules/gates/py-import/check-py-import.mjs +0 -30
  667. package/modules/gates/py-import/local-pre-commit.line +0 -1
  668. package/modules/gates/test-protect/README.md +0 -23
  669. package/modules/gates/test-protect/check-test-protect.mjs +0 -64
  670. package/modules/gates/test-protect/local-pre-commit.line +0 -1
  671. package/modules/hosts/README.md +0 -57
  672. package/modules/hosts/claude/agents/implementer.md +0 -51
  673. package/modules/hosts/claude/agents/independent-reviewer.md +0 -49
  674. package/modules/hosts/claude/agents/ui-verifier.md +0 -48
  675. package/modules/hosts/claude/commands/wf-build.md +0 -69
  676. package/modules/hosts/claude/commands/wf-deploy.md +0 -58
  677. package/modules/hosts/claude/commands/wf-design.md +0 -49
  678. package/modules/hosts/claude/commands/wf-gate-checklist.md +0 -77
  679. package/modules/hosts/claude/commands/wf-maintain.md +0 -76
  680. package/modules/hosts/claude/commands/wf-new-task.md +0 -102
  681. package/modules/hosts/claude/commands/wf-pipeline-run.md +0 -35
  682. package/modules/hosts/claude/commands/wf-plan.md +0 -40
  683. package/modules/hosts/claude/commands/wf-review.md +0 -49
  684. package/modules/hosts/claude/commands/wf-sync-hosts.md +0 -64
  685. package/modules/hosts/claude/commands/wf-test.md +0 -68
  686. package/modules/hosts/codex/agents/implementer.md +0 -51
  687. package/modules/hosts/codex/agents/independent-reviewer.md +0 -49
  688. package/modules/hosts/codex/agents/ui-verifier.md +0 -48
  689. package/modules/hosts/codex/commands/wf-build.md +0 -69
  690. package/modules/hosts/codex/commands/wf-deploy.md +0 -58
  691. package/modules/hosts/codex/commands/wf-design.md +0 -49
  692. package/modules/hosts/codex/commands/wf-gate-checklist.md +0 -77
  693. package/modules/hosts/codex/commands/wf-maintain.md +0 -76
  694. package/modules/hosts/codex/commands/wf-new-task.md +0 -102
  695. package/modules/hosts/codex/commands/wf-pipeline-run.md +0 -35
  696. package/modules/hosts/codex/commands/wf-plan.md +0 -40
  697. package/modules/hosts/codex/commands/wf-review.md +0 -49
  698. package/modules/hosts/codex/commands/wf-sync-hosts.md +0 -64
  699. package/modules/hosts/codex/commands/wf-test.md +0 -68
  700. package/modules/hosts/codex/skills/flow-kit/SKILL.md +0 -14
  701. package/modules/hosts/cursor/agents/implementer.md +0 -51
  702. package/modules/hosts/cursor/agents/independent-reviewer.md +0 -49
  703. package/modules/hosts/cursor/agents/ui-verifier.md +0 -48
  704. package/modules/hosts/cursor/commands/wf-build.md +0 -69
  705. package/modules/hosts/cursor/commands/wf-deploy.md +0 -58
  706. package/modules/hosts/cursor/commands/wf-design.md +0 -49
  707. package/modules/hosts/cursor/commands/wf-gate-checklist.md +0 -77
  708. package/modules/hosts/cursor/commands/wf-maintain.md +0 -76
  709. package/modules/hosts/cursor/commands/wf-new-task.md +0 -102
  710. package/modules/hosts/cursor/commands/wf-pipeline-run.md +0 -35
  711. package/modules/hosts/cursor/commands/wf-plan.md +0 -40
  712. package/modules/hosts/cursor/commands/wf-review.md +0 -49
  713. package/modules/hosts/cursor/commands/wf-sync-hosts.md +0 -64
  714. package/modules/hosts/cursor/commands/wf-test.md +0 -68
  715. package/modules/hosts/omp/agents/implementer.md +0 -52
  716. package/modules/hosts/omp/agents/independent-reviewer.md +0 -50
  717. package/modules/hosts/omp/agents/ui-verifier.md +0 -49
  718. package/modules/hosts/opencode/agents/implementer.md +0 -59
  719. package/modules/hosts/opencode/agents/independent-reviewer.md +0 -53
  720. package/modules/hosts/opencode/agents/ui-verifier.md +0 -52
  721. package/modules/hosts/opencode/commands/wf-build.md +0 -69
  722. package/modules/hosts/opencode/commands/wf-deploy.md +0 -58
  723. package/modules/hosts/opencode/commands/wf-design.md +0 -49
  724. package/modules/hosts/opencode/commands/wf-gate-checklist.md +0 -77
  725. package/modules/hosts/opencode/commands/wf-maintain.md +0 -76
  726. package/modules/hosts/opencode/commands/wf-new-task.md +0 -102
  727. package/modules/hosts/opencode/commands/wf-pipeline-run.md +0 -35
  728. package/modules/hosts/opencode/commands/wf-plan.md +0 -40
  729. package/modules/hosts/opencode/commands/wf-review.md +0 -49
  730. package/modules/hosts/opencode/commands/wf-sync-hosts.md +0 -64
  731. package/modules/hosts/opencode/commands/wf-test.md +0 -68
  732. package/modules/hosts/trae/agents/implementer.md +0 -52
  733. package/modules/hosts/trae/agents/independent-reviewer.md +0 -51
  734. package/modules/hosts/trae/agents/ui-verifier.md +0 -50
  735. package/modules/hosts/trae/commands/wf-build.md +0 -70
  736. package/modules/hosts/trae/commands/wf-deploy.md +0 -59
  737. package/modules/hosts/trae/commands/wf-design.md +0 -50
  738. package/modules/hosts/trae/commands/wf-gate-checklist.md +0 -78
  739. package/modules/hosts/trae/commands/wf-maintain.md +0 -77
  740. package/modules/hosts/trae/commands/wf-new-task.md +0 -103
  741. package/modules/hosts/trae/commands/wf-pipeline-run.md +0 -36
  742. package/modules/hosts/trae/commands/wf-plan.md +0 -41
  743. package/modules/hosts/trae/commands/wf-review.md +0 -50
  744. package/modules/hosts/trae/commands/wf-sync-hosts.md +0 -65
  745. package/modules/hosts/trae/commands/wf-test.md +0 -69
  746. package/modules/hosts/trae/hooks/post-edit-check.cjs +0 -98
  747. package/modules/hosts/trae/hooks/pre-shell-check.cjs +0 -192
  748. package/modules/hosts/trae/hooks/resolve-shell.cjs +0 -30
  749. package/modules/hosts/trae/hooks.json +0 -29
  750. package/modules/hosts/trae/rules/beautify-input-chinese.md +0 -6
  751. package/modules/hosts/trae/rules/git-commit-message.md +0 -10
  752. package/modules/hosts/trae/rules/project-workflow.md +0 -14
  753. package/modules/hosts/zcode/agents/implementer.md +0 -51
  754. package/modules/hosts/zcode/agents/independent-reviewer.md +0 -49
  755. package/modules/hosts/zcode/agents/ui-verifier.md +0 -48
  756. package/src/add-gate.mjs +0 -116
  757. package/src/add-gate.test.mjs +0 -103
  758. package/src/add-host.mjs +0 -68
  759. package/src/cli.mjs +0 -169
  760. package/src/doctor.mjs +0 -629
  761. package/src/executor.mjs +0 -262
  762. package/src/executor.test.mjs +0 -295
  763. package/src/fresh-init.test.mjs +0 -64
  764. package/src/gate-dotnet-ca.test.mjs +0 -124
  765. package/src/gates.test.mjs +0 -143
  766. package/src/init.mjs +0 -382
  767. package/src/init.test.mjs +0 -163
  768. package/src/instance-ref.test.mjs +0 -62
  769. package/src/jscpd-drift.test.mjs +0 -145
  770. package/src/pack.test.mjs +0 -24
  771. package/src/profiles.mjs +0 -183
  772. package/src/render.mjs +0 -132
  773. package/src/rule-budget.test.mjs +0 -103
  774. package/src/run-tests.mjs +0 -56
  775. package/src/stack-profile.test.mjs +0 -95
  776. package/src/sync-hosts.mjs +0 -257
  777. package/src/sync-hosts.test.mjs +0 -291
  778. package/src/sync.mjs +0 -228
  779. package/src/sync.test.mjs +0 -452
  780. package/src/trae-hooks.test.mjs +0 -127
  781. package/src/validate.mjs +0 -77
  782. package/src/validate.test.mjs +0 -95
  783. package/templates/.gitattributes +0 -17
  784. package/templates/AGENTS.md +0 -58
  785. package/templates/_agents/board/index.html +0 -676
  786. package/templates/_agents/commands/build.md +0 -84
  787. package/templates/_agents/commands/deploy.md +0 -66
  788. package/templates/_agents/commands/design.md +0 -63
  789. package/templates/_agents/commands/gate-checklist.md +0 -91
  790. package/templates/_agents/commands/maintain.md +0 -90
  791. package/templates/_agents/commands/new-task.md +0 -110
  792. package/templates/_agents/commands/pipeline-run.md +0 -43
  793. package/templates/_agents/commands/plan.md +0 -48
  794. package/templates/_agents/commands/review.md +0 -62
  795. package/templates/_agents/commands/sync-hosts.md +0 -77
  796. package/templates/_agents/commands/test.md +0 -87
  797. package/templates/_agents/control-surfaces.txt +0 -53
  798. package/templates/_agents/engine-lock.json +0 -342
  799. package/templates/_agents/hooks/check-index-incremental.mjs +0 -48
  800. package/templates/_agents/hooks/check-pairing-incremental.mjs +0 -66
  801. package/templates/_agents/hooks/check-wiki-ledger.mjs +0 -30
  802. package/templates/_agents/hooks/commit-check.cjs +0 -193
  803. package/templates/_agents/hooks/local-pre-commit +0 -6
  804. package/templates/_agents/lane-surfaces.txt +0 -17
  805. package/templates/_agents/level-hints.txt +0 -30
  806. package/templates/_agents/loop/papercut-debt/DESIGN.md +0 -112
  807. package/templates/_agents/mechanism-registry.md +0 -35
  808. package/templates/_agents/metric-claims.txt +0 -81
  809. package/templates/_agents/notes/engine-internals.md +0 -17
  810. package/templates/_agents/notes/runtime-env.md +0 -18
  811. package/templates/_agents/roles/implementer.md +0 -47
  812. package/templates/_agents/roles/independent-reviewer.md +0 -45
  813. package/templates/_agents/roles/ui-verifier.md +0 -44
  814. package/templates/_agents/rule-budgets.txt +0 -20
  815. package/templates/_agents/scripts/agg-delegations.cjs +0 -302
  816. package/templates/_agents/scripts/agg-delegations.test.mjs +0 -282
  817. package/templates/_agents/scripts/agg-gate-stats.mjs +0 -113
  818. package/templates/_agents/scripts/agg-gate-stats.test.mjs +0 -95
  819. package/templates/_agents/scripts/agg-judgments.mjs +0 -156
  820. package/templates/_agents/scripts/agg-judgments.test.mjs +0 -93
  821. package/templates/_agents/scripts/archive-sweep.mjs +0 -235
  822. package/templates/_agents/scripts/archive-sweep.test.mjs +0 -129
  823. package/templates/_agents/scripts/check-attribution.mjs +0 -37
  824. package/templates/_agents/scripts/check-convergence.mjs +0 -124
  825. package/templates/_agents/scripts/check-engine-integrity.mjs +0 -220
  826. package/templates/_agents/scripts/check-engine-integrity.test.mjs +0 -215
  827. package/templates/_agents/scripts/check-funnel.mjs +0 -56
  828. package/templates/_agents/scripts/check-hygiene.mjs +0 -167
  829. package/templates/_agents/scripts/check-hygiene.test.mjs +0 -182
  830. package/templates/_agents/scripts/check-index-incremental.test.mjs +0 -73
  831. package/templates/_agents/scripts/check-lane-surface.mjs +0 -238
  832. package/templates/_agents/scripts/check-lane-surface.test.mjs +0 -302
  833. package/templates/_agents/scripts/check-ledger-invariant.mjs +0 -586
  834. package/templates/_agents/scripts/check-ledger-invariant.test.mjs +0 -639
  835. package/templates/_agents/scripts/check-loop-rev.test.mjs +0 -336
  836. package/templates/_agents/scripts/check-loop-unit.test.mjs +0 -103
  837. package/templates/_agents/scripts/check-loop.mjs +0 -1987
  838. package/templates/_agents/scripts/check-loop.sh +0 -6
  839. package/templates/_agents/scripts/check-loop.test.mjs +0 -3912
  840. package/templates/_agents/scripts/check-metric-claims.mjs +0 -277
  841. package/templates/_agents/scripts/check-prejudgment.mjs +0 -64
  842. package/templates/_agents/scripts/check-registry.mjs +0 -45
  843. package/templates/_agents/scripts/check-scope.mjs +0 -96
  844. package/templates/_agents/scripts/check-scope.test.mjs +0 -99
  845. package/templates/_agents/scripts/check-scripts-syntax.mjs +0 -84
  846. package/templates/_agents/scripts/check-scripts-syntax.test.mjs +0 -72
  847. package/templates/_agents/scripts/check-spec-verif.mjs +0 -47
  848. package/templates/_agents/scripts/check-stage-index.mjs +0 -40
  849. package/templates/_agents/scripts/check-stage-index.test.mjs +0 -77
  850. package/templates/_agents/scripts/closeout-l1.mjs +0 -217
  851. package/templates/_agents/scripts/closeout-l1.test.mjs +0 -105
  852. package/templates/_agents/scripts/commit-check-trigger.test.mjs +0 -205
  853. package/templates/_agents/scripts/compact-ledgers.mjs +0 -97
  854. package/templates/_agents/scripts/compact-ledgers.test.mjs +0 -162
  855. package/templates/_agents/scripts/confirm-doc.mjs +0 -610
  856. package/templates/_agents/scripts/confirm-doc.test.mjs +0 -1119
  857. package/templates/_agents/scripts/doctor.test.mjs +0 -770
  858. package/templates/_agents/scripts/draft-sediment.mjs +0 -178
  859. package/templates/_agents/scripts/draft-sediment.test.mjs +0 -272
  860. package/templates/_agents/scripts/edit-face-check.mjs +0 -109
  861. package/templates/_agents/scripts/edit-face-check.test.mjs +0 -99
  862. package/templates/_agents/scripts/ensure-board.mjs +0 -185
  863. package/templates/_agents/scripts/fill-intent.mjs +0 -91
  864. package/templates/_agents/scripts/fill-intent.test.mjs +0 -113
  865. package/templates/_agents/scripts/fill-plan.mjs +0 -79
  866. package/templates/_agents/scripts/fill-plan.test.mjs +0 -224
  867. package/templates/_agents/scripts/fill-spec.mjs +0 -70
  868. package/templates/_agents/scripts/fill-spec.test.mjs +0 -266
  869. package/templates/_agents/scripts/fixture-scripts.mjs +0 -153
  870. package/templates/_agents/scripts/fixture-scripts.test.mjs +0 -112
  871. package/templates/_agents/scripts/gate-checklist.mjs +0 -209
  872. package/templates/_agents/scripts/gate-checklist.test.mjs +0 -201
  873. package/templates/_agents/scripts/gate-seg.mjs +0 -54
  874. package/templates/_agents/scripts/gate-seg.test.mjs +0 -112
  875. package/templates/_agents/scripts/gen-effective-policy.mjs +0 -107
  876. package/templates/_agents/scripts/gen-effective-policy.test.mjs +0 -100
  877. package/templates/_agents/scripts/gen-verify-evidence.mjs +0 -107
  878. package/templates/_agents/scripts/gen-verify-evidence.test.mjs +0 -84
  879. package/templates/_agents/scripts/gen-wiki-board.mjs +0 -276
  880. package/templates/_agents/scripts/gen-wiki-board.test.mjs +0 -249
  881. package/templates/_agents/scripts/gen-workflow-dashboard.mjs +0 -251
  882. package/templates/_agents/scripts/gen-workflow-dashboard.test.mjs +0 -188
  883. package/templates/_agents/scripts/gen-workflow-index.mjs +0 -201
  884. package/templates/_agents/scripts/gen-workflow-index.test.mjs +0 -152
  885. package/templates/_agents/scripts/gen-workflow-metrics.mjs +0 -466
  886. package/templates/_agents/scripts/gen-workflow-metrics.test.mjs +0 -343
  887. package/templates/_agents/scripts/git-merge-jsonl.mjs +0 -63
  888. package/templates/_agents/scripts/git-merge-jsonl.test.mjs +0 -125
  889. package/templates/_agents/scripts/judgment-ledger.mjs +0 -65
  890. package/templates/_agents/scripts/judgment-ledger.test.mjs +0 -129
  891. package/templates/_agents/scripts/kb-cache-evict.mjs +0 -50
  892. package/templates/_agents/scripts/kb-cache-evict.test.mjs +0 -104
  893. package/templates/_agents/scripts/kb-search.mjs +0 -413
  894. package/templates/_agents/scripts/kb-search.test.mjs +0 -299
  895. package/templates/_agents/scripts/lane-surface-audit.mjs +0 -143
  896. package/templates/_agents/scripts/lane-surface-audit.test.mjs +0 -93
  897. package/templates/_agents/scripts/ledger-doc-chain.test.mjs +0 -166
  898. package/templates/_agents/scripts/ledger-loader.mjs +0 -108
  899. package/templates/_agents/scripts/ledger-loader.test.mjs +0 -131
  900. package/templates/_agents/scripts/ledger-prune.mjs +0 -96
  901. package/templates/_agents/scripts/ledger-prune.test.mjs +0 -120
  902. package/templates/_agents/scripts/ledger-shards.mjs +0 -344
  903. package/templates/_agents/scripts/ledger-shards.test.mjs +0 -356
  904. package/templates/_agents/scripts/ledger-ts-monotonic.test.mjs +0 -135
  905. package/templates/_agents/scripts/level-criteria.mjs +0 -231
  906. package/templates/_agents/scripts/level-criteria.test.mjs +0 -281
  907. package/templates/_agents/scripts/mechanism-retire-watch.mjs +0 -183
  908. package/templates/_agents/scripts/mechanism-retire-watch.test.mjs +0 -114
  909. package/templates/_agents/scripts/papercut-debt-controller.mjs +0 -141
  910. package/templates/_agents/scripts/papercut-debt-controller.test.mjs +0 -127
  911. package/templates/_agents/scripts/papercut-debt-sensor.mjs +0 -170
  912. package/templates/_agents/scripts/papercut-debt-sensor.test.mjs +0 -146
  913. package/templates/_agents/scripts/pipeline-run-docs.mjs +0 -76
  914. package/templates/_agents/scripts/pipeline-run-run.mjs +0 -63
  915. package/templates/_agents/scripts/pipeline-run.mjs +0 -867
  916. package/templates/_agents/scripts/pipeline-run.test.mjs +0 -517
  917. package/templates/_agents/scripts/policy.mjs +0 -281
  918. package/templates/_agents/scripts/pre-push.test.mjs +0 -105
  919. package/templates/_agents/scripts/resolve-merge-conflicts.mjs +0 -110
  920. package/templates/_agents/scripts/resolve-merge-conflicts.test.mjs +0 -87
  921. package/templates/_agents/scripts/rewrite-file.mjs +0 -133
  922. package/templates/_agents/scripts/rewrite-file.test.mjs +0 -148
  923. package/templates/_agents/scripts/rule-budget.mjs +0 -96
  924. package/templates/_agents/scripts/rule-budget.test.mjs +0 -118
  925. package/templates/_agents/scripts/run-tests.mjs +0 -99
  926. package/templates/_agents/scripts/run-tests.test.mjs +0 -105
  927. package/templates/_agents/scripts/solidify-task.mjs +0 -109
  928. package/templates/_agents/scripts/solidify-task.test.mjs +0 -129
  929. package/templates/_agents/scripts/stage-gates.mjs +0 -343
  930. package/templates/_agents/scripts/stage-gates.test.mjs +0 -105
  931. package/templates/_agents/scripts/trust-mode.mjs +0 -67
  932. package/templates/_agents/scripts/trust-mode.test.mjs +0 -110
  933. package/templates/_agents/scripts/verify-wiki-consistency.mjs +0 -253
  934. package/templates/_agents/scripts/verify-wiki-consistency.test.mjs +0 -123
  935. package/templates/_agents/scripts/verify.mjs +0 -345
  936. package/templates/_agents/scripts/verify.test.mjs +0 -373
  937. package/templates/_agents/scripts/wf-journal.mjs +0 -231
  938. package/templates/_agents/scripts/wf-journal.test.mjs +0 -216
  939. package/templates/_agents/scripts/wiki-search.mjs +0 -19
  940. package/templates/_agents/scripts/wiki-search.test.mjs +0 -57
  941. package/templates/_agents/scripts/workflow-board-server.mjs +0 -393
  942. package/templates/_agents/scripts/workflow-board-server.test.mjs +0 -201
  943. package/templates/_agents/scripts/workflow-enums.mjs +0 -70
  944. package/templates/_agents/scripts/workflow-enums.test.mjs +0 -118
  945. package/templates/_agents/scripts/workflows-check.mjs +0 -260
  946. package/templates/_agents/scripts/workflows-check.test.mjs +0 -278
  947. package/templates/_agents/scripts-test-exempt.txt +0 -16
  948. package/templates/_agents/skills/papercut-fix/SKILL.md +0 -60
  949. package/templates/_agents/skills/papercut-fix/references/response-template.md +0 -81
  950. package/templates/_agents/skills/review-method/SKILL.md +0 -58
  951. package/templates/_agents/skills/verify-ui/SKILL.md +0 -61
  952. package/templates/_agents/skills/wiki/SKILL.md +0 -106
  953. package/templates/_agents/workflow-enums.txt +0 -26
  954. package/templates/_agents/workflow-modules.txt +0 -11
  955. package/templates/_agents/workflows/_TEMPLATE.md +0 -75
  956. package/templates/_agents/workflows/pipeline-closing.md +0 -28
  957. package/templates/_agents/workflows//347/244/272/344/276/213-/345/271/266/350/241/214/345/256/236/347/216/260/350/257/204/345/256/241.md +0 -16
  958. package/templates/_githooks/commit-msg +0 -17
  959. package/templates/_githooks/post-commit +0 -10
  960. package/templates/_githooks/pre-commit +0 -126
  961. package/templates/_githooks/pre-merge-commit +0 -29
  962. package/templates/_githooks/pre-push +0 -136
  963. package/templates/_github/workflows/kit-ci.yml +0 -49
  964. package/templates/wiki/INDEX.md +0 -73
  965. package/templates/wiki/drafts-archive/README.md +0 -3
  966. package/templates/wiki//344/272/247/345/223/201/351/234/200/346/261/202/README.md +0 -3
  967. package/templates/wiki//345/274/200/345/217/221/346/226/271/346/241/210/README.md +0 -3
  968. package/templates/wiki//346/225/260/346/215/256/347/273/264/346/212/244/README.md +0 -3
  969. package/templates/wiki//346/265/213/350/257/225/346/212/245/345/221/212/README.md +0 -3
  970. package/templates/wiki//347/224/250/346/210/267/345/212/237/350/203/275/README.md +0 -3
  971. package/templates/wiki//347/237/245/350/257/206/346/262/211/346/267/200/346/200/273/350/247/210.html +0 -77
  972. package/templates/wiki//351/241/271/347/233/256/350/247/204/350/214/203/README.md +0 -3
  973. package/templates/wiki//351/241/271/347/233/256/350/256/241/345/210/222/README.md +0 -3
  974. package/templates/workflow/README.md +0 -91
  975. package/templates/workflow/delegations.md +0 -29
  976. package/templates/workflow/incidents/_TEMPLATE.md +0 -51
  977. package/templates/workflow/intents/_TEMPLATE.md +0 -51
  978. package/templates/workflow/papercuts.md +0 -9
  979. package/templates/workflow/plans/_TEMPLATE.md +0 -47
  980. package/templates/workflow/regression-checklist.md +0 -23
  981. package/templates/workflow/specs/_TEMPLATE.md +0 -80
  982. /package/templates/{_agents → engine/.agents}/board/marked.min.js +0 -0
  983. /package/templates/{_agents/workflows → engine/.agents/pipelines}/steps//347/244/272/344/276/213-/351/203/250/347/275/262/351/252/214/350/257/201.md" +0 -0
  984. /package/templates/{_agents → engine/.agents}/scripts/git-core.mjs +0 -0
@@ -1,1987 +0,0 @@
1
- #!/usr/bin/env node
2
- // check-loop: AI-Native 闭环骨架断档扫描(agentic-flow-kit 通用版;2026-09-26 check-loop-node 自 POSIX sh 全量迁移 node)
3
- // 扫描 workflow/ 目录,输出 intent/spec/plan 配对、模板字段占位符、incidents 复盘三件套、新 intent 回路等断档。
4
- // 迁移背景:sh 版为规避 MSYS fork 开销引入 awk 预扫临时文件 + fd 3/4 与 glob 序逐行对齐的隐式契约
5
- // (重排循环/加 continue 即静默错位)、四处临时文件无 trap 清理——node 为 kit 硬依赖,双语言实现面纯负担。
6
- // 判定语义/消息文案/exit 语义与 sh 版逐条对齐(check-loop.test.mjs 37+ 场景为对齐安全网);
7
- // 输出 banner 保留「check-loop.sh」字样为稳定输出契约(doctor 按 WARN 行计数、pre-push 按 exit 码判定)。
8
- // 旧入口 check-loop.sh 为 4 行兼容 shim(exec node 本文件)——.githooks/pre-push 与文档引用零改动继续有效。
9
- //
10
- // 严重性分级(沿用):
11
- // - hard-block(阻断 push / CI):配对断裂 + 回路断档(影响三件套可追溯性与闭环电路)
12
- // - warning(打印提示,exit 0):其余卫生项(状态未确认 / 模板占位残留 / 引用漂移 / Adapter 一致性等)
13
- // 违例输出到 stderr 并 exit 1;只剩警告时 exit 0。
14
- //
15
- // 检查项清单(编号/标题/severity 逐条沿 sh 版头部——gate-checklist 配对登记表按 id 消费,不得增删改号):
16
- // 分道 lane 表(2026-10-13 B6b-1/B6b-2,源仓 SECTIONS 同款语义;机读单源 = LANE_OF 表,判据零变化只归属运行面):
17
- // hard(默认关单/pre-push 面): 1 配对(清单 5 状态/L3 复核在同遍循环实现,随 1 同道)、3 复盘三件套+回路、
18
- // 3x 防复发验证证据门、8 验收对账、14 确认留痕、15 指纹链、17 发版收口、
19
- // 23 判据级收敛对账(hard 档随 convergenceHardSince)、25 路由预判一致性(内容纯 WARN 不阻断)
20
- // hygiene(--hygiene / --all 的 WARN 面): 2 模板占位、4 引用、6 角色契约与 Adapter(段 id '5')、
21
- // 7 阶段索引(段 id '6')、9 kebab、10 迁移、11 生成物漂移、12 模块词表、13 体积预算、16 指标签名、
22
- // 18 委派、19 逐阶段、20 引擎脚本测试覆盖、21 spec 验证落地 / 22 机制台账 / 24 归因 / 26 漏斗协议前
23
- // (21–26 六段检查 2026-10-13 B6b-2 落地,见下方清单与 LANE_OF)
24
- // 1. 入口文档/spec/plan 同名配对(plan 配对全级别强制(2026-10-13 L0 退役,自源仓收敛系列 1 回灌——
25
- // 原 L0 协作道豁免随级别退役删除);L2/L3 必须有 spec;
26
- // L1 plan 可即入口(级别恰为 L1 的 plan 无同名 intent/incident 不拦;级别缺失/L2/L3 落单照拦,
27
- // 2026-10-13 B6b-2 自源仓 s01 回灌);L1 勾触达红线 → 「红线判低」hard——协作道不受理 STOP 级改动,
28
- // 就高不就低,2026-09-30 hybrid-governance-risk-lanes) [hard-block]
29
- // 2. 模板字段占位符残留(YYYY-MM-DD / <主题> 等未替换;<主题> 与 .md 同行 = 命名约定描述,豁免) [warning]
30
- // 3. incidents 复盘三件套完整性 + 状态严格枚举 + 新 intent 回路(回路断档=hard,其他=warning)
31
- // 4. 引用有效性(文档/指令中引用的 .agents/ 路径必须存在;支持 fill-{a,b,c}.mjs 花括号展开与 fill-*.mjs 通配;
32
- // workflow 文档仅扫活跃态——终态件的引用是历史叙述,不扫,2026-09-27 audit-gate-hardening) [warning]
33
- // 5. intent/spec/plan 状态字段 + L3 独立复核 [warning]
34
- // 6. 子智能体角色契约 + OpenCode/Trae/ZCode Adapter 一致性(含旧委派残留/钉死模型) [warning]
35
- // 7. 阶段索引同步(AGENTS.md 与 new-task.md 须双向索引全部阶段指令) [warning]
36
- // 8. intent 验收标准对账(新建:done 未勾验/缺节=hard,勾选缺证据=warning;存量聚合 warning,含「存量对账豁免」声明者出账)
37
- // + 场景覆盖子判据(2026-10-10 scenario-coverage,灰度 warning):同名 spec 有「验收场景」节时,
38
- // done intent 验收标准须逐场景 ID 引用(场景:S1…),缺引用=warning;spec 无该节则不适用(零变化)
39
- // + THEN 断言子判据(2026-10-11 then-assertion,灰度 warning):声明场景缺「- THEN」行=空壳场景,
40
- // 聚合一条「场景无断言」warning(THEN 是机器对账锚;节不存在=零变化)
41
- // + 引用断链子判据(2026-10-11 dangling-ref,灰度 warning):验收标准引用 spec 未声明的场景 ID
42
- // (含 spec 无场景节)=「场景引用断链」warning——场景未覆盖的反向对账,共用同一次解析
43
- // **生效日锚=git 首次加入日期(2026-09-28 改;此前取文件名前 10 字符——命名规范强制的字段、
44
- // 写早零成本,一条 hard 门可被平凡绕过;incident 2026-09-28-check8-git-anchor 实证)**:
45
- // 非 git / 查不到加入记录 → 不可判定 → 走存量口径(不误报 hard)
46
- // 证据可写在 [x] 行的续行(仓库通写法「(证据:…)」另起一行;全/半角冒号皆认)
47
- // 9. 文件名英文 kebab-case(非 ASCII 文件名=warning,2026-09-11 规则)
48
- // 10. 级别 vs 迁移文件一致性(L1/L2 入口文档加入提交触及迁移 SQL/Migrations=疑似判低,warning)
49
- // 11. 生成物漂移:workflow/INDEX.md(2026-09-21 检索层) + workflow/DASHBOARD.md(2026-10-08 扩覆盖面)=warning;
50
- // wiki 侧(wiki/INDEX.md + 看板 DATA)由 doctor §6b 经 gen-wiki-board --check 校验,不在此重复
51
- // (2026-10-10:wiki 生成区此前零机器校验,现与 workflow 侧对称为 doctor 单路);
52
- // 12. frontmatter「模块:」合法性(枚举非法 / 2026-09-22 起新建缺字段=warning;词表单源 .agents/workflow-modules.txt)
53
- // 13. 常驻面体积预算(超限=warning;判定单源 rule-budget.mjs——node 直跑,恒可跑)
54
- // 14. 新 done 的 spec/plan 须在 git 历史里出现过 `状态: approved`(确认环节留痕,2026-09-22;恒 advisory 永不升级 hard)
55
- // 15. 确认指纹对账(2026-09-27 起:approved/done 须 confirm-doc.mjs 确认指纹+台账配对,缺=hard-block;
56
- // 两形态——TTY 亲手 / --delegated 对话委托代录,台账 source 如实区分,配对判据与 source 无关)
57
- // **受管准入 = 两条件取或(2026-09-28 改锚;此前仅「自报日期 ≥ 生效日」单条件——
58
- // 新档只要把日期写早即整段跳过判定,incident 2026-09-28-confirm-gate-effective-date-anchor 实证)**:
59
- // ① 该 doc 在台账中有合法跳转行(stage∈approved/done/fixed/closed/superseded/cancelled,append-only
60
- // 取末次)——「确认确实发生过」的机器事实,作者**不可顺手填**(经 confirm-doc 走确认门才产生);
61
- // **诚实边界**:台账是本地可写文件、本检查不验签,刻意手改台账仍可伪造——与「伪造 git 时间戳」
62
- // 同属本地信任边界内不可机器防,事后对质靠 git 历史与台账(2026-09-28-claim-exceeds-fix 口径统一);
63
- // ② 自报日期(日期/发现/文件名兜底)≥ 生效日——覆盖「新档完全没跑 confirm-doc」的漏网面
64
- // (此类文档无台账行,仅靠 ① 会误判为存量豁免)。
65
- // 两条件皆不满足 = 存量豁免(生效日前既有、从未走过确认门,不追溯)。
66
- // 改锚收益:把「确认过却把日期写早以逃掉对账」这条攻破路径堵死(条件 ① 独立于自报日期成立)。
67
- // **注意条件②的日期阈值仍分档、且不等价**:docs 2026-09-27 / incidents 2026-09-28——本仓现役
68
- // incident 的「发现」均 ≤2026-09-27,故该档差异当前不显;新 incident 若把「发现」写成 09-27 且
69
- // 无台账行,会因 incidents 阈值(09-28)被豁免,而同日期文档在 docs 档则受管。
70
- // (复核 P2-1 更正:此前本注释误称「incidents 常量退役 / 两档等价」,与代码 :eff 实际保留分档不符;
71
- // 台账锚两档共用为真,条件②阈值分档亦为真,二者不是一回事——README 遣词为准确口径)
72
- // + incidents 覆盖(2026-09-27 gate-coverage:fixed/closed 须配对;open=起草态不加门;
73
- // 不支持 open→closed 单跳——confirm-doc 状态机强制经 fixed)
74
- // + 放弃态覆盖(2026-09-27 closing-coverage:superseded/cancelled 入配对集,confirm-doc --to 唯一通道)
75
- // + 四终态内容绑定(2026-09-27 audit-gate-hardening;生效锚=台账行 ts≥2026-09-28——同日 p2-batch
76
- // 自文档自报日期改锚:旧日期文档晚关单也绑定,3 份失配存量 ts 均 09-27 天然豁免):
77
- // 按 prev 复原跳转前文本重算 sha256 与台账全量比对,不符=hard「确认内容漂移」;状态行保分隔符换值
78
- // (非规范格式不误伤);台账行缺 prev 降级 warning;关单编辑顺序新约定:勾验/回填先于关单确认,
79
- // confirm-doc 是最后一次写入)
80
- // + scope 子项(2026-10-09 审查 A1 干净版):受管行(ts≥policy.scopeSince,**时刻**锚,缺键 v1-v6 整体跳过
81
- // →存量 406 行零新增告警)须带机器派生的改动面 scope{files,sha256}——写入侧 confirm-doc.machineScope
82
- // 自动派生(被确认文档 + `git status --porcelain` 未提交改动集),**AI 无输入面**,分辨力从
83
- // 「一句可复用的用户原话」换成「机器实测的这 N 个文件」。判据:缺 scope→warning(灰度第一档);
84
- // scope.files 重算 sha256 不符→hard(「改了 files 没改摘要」= 同一信任边界内手改痕迹,兜住整文件
85
- // 重写重建链后的二次篡改)。**边界**:scope 证「放行时盘面上哪些文件在动」,不证「这些改动语义正确」
86
- // ——后者由 fingerprint(文档内容绑定)+ commit diff(事后对质)承担,不越界宣称
87
- // + 并录批次审计子检查(2026-09-28 batch-ledger-audit 改判据;**读调用事实,不猜时间戳模式**):
88
- // 判据 = 台账行按 batch 分组、组内 of>1(delegated 行) → warning「确认并录」;batch/seq/of 由
89
- // confirm-doc 写入时记录(那才是"本次调用落几份"确定已知的时刻)。旧判据「同 quote + 相邻 ts<2s」
90
- // 整段退役——已实证四类失效:假阳性(合规逐件复用同句必然误报)/假阴性(换 quote 即零告警,
91
- // 等于引导伪装)/噪声不可消退(不按日期门豁免,退役前本仓 22 条 advisory 中 14 条为该告警)/
92
- // quote 字段职责冲突(对质凭据 vs 并录指纹,现归还单一职责)。无 batch 的历史行静默跳过
93
- // (无判定依据的行不产出不可消除噪声——沿 audit-gate-hardening P3 教训)
94
- // 17. 发版提交树上仍未收口的 intent/spec/plan [hard-block]
95
- // (2026-10-16 快径:当前树 package.json 无 version 字段 → 整段跳过——无 version 则版本变化提交
96
- // 永不存在恒不触发,省全历史 git 扫描;源仓「registry 登记恒不触发」同款口径)
97
- // 18. 委派台账对账 [warning](policy v4 加 delegationSince 生效日豁免:日期早于锚的 L2/L3 存量豁免——
98
- // delegations.md 记法自始不含文件名、无豁免时 113 条不可消退;缺键 v1-v3 维持原全量对账)
99
- // 19. 逐阶段审计(起草先于入口确认 / 台账审批顺序倒置) [warning]
100
- // 20. 引擎脚本测试覆盖(包源环境:templates/_agents/scripts/ 下每个非 *.test.mjs 引擎脚本须有同名兄弟
101
- // .test.mjs,或在 .agents/scripts-test-exempt.txt 登记豁免;2026-10-01 gate-script-test-coverage) [warning]
102
- // 判据 A=在途扫描(同名 spec/plan 为 draft 且日期≥stageGateSince 时判入口确认;plan 另判 L2/L3 的 spec);
103
- // 判据 B=台账 approved 行按主题校验 intents≤specs≤plans 顺序(组内最早 ts 日期≥stageGateSince 才判);
104
- // stageGateSince 缺键(v1) → 本检查整体跳过;口径与 stage-gates.mjs / fill-* / confirm-doc 前置门互引
105
- // 16. 量化断言指标签名对账 [warning](2026-09-28 起;登记表单源 .agents/metric-claims.txt):
106
- // 判据 = 活跃态文档(draft/approved/open)中的 `{{指标名}}` 签名须替换为实时值,留签名=未回填=warning。
107
- // **只查显式签名、不全文扫数字**(据实说明):本仓活跃文档「N 行/N 条/N 份」类表述数十处,绝大多数是
108
- // 历史叙述(描述某次提交当时的规模,天然不随当前事实变化)——全文扫描对这些正确表述产生大量假阳性,
109
- // 而本脚本已立红线「无判定依据的行不产出不可消除噪声」(P3:噪声淹没真漏点)。故本检查**假阳性恒 0**,
110
- // 代价是覆盖面依赖作者登记。签名收窄为小写点分形态——装户模板占位符走全大写 SCREAMING_CASE
111
- // (由 init 渲染替换,如构建/端口/项目名三类,不属本检查面)。未登记签名 / 取数器缺失 → fail-loud 出账
112
- // (静默会让「登记了却没查」不可见);登记表不存在 → 静默跳过(未启用该检查的装户不应被噪声打扰)。
113
- // 21. spec 验证落地核查(L2/L3 done spec 且 git 建档日 ≥ specVerifSince,「测试用例/验证计划/验证方式」
114
- // 节无测试文件/验证命令引用 = warning;存量豁免;锚键缺 → 整段跳过) [warning]
115
- // 22. 机制使用量台账(.agents/mechanism-registry.md 在场才启用;数据行行列数≠7/状态非法/待退役缺
116
- // 处置期限/表无数据行 = warning;纯 WARN 永不 hard) [warning]
117
- // 23. 判据级收敛对账(L2/L3 done spec 锚后「验收判据」表逐判据×证据对账;advisory 档 convergenceSince
118
- // 起证据无效 = warning,hard 档 convergenceHardSince 起路径不存在/命令不在全量门/无对应全绿行 =
119
- // hard-block;人工+空证据合法;无判据表两档都 = warning;存量豁免) [hard-block]
120
- // 24. incident 归因字段核查(发现日 ≥ attributionSince 的新建件「来源/影响环境」必填且值在
121
- // incident.source.all / incident.env.all 枚举 = warning;legacy 回填件与存量豁免) [warning]
122
- // 25. 路由预判一致性(frontmatter「预判: kind= level=」在场才检;类型不符 intents≡require/incidents≡fix、
123
- // 级别与「级别」字段不符、词表/枚举非法 = warning,不阻断;缺字段零告警;内容纯 WARN,lane=hard
124
- // 随源仓 SECTIONS) [advisory]
125
- // 26. 闭环漏斗「协议前」占比动作阈值(workflow/metrics.md 漏斗表日历相邻两月协议前占比均 >30% =
126
- // warning,要求一轮归因;收口=0 的月不判;单月波动不触发) [warning]
127
- // 3x(编号沿源仓 3x 写法,非独立清单号——gate-checklist 按 `N.` 解析,本条不入其配对面). incident 防复发
128
- // 验证证据门(fixed/closed 且 git 建档日 ≥ incidentRegrSince,正文无自动化用例/回归清单引用 =
129
- // hard-block;存量豁免;锚键缺 → 整段跳过) [hard-block]
130
- //
131
- // 注:清单条目 5(状态字段+L3 复核)与 1(配对)在同一遍 intents/specs/plans 循环里实现(沿 sh 版代码结构);
132
- // 条目 6 的旧委派残留/钉死模型子项在「角色契约与 Adapter」代码段实现。
133
- //
134
- // 运行模式:CHECK_LOOP_ROOT 注入 fixture 根(全扫不过滤,非 git 时检查 10/14 跳过);
135
- // 缺省 = git 仓库根(不在 git 仓库内 stderr 提示后 exit 0 跳过);仓库模式只扫已提交(HEAD)内容
136
- // (并行会话未跟踪半成品不拦别人的 push;ls-tree 失败退化为全扫,门禁不失效)。
137
- // --rev <sha>:把该提交剥到 commit 后挂到临时 detached worktree,ROOT 改到那里再扫。
138
- // 原工作区的未提交改动不进入这次扫描。与 CHECK_LOOP_ROOT 同时出现则 exit 1。全 0 sha exit 1。
139
- // --all | --hygiene:分道运行面(2026-10-13 B6b-1,机读单源 LANE_OF)——缺省只跑硬门,口径见头部「用法」。
140
- // 文档协议:机器字段一律由文件头 YAML frontmatter(受限子集:每行 `键: 值`)承载,本脚本只扫 frontmatter 取字段;
141
- // 叙述性字段(独立复核/复盘三件套/验收勾验)按正文行锚定。枚举单源 .agents/workflow-enums.txt
142
- // (缺文件/缺键 fail-loud exit 1;经 workflow-enums.mjs 读取,CRLF 天然容忍)。
143
- // 已确认状态: approved/done=已批或闭环; superseded/cancelled=放弃留档(仍算确认,不挡 push); incident: fixed/closed
144
- // 用法:node .agents/scripts/check-loop.mjs [--rev <sha>] [--all | --hygiene] [--hardening] [--gate-stats] (或经 check-loop.sh shim)
145
- // 分道(2026-10-13 B6b-1,源仓 check-loop SECTIONS 同款口径):默认只跑硬门(配对/判低/指纹/证据/
146
- // 发版未收口)——关单/pre-push 门;--hygiene 只跑卫生段(索引/宿主/词表/指标签名/委派/体积预算等
147
- // WARN 面,不进关单——要看时另跑);--all 两段都跑(= 分道前的裸跑全量)。--all 与 --hygiene 同给
148
- // 报用法错。每段判据零变化,lane 只决定段归属哪个运行面;机读单源 = 本文件 LANE_OF 表。
149
- // --hardening:追加「加固门」(experiment 泳道 exploring 任务入 main 的转正门槛,hard-block;
150
- // .githooks/pre-push 对 remote=refs/heads/main 的推送传入;不占 1-20 编号,gate-checklist 登记表
151
- // 按号配对面不变,门体说明见加固门段注释)
152
- // 测试:node templates/_agents/scripts/check-loop.test.mjs(fixture 注入 CHECK_LOOP_ROOT)
153
- // import 契约(2026-10-08 checkloop-importable):import { runCheckLoop, delegationResultRows, versionGreater, fmStatus, bindingSha256 }
154
- // ——零副作用;runCheckLoop({root?, rev?, mode?, hardening?}) 返回 { exitCode, blockers, warnings }(输出打印照旧,静默断言自行重定向 stderr)
155
- import fs from 'node:fs';
156
- import os from 'node:os';
157
- import path from 'node:path';
158
- import { spawnSync } from 'node:child_process';
159
- import { createHash } from 'node:crypto';
160
- import { loadEnums } from './workflow-enums.mjs';
161
- import { runCheck16 } from './check-metric-claims.mjs';
162
- import { auditEnabled, loadKitPolicy, hasFreshVerifyLine, ledgerChainHash, ledgerDocChainActive, scopeMatches } from './policy.mjs';
163
- import { laneOfEntry } from './stage-gates.mjs';
164
- import { readLedgerRows, readLedgerEntries, LEDGER_REL } from './ledger-loader.mjs';
165
- import { prunedHashes as prunedHashesOf } from './ledger-prune.mjs';
166
- // 委派台账分片感知读(2026-10-13 ledger-shard-ledgers 回灌):主台账 ∪ delegations.d/*.md 文本单源。
167
- import { readDelegationsText } from './ledger-shards.mjs';
168
- // MARK_RE:incident 留痕形态的单源(第七轮复核 N3——此前 check-loop 内联复制一份同口径字面量,
169
- // 两处靠注释与人工同步;改为复用 stage-gates.mjs 的导出,从结构上消除漂移可能)
170
- import { MARK_RE, approvedTraceHit } from './stage-gates.mjs';
171
- // 卫生类检查已拆出(2026-10-08 selfmeasure-and-modularize):检查 2/9/11/12/13 迁入 check-hygiene.mjs,
172
- // 本文件只组装 ctx 并消费返回的文案数组(先例 = check-metric-claims.mjs 承载检查 16)。
173
- // 调用点位置即输出顺序位:须留在检查 10 与 12 之间以保持 warnings 行序(稳定输出契约),见该模块内注释。
174
- import { runCheckHygiene } from './check-hygiene.mjs';
175
- // 检查 7 拆模块(2026-10-09 engine-quality-round2 A1):阶段索引同步迁 check-stage-index.mjs
176
- import { runCheckStageIndex } from './check-stage-index.mjs';
177
- // 六段检查模块(2026-10-13 B6b-2,自 Shipyard.Material check-loop-sections s21–s26 回灌;出处沿革
178
- // 留痕在包源仓 git 历史与 CHANGELOG)。模块形态 = 各文件 export run(ctx):判定语义单源在段内,
179
- // ctx 只传本文件既有共享面(helper 零复刻);段体调 wall 位置即输出顺序位(稳定输出契约)。
180
- import { run as runSpecVerif } from './check-spec-verif.mjs';
181
- import { run as runRegistry } from './check-registry.mjs';
182
- import { run as runConvergence } from './check-convergence.mjs';
183
- import { run as runAttribution } from './check-attribution.mjs';
184
- import { run as runPrejudgment } from './check-prejudgment.mjs';
185
- import { run as runFunnel } from './check-funnel.mjs';
186
- import { gateSeg, finishSegs, makeCollector } from './gate-seg.mjs';
187
- // 判定流水落账(2026-10-11 judgment-ledger):每次真实运行追加一行 per-rule 计数(观测面,fail-open)
188
- import { recordRun } from './judgment-ledger.mjs';
189
-
190
- // CHECK_LOOP_GIT:测试注入钩子(指向不存在/不可执行路径可稳定触发 spawn 异常);未设置时与原行为逐字节一致(2026-10-05-gitout-fail-open)
191
- const GIT = process.env.CHECK_LOOP_GIT || (process.platform === 'win32' ? 'git.exe' : 'git');
192
-
193
- // usage:用法错误统一出口(2026-10-13 分道随源仓 usage() 口径逐字对齐;行 1 追加 kit 自有旗标)。
194
- // 未知参数 / --rev 缺值 / --all 与 --hygiene 同给 → 此处 exit 1(CLI 专属路径;runCheckLoop import 面
195
- // 不经此,mode 由 opts.mode 直给)。
196
- function usage() {
197
- console.error('check-loop: 用法 node check-loop.mjs [--rev <sha>] [--all | --hygiene] [--hardening] [--gate-stats]');
198
- console.error(' 默认只跑硬门(配对/判低/指纹/证据/发版未收口)。--hygiene 只跑卫生段。--all 两段都跑。');
199
- process.exit(1);
200
- }
201
- function takeOpts() {
202
- const args = process.argv.slice(2);
203
- const opts = { rev: null, mode: 'hard', hardening: false, gateStats: false };
204
- for (let i = 0; i < args.length; i++) {
205
- if (args[i] === '--rev') {
206
- opts.rev = args[++i] ?? '';
207
- if (!opts.rev) usage();
208
- } else if (args[i] === '--all') {
209
- if (opts.mode === 'hygiene') usage(); // 互斥组合报用法错(源仓 takeOpts 同款)
210
- opts.mode = 'all';
211
- } else if (args[i] === '--hygiene') {
212
- if (opts.mode === 'all') usage();
213
- opts.mode = 'hygiene';
214
- } else if (args[i] === '--hardening') {
215
- opts.hardening = true; // 加固门(2026-09-30 hybrid-governance-explore-hardening):pre-push 对 main 目标传入
216
- } else if (args[i] === '--gate-stats') {
217
- opts.gateStats = true; // 门禁 ROI 落盘(2026-10-08 gate-roi-metrics):默认路径输出逐字节不变
218
- } else usage();
219
- }
220
- return opts;
221
- }
222
-
223
- // ---- 分道 lane 表(2026-10-13 B6b-1,源仓 check-loop.mjs SECTIONS 同款语义;机读单源)----
224
- // id = 段插桩 id(markGate / check-hygiene / check-stage-index / runCheck16 的 gateSeg 同名),
225
- // 值 = 运行面。守卫只决定段跑不跑,段体判据零变化。清单 5(状态/L3 复核)在检查 1 循环内实现、
226
- // 无独立段 id,随 '1' 同道(hard)。§21–26 与 '3x' 已随 B6b-2 落地登记(2026-10-13)。
227
- const LANE_OF = {
228
- 1: 'hard', // 清单 1+5:配对 + 状态确认 + L3 复核 + 红线判低
229
- 2: 'hygiene', 9: 'hygiene', 11: 'hygiene', 12: 'hygiene', 13: 'hygiene', // check-hygiene.mjs 五段
230
- 3: 'hard', // 复盘三件套 + 新 intent 回路
231
- 4: 'hygiene', // 引用有效性
232
- 5: 'hygiene', // 角色契约与宿主 Adapter(清单 6)
233
- 6: 'hygiene', // 阶段索引同步(清单 7;check-stage-index.mjs)
234
- 8: 'hard', // 验收标准对账
235
- 10: 'hygiene', // 级别 vs 迁移文件
236
- 14: 'hard', // 确认留痕(approved 快照)
237
- 15: 'hard', // 确认指纹对账(指纹链)
238
- 16: 'hygiene', // 量化断言签名对账
239
- 17: 'hard', // 发版树未收口
240
- 18: 'hygiene', // 委派台账对账
241
- 19: 'hygiene', // 逐阶段审计
242
- 20: 'hygiene', // 引擎脚本测试覆盖
243
- // B6b-2 六段(2026-10-13 自源仓 SECTIONS 回灌;lane 沿源仓:21/22/24/26 hygiene,23/25 hard)
244
- 21: 'hygiene', // spec 验证落地核查(§21;锚 specVerifSince)
245
- 22: 'hygiene', // 机制使用量台账(§22;.agents/mechanism-registry.md 在场才启用)
246
- 23: 'hard', // 判据级收敛对账(§23;hard 档随 convergenceHardSince,锚前 advisory WARN)
247
- 24: 'hygiene', // incident 归因字段核查(§24;锚 attributionSince)
248
- 25: 'hard', // 路由预判一致性(§25;内容纯 WARN 不阻断,lane=hard 随源仓 SECTIONS)
249
- 26: 'hygiene', // 闭环漏斗「协议前」占比动作阈值(§26)
250
- '3x': 'hard', // incident 防复发验证证据门(§3 扩展,编号沿源仓 3x 写法;锚 incidentRegrSince)
251
- };
252
-
253
- // ---- runCheckLoop:门禁主流程可 import 化(2026-10-08 checkloop-importable;2026-10-04 isMain 行点名单独立项)----
254
- // import 本模块零副作用(isMain 主守卫,board-kb-p1 先例);opts = { root?, rev?, mode?, hardening? }——root 显式参数
255
- // 优先于 CHECK_LOOP_ROOT env 优先于 git toplevel(CLI 缺省行为逐字节不变);mode = 运行面(2026-10-13 分道:
256
- // 'hard'(缺省,关单/pre-push 面)| 'hygiene'(只卫生段)| 'all'(两段都跑=分道前裸跑全量);CLI 由 takeOpts
257
- // 注入,import 面按需显式给——需要全量语义的消费方传 'all',勿依赖缺省);返回 { exitCode, blockers, warnings },
258
- // 输出打印照旧在本函数内(稳定输出契约:banner 后空行、条目 `- ` 前缀、HARD-BLOCK/WARN 两段式——消费者 .githooks/pre-push)。
259
- // opts.rev 的 worktree 清理挂 process.on('exit')——进程内多次调用累计监听器(测试场景 ≤3 次,可接受)。
260
- // ---- 门禁 ROI 插桩件已抽至 gate-seg.mjs(2026-10-08 gate-roi-metrics)----
261
- // 抽因:check-loop.mjs 已 import check-hygiene.mjs,后者若再 import check-loop.mjs 即循环依赖——
262
- // 而两者都要插桩,判据单源必须只有一处。gateSeg / finishSegs / makeCollector 见该件;
263
- // 本文件在每段开头调 markGate(id,label),统计由数组长度差推出,不动任何 push 调用点。
264
-
265
- // writeGateStats:门禁 ROI 落盘(2026-10-08 gate-roi-metrics)——append 一行到
266
- // <root>/.agents/cache/gate-stats.jsonl(该目录已 gitignore,属运行时数据、不入 git、不进 kit.json
267
- // managed 台账——刻意避开 2026-10-05 探针临时件被 sync 收编的事故面)。
268
- // IO 失败只出账不阻断(沿 verify.mjs 凭证落账同款容错——度量失败不该让门禁变成红灯)。
269
- export function writeGateStats(root, segs) {
270
- try {
271
- const dir = path.join(root, '.agents', 'cache');
272
- fs.mkdirSync(dir, { recursive: true });
273
- const total = segs.reduce((a, s) => a + s.ms, 0);
274
- fs.appendFileSync(path.join(dir, 'gate-stats.jsonl'),
275
- `${JSON.stringify({ ts: new Date().toISOString(), root, segs, totalMs: total })}\n`);
276
- const hits = segs.filter((s) => s.warns || s.blocks).length;
277
- console.error(`[gate-stats] ${segs.length} 段已记账(命中 ${hits} 段)→ .agents/cache/gate-stats.jsonl`);
278
- } catch (e) {
279
- console.error(`[gate-stats] ⚠️ 落盘失败(${e.code || e.message})——不阻断门禁`);
280
- }
281
- }
282
-
283
- export function runCheckLoop(opts = {}) {
284
- const REV_ARG = opts.rev ?? null;
285
- const HARDENING = !!opts.hardening;
286
- const LOOP_MODE = opts.mode || 'hard'; // 分道运行面(2026-10-13 B6b-1):hard(缺省)| hygiene | all
287
- // laneOn(id):本运行面是否执行该段——all 全跑;hard/hygiene 只跑同名面(源仓 SECTIONS 过滤同款)。
288
- const laneOn = (id) => LOOP_MODE === 'all' || LANE_OF[id] === LOOP_MODE;
289
- if (REV_ARG && (opts.root || process.env.CHECK_LOOP_ROOT)) {
290
- console.error('check-loop: --rev 不能同时使用 root 参数 / CHECK_LOOP_ROOT');
291
- return { exitCode: 1, blockers: [], warnings: [] };
292
- }
293
- if (REV_ARG && /^0+$/.test(REV_ARG)) {
294
- console.error(`check-loop: --rev 不是提交 ${REV_ARG}`);
295
- return { exitCode: 1, blockers: [], warnings: [] };
296
- }
297
- let REV = null;
298
-
299
- // ---- 根目录与枚举单源 ----
300
- let ROOT;
301
- if (opts.root) {
302
- ROOT = path.resolve(opts.root);
303
- if (!fs.existsSync(ROOT)) {
304
- console.error('check-loop: root 不可访问:' + opts.root);
305
- return { exitCode: 1, blockers: [], warnings: [] };
306
- }
307
- } else if (process.env.CHECK_LOOP_ROOT) {
308
- ROOT = path.resolve(process.env.CHECK_LOOP_ROOT);
309
- if (!fs.existsSync(ROOT)) {
310
- console.error('check-loop: CHECK_LOOP_ROOT 不可访问:' + process.env.CHECK_LOOP_ROOT);
311
- return { exitCode: 1, blockers: [], warnings: [] };
312
- }
313
- } else {
314
- const top = gitOut(['rev-parse', '--show-toplevel']);
315
- if (top === null) {
316
- if (REV_ARG) {
317
- console.error(`check-loop: --rev 剥不到提交 ${REV_ARG}`);
318
- return { exitCode: 1, blockers: [], warnings: [] };
319
- }
320
- console.error('check-loop: 不在 git 仓库内,跳过扫描');
321
- return { exitCode: 0, blockers: [], warnings: [] };
322
- }
323
- ROOT = top.trim();
324
- if (REV_ARG) {
325
- const peeled = gitOut(['rev-parse', '--verify', `${REV_ARG}^{commit}`]);
326
- if (!peeled) {
327
- console.error(`check-loop: --rev 剥不到提交 ${REV_ARG}`);
328
- return { exitCode: 1, blockers: [], warnings: [] };
329
- }
330
- REV = peeled.trim();
331
- const parent = fs.mkdtempSync(path.join(os.tmpdir(), 'ck-rev-'));
332
- const wt = path.join(parent, 'wt');
333
- const main = ROOT;
334
- const add = spawnSync(GIT, ['worktree', 'add', '--detach', '--quiet', wt, REV], {
335
- cwd: main, encoding: 'utf8',
336
- });
337
- if (add.status !== 0) {
338
- fs.rmSync(parent, { recursive: true, force: true });
339
- console.error(`check-loop: 导出提交失败 ${REV_ARG}\n${add.stderr || add.stdout || ''}`);
340
- return { exitCode: 1, blockers: [], warnings: [] };
341
- }
342
- process.on('exit', () => {
343
- spawnSync(GIT, ['worktree', 'remove', '--force', wt], { cwd: main });
344
- fs.rmSync(parent, { recursive: true, force: true });
345
- });
346
- ROOT = wt;
347
- }
348
- }
349
- // 枚举单源(<root>/.agents/workflow-enums.txt——fixture 契约:缺文件/缺键 fail-loud)
350
- let ENUMS;
351
- try {
352
- ENUMS = loadEnums(path.join(ROOT, '.agents', 'workflow-enums.txt'));
353
- } catch (e) {
354
- const msg = String(e.message || '');
355
- if (msg.includes('不可读')) {
356
- console.error(`check-loop: 缺 ${path.join('.agents', 'workflow-enums.txt')}(枚举单源)——跑 flow-kit sync 恢复后重试`);
357
- } else {
358
- console.error('check-loop: 枚举单源 ' + msg);
359
- }
360
- return { exitCode: 1, blockers: [], warnings: [] };
361
- }
362
- const inSet = (v, arr) => arr.includes(v);
363
- const stOkDoc = (st) => inSet(st, ENUMS['doc.status.confirmed']);
364
-
365
- // git 调用(参数数组形式不走 shell——Windows cmd 不认单引号;git.exe 显式解析沿 doctor 先例)
366
- // 基础设施异常与业务失败分流(2026-10-05-gitout-fail-open):spawn 异常响亮出账(进程级去重恰一条,
367
- // 沿检查 16 装户「载入失败响亮出账」先例)+ 瞬时类错误码单次重试;「非 git 仓」(status≠0)仍是
368
- // 合法装户语义、静默走降级。intentional-simple: 重试后仍异常继续走原降级/拦截语义(连续瞬时异常
369
- // 残余面小且有账可查);升级路径 = 探测门(:720/:796)改三态拆分
370
- let gitInfraWarned = false;
371
- function warnGitInfra(args, code) {
372
- if (gitInfraWarned) return;
373
- gitInfraWarned = true;
374
- console.error(`check-loop: git 探测异常 ${args[0]}(${code})——按非 git 仓降级,检查面可能收窄`);
375
- }
376
- const GIT_TRANSIENT = new Set(['EAGAIN', 'EPERM', 'EMFILE', 'EINTR']);
377
- function spawnGit(args) {
378
- const opts = { cwd: ROOT, encoding: 'utf8', maxBuffer: 32 * 1024 * 1024 };
379
- let r = spawnSync(GIT, args, opts);
380
- if (r.error) {
381
- // 出账在重试终败后(与 linesOf 对称——瞬时重试恢复成功不打扰);非瞬时类直接出账
382
- if (GIT_TRANSIENT.has(r.error.code)) r = spawnSync(GIT, args, opts);
383
- if (r.error) warnGitInfra(args, r.error.code || r.error.message);
384
- }
385
- return r;
386
- }
387
- function gitOut(args, { ok = () => true } = {}) {
388
- const r = spawnGit(args);
389
- if (r.error || r.status !== 0 || !ok(r)) return null;
390
- return r.stdout || '';
391
- }
392
-
393
- // ---- frontmatter 受限子集读取(fm_get 语义:首行 --- 进入、下一 --- 闭合、键在行首、首个命中、值两侧去空白)----
394
- // fs 读取同走 fail-loud(2026-10-05-gitout-fail-open 实现期诊断追加,与 spawnGit 同一故障类):
395
- // readFileSync 瞬时异常(宿主资源压力 EMFILE/共享冲突类)重试一次,仍失败响亮出账(进程级去重)
396
- // 后按 null 降级——调用方按空文档跳过该件,但异常本身不再静默
397
- let fsReadWarned = new Set();
398
- const fileLinesCache = new Map();
399
- function linesOf(file) {
400
- if (!fileLinesCache.has(file)) {
401
- let lines = null;
402
- try {
403
- lines = fs.readFileSync(file, 'utf8').split(/\r?\n/);
404
- } catch (e) {
405
- try { lines = fs.readFileSync(file, 'utf8').split(/\r?\n/); } catch { lines = null; }
406
- if (!lines && !fsReadWarned.has(file)) {
407
- fsReadWarned.add(file);
408
- console.error(`check-loop: 文档读取异常 ${path.basename(file)}(${e.code || e.message})——按空文档降级,检查面可能收窄`);
409
- }
410
- }
411
- fileLinesCache.set(file, lines);
412
- }
413
- return fileLinesCache.get(file);
414
- }
415
- function fmGet(file, key) {
416
- const lines = linesOf(file);
417
- if (!lines) return '';
418
- const isDelim = (l) => /^---\s*$/.test(l);
419
- if (!isDelim(lines[0] || '')) return '';
420
- for (let i = 1; i < lines.length; i++) {
421
- if (isDelim(lines[i])) return '';
422
- if (lines[i].startsWith(key + ':')) return lines[i].slice(key.length + 1).trim();
423
- }
424
- return '';
425
- }
426
-
427
- // 落点空壳告警(2026-10-11 landing-reality,沉淀追踪第三级,incident/intent 两侧共用):
428
- // 「沉淀: <路径>」存在 ≠ 有效——文件存在但 sedimentLandingIsShell 为真(无来源 frontmatter
429
- // 且非占位正文不足 3 行)→ WARN 落点空壳(advisory,灰度第一档)。调用方须先出过「沉淀断档」
430
- // 分支(文件不存在),故此处 readFileSync 异常 = 真读取故障,按空壳出账并在文案注明读取失败。
431
- const warnSedimentShell = (single, sed) => {
432
- let text = null;
433
- try { text = fs.readFileSync(path.resolve(ROOT, sed), 'utf8'); } catch { text = null; }
434
- if (!sedimentLandingIsShell(text)) return;
435
- const readFail = text === null ? ';落点文件读取失败' : '';
436
- warnings.push(`- [WARN 落点空壳] ${single} frontmatter「沉淀: ${sed}」指向的文件存在但无有效内容(无来源 frontmatter 且非占位正文不足 3 行${readFail})——沉淀须真实整理而非空壳占位(advisory,灰度第一档)`);
437
- };
438
-
439
- const WF = 'workflow';
440
- const DOC_DIRS = ['intents', 'specs', 'plans', 'incidents'];
441
- const blockers = [];
442
- const warnings = [];
443
- // 门禁 ROI 收集器(2026-10-08 gate-roi-metrics):引用同一对数组 + 段游标,不复制任何数据。
444
- // 默认路径不打印不写盘(见 gate-seg.mjs 注释的输出契约硬约束)。
445
- const gateStats = makeCollector(warnings, blockers);
446
- const markGate = (id, label) => gateSeg(gateStats, id, label); // 局部别名,避免遮蔽同名导出
447
- // audit:false(init 新装)只保留 blockers。缺省与 audit:true 保持全量警告。
448
- // 硬规则:配对 / 验收勾验的阻断 / 确认留痕 / 发版草稿。卫生项走 warnings。
449
- const kitPolicy = loadKitPolicy(ROOT);
450
- if (!auditEnabled(kitPolicy)) {
451
- warnings.push = () => warnings.length;
452
- }
453
-
454
- // ---- 已提交(HEAD)过滤:仓库模式只扫 tracked(fixture 模式恒真;ls-tree 失败退化全扫)----
455
- let trackedSet = null; // null = 不过滤
456
- if (!process.env.CHECK_LOOP_ROOT) {
457
- const out = gitOut(['ls-tree', '-r', '--name-only', 'HEAD', '--', 'workflow']);
458
- if (out !== null) trackedSet = new Set(out.split('\n').map((l) => l.trim()).filter(Boolean));
459
- }
460
- const isTracked = (abs) => trackedSet === null || trackedSet.has(path.relative(ROOT, abs).split(path.sep).join('/'));
461
- const docFiles = (sub) => {
462
- const dir = path.join(ROOT, WF, sub);
463
- if (!fs.existsSync(dir)) return [];
464
- return fs.readdirSync(dir)
465
- .filter((f) => f.endsWith('.md') && /^\d/.test(f))
466
- .map((f) => path.join(dir, f))
467
- .filter((f) => isTracked(f))
468
- .sort();
469
- };
470
-
471
- // --- 1. intent/spec/plan 同名配对 + 状态确认 + L3 确认三件 + 风险泳道一致性 [hard-block] ---
472
- if (laneOn(1)) { // lane=hard:默认关单/pre-push 面(清单 5 随本段循环实现,同 lane)
473
- markGate('1', '意图/spec/plan 配对');
474
- for (const intent of docFiles('intents')) {
475
- const base = path.basename(intent);
476
- const st = fmGet(intent, '状态');
477
- const lvl = fmGet(intent, '级别');
478
- const risk = fmGet(intent, 'risk_level'); // 风险泳道字段(fill-intent 落,=级别;2026-09-30 hybrid-governance-risk-lanes)
479
- if (!stOkDoc(st)) {
480
- const msg = `${base}(frontmatter 状态键当前值:『${st || '缺失'}』)`;
481
- if (lvl === 'L3') blockers.push(`- [状态未确认] L3 intent 必须为 approved/done/superseded/cancelled:${msg}`);
482
- else warnings.push(`- [WARN 状态未确认] intent 必须为 approved/done/superseded/cancelled:${msg}`);
483
- }
484
- if (lvl === 'L2' || lvl === 'L3') {
485
- if (!fs.existsSync(path.join(ROOT, WF, 'specs', base))) {
486
- blockers.push(`- [配对断裂] intent 缺 spec:${base}(应在 ${WF}/specs/ 下同名)`);
487
- }
488
- }
489
- // plan 配对全级别强制(2026-10-13 L0 退役,自源仓收敛系列 1 回灌:原 L0 协作道豁免随级别退役删除;L2/L3 另须 spec)
490
- if (!fs.existsSync(path.join(ROOT, WF, 'plans', base))) {
491
- blockers.push(`- [配对断裂] intent 缺 plan:${base}(应在 ${WF}/plans/ 下同名)`);
492
- }
493
- // 风险泳道一致性(2026-10-02 caliber-convergence 起单源 laneOfEntry·方案 C 分歧双严):非 high
494
- // (low 或 suspect——级别/risk_level 缺失、非法、分歧)勾选触达红线 = 自认触及规则/契约或数据/运行时
495
- // 结构面——就高不就低,协作道不受理 → hard 判低,须对齐两字段至 L2/L3 并补同名 spec
496
- if (laneOfEntry(lvl, risk, kitPolicy.riskLevelSince, fmGet(intent, '日期')) !== 'high') {
497
- const redlineTouched = (linesOf(intent) || [])
498
- .some((l) => /^- \[x\]/.test(l) && /(\$\\rightarrow\$|→)\s*级别|级别至少\s*L[23]/.test(l));
499
- if (redlineTouched) {
500
- blockers.push(`- [红线判低] ${base} 级别/风险泳道为 ${[lvl, risk].filter(Boolean).join('/')} 但触达红线已勾选(规则/契约或 schema/结构面)——协作道不受理 STOP 级改动:就高不就低,把「级别」与「risk_level」两字段对齐到 L2/L3(fill-intent 双写口径)并补同名 spec`);
501
- }
502
- }
503
- }
504
-
505
- for (const spec of docFiles('specs')) {
506
- const base = path.basename(spec);
507
- const st = fmGet(spec, '状态');
508
- const lvl = fmGet(spec, '级别');
509
- const hasEntry = fs.existsSync(path.join(ROOT, WF, 'intents', base)) || fs.existsSync(path.join(ROOT, WF, 'incidents', base));
510
- if (!hasEntry) blockers.push(`- [配对断裂] spec 缺 intent/incident:${base}(应在 ${WF}/intents/ 或 ${WF}/incidents/ 下同名)`);
511
- if (!stOkDoc(st)) {
512
- const msg = `${base}(frontmatter 状态键当前值:『${st || '缺失'}』)`;
513
- if (lvl === 'L3') blockers.push(`- [状态未确认] L3 spec 必须为 approved/done/superseded/cancelled:${msg}`);
514
- else warnings.push(`- [WARN 状态未确认] spec 必须为 approved/done/superseded/cancelled:${msg}`);
515
- }
516
- // L3 确认三件:确认结果/确认时间读 frontmatter;独立复核按正文行锚定(放弃件豁免 = 枚举单源 abandoned 集)
517
- if (lvl === 'L3' && !inSet(st, ENUMS['doc.status.abandoned'])) {
518
- if (fmGet(spec, '确认结果') !== 'approved') blockers.push(`- [L3 确认缺失] ${base} 确认结果必须为 approved`);
519
- if (!fmGet(spec, '确认时间')) blockers.push(`- [L3 确认缺失] ${base} 必须记录确认时间`);
520
- if (!(linesOf(spec) || []).some((l) => /^- 独立复核:[ \t]*[^<\s]/.test(l))) {
521
- blockers.push(`- [L3 复核缺失] ${base} 必须记录新会话独立复核结论`);
522
- }
523
- }
524
- // 独立复核上下文标识(2026-10-13 B6b-2 自源仓 s01 回灌,policy v12 reviewerSince advisory):
525
- // 独立性声明须带可证伪基底——复核行落「复核上下文:<会话/子代理 id>」,使「主智能体自查冒充」
526
- // 从遗漏升级为积极伪造。只扫有独立复核行的 spec;锚前存量豁免不回填;缺键(v1–v11)→ 本子检整体跳过。
527
- if (kitPolicy.reviewerSince) {
528
- const rvDate = fmGet(spec, '日期') || (/^\d{4}-\d{2}-\d{2}$/.test(base.slice(0, 10)) ? base.slice(0, 10) : '');
529
- if (rvDate >= kitPolicy.reviewerSince) {
530
- const rvLine = (linesOf(spec) || []).find((l) => /^- 独立复核:/.test(l));
531
- if (rvLine && !/复核上下文:/.test(rvLine)) {
532
- warnings.push(`- [WARN 复核上下文缺失] ${base} 独立复核行缺「复核上下文:<会话/子代理 id>」——独立性声明无可证伪基底(C2,reviewerSince ${kitPolicy.reviewerSince})`);
533
- }
534
- }
535
- }
536
- }
537
-
538
- for (const plan of docFiles('plans')) {
539
- const base = path.basename(plan);
540
- const st = fmGet(plan, '状态');
541
- const lvl = fmGet(plan, '级别');
542
- const hasEntry = fs.existsSync(path.join(ROOT, WF, 'intents', base)) || fs.existsSync(path.join(ROOT, WF, 'incidents', base));
543
- // L1 plan 即入口(2026-10-13 B6b-2 自源仓 s01 回灌):级别恰好为 L1 的 plan 自己就是入口,无同名
544
- // intent/incident 不拦。级别缺失或 L2/L3 仍要求入口(fail-closed)。已写的 intent 不论级别仍要求同名 plan。
545
- if (lvl !== 'L1' && !hasEntry) blockers.push(`- [配对断裂] plan 缺 intent/incident:${base}(应在 ${WF}/intents/ 或 ${WF}/incidents/ 下同名)`);
546
- if (!stOkDoc(st)) {
547
- const msg = `${base}(frontmatter 状态键当前值:『${st || '缺失'}』)`;
548
- if (lvl === 'L3') blockers.push(`- [状态未确认] L3 plan 必须为 approved/done/superseded/cancelled:${msg}`);
549
- else warnings.push(`- [WARN 状态未确认] plan 必须为 approved/done/superseded/cancelled:${msg}`);
550
- }
551
- }
552
- } // laneOn(1) 守卫闭合
553
-
554
- // --- 卫生类检查 2 / 9 / 11 / 12 / 13(2026-10-08 selfmeasure-and-modularize 拆出)---
555
- // ⚠️ 调用点位置即输出顺序位:原实现分处五处,逐条顺序 2 → 9 → 11 → 12 → 13,而 warnings 按插入序输出、
556
- // 行序属稳定输出契约(pre-push / pre-commit 消费者 + doctor 按 WARN 行计数)。拆成一次调用后本块统一落在
557
- // 原检查 2 的位置,**块内顺序由 check-hygiene.mjs 保证**(与其内注释互引)。新增检查请按原编号插入
558
- // 到正确位置,勿一律追加末尾。
559
- // ctx 只传既有 helper、模块内零复刻:docFiles 的 tracked 过滤、fmGet 的 frontmatter 受限子集、
560
- // linesOf 的读异常响亮出账各自承载不可漂移语义,复刻即造口径分叉。audit:false 下 warnings.push 是
561
- // no-op,卫生项因此不出账(硬规则语义保持)。
562
- // 分道(2026-10-13):本调用是卫生段(2/9/11/12/13,lane=hygiene)唯一入口——硬门默认面整段跳过
563
- // (连带省掉检查 11/13 的生成器子进程);--hygiene / --all 才执行。
564
- if (laneOn(2)) warnings.push(...runCheckHygiene({ root: ROOT, WF, DOC_DIRS, docFiles, linesOf, fmGet, isTracked, readdirOrNull, kitPolicy, gateStats }));
565
- // --- 3. incidents 复盘三件套 + 状态严格枚举 + 新 intent 回路(回路断档 = hard)---
566
- if (laneOn(3)) { // lane=hard
567
- markGate('3', 'incidents 复盘三件套');
568
- for (const inc of docFiles('incidents')) {
569
- const name = path.basename(inc);
570
- const lines = linesOf(inc) || [];
571
- const incLvl = fmGet(inc, '级别');
572
- const incSt = fmGet(inc, '状态');
573
-
574
- if (!inSet(incSt, ENUMS['incident.status.all'])) {
575
- warnings.push(`- [WARN 状态非法] incident 状态必须为 open/fixed/closed:${name}(frontmatter 状态键当前值:『${incSt || '缺失'}』)`);
576
- }
577
-
578
- if (fmGet(inc, '流程') !== 'legacy') {
579
- if (!inSet(incLvl, ENUMS['level.all'])) {
580
- warnings.push(`- [WARN 级别缺失] ${name} 必须填写 L1/L2/L3(配对检查已跳过——补级别后重跑本脚本校验配对)`);
581
- } else {
582
- if (['L1', 'L2', 'L3'].includes(incLvl) && !fs.existsSync(path.join(ROOT, WF, 'plans', name))) {
583
- blockers.push(`- [配对断裂] incident 缺 plan:${name}(应在 ${WF}/plans/ 下同名)`);
584
- }
585
- if (['L2', 'L3'].includes(incLvl) && !fs.existsSync(path.join(ROOT, WF, 'specs', name))) {
586
- blockers.push(`- [配对断裂] incident 缺 spec:${name}(应在 ${WF}/specs/ 下同名)`);
587
- }
588
- }
589
- }
590
-
591
- // 三件套:正文行锚定 /^1\. /^2\. /^3\. (sh awk 同款)
592
- let trioOk = true;
593
- for (const n of [1, 2, 3]) {
594
- if (!lines.some((l) => l.startsWith(`${n}. `))) {
595
- warnings.push(`- [WARN 三件套不全] ${name} 缺复盘三件套之 ${n}`);
596
- trioOk = false;
597
- }
598
- }
599
- // 沉淀追踪(incident 侧,与检查 8 intent 侧对称):closed 且三件套齐全 = 最高价值沉淀源。
600
- // frontmatter「沉淀: <相对仓根路径>」登记去向;缺登记 → WARN 未沉淀(advisory,灰度第一档);
601
- // 登记了但文件不存在 → WARN 沉淀断档;存在但空壳(无来源且非占位正文不足 3 行)→ WARN 落点空壳。
602
- // 同「沉淀: 无」显式豁免口径。
603
- if (incSt === 'closed' && trioOk) {
604
- const sed = fmGet(inc, '沉淀');
605
- if (!sed) {
606
- warnings.push(`- [WARN 未沉淀] ${name} 复盘三件套齐全(closed)但未登记沉淀去向——整理到 wiki 后在 frontmatter 记「沉淀: wiki/<主题>/<文件>」,或显式写「沉淀: 无」(advisory,灰度第一档;沉淀是人工判断,机器只提醒不强制)`);
607
- } else if (sed !== '无' && !fs.existsSync(path.resolve(ROOT, sed))) {
608
- warnings.push(`- [WARN 沉淀断档] ${name} frontmatter「沉淀: ${sed}」指向的文件不存在——沉淀文件移动/改名后须同步更新本字段(advisory,灰度第一档)`);
609
- } else if (sed !== '无') {
610
- warnSedimentShell(name, sed); // 落点真实性(P1-3):存在但空壳 → WARN 落点空壳
611
- }
612
- }
613
- const hasParent = lines.some((l) => l.includes('是否需要新 intent'));
614
- if (!hasParent) {
615
- warnings.push(`- [WARN 三件套不全] ${name} 缺「是否需要新 intent」子项`);
616
- continue;
617
- }
618
- const yesLine = lines.find((l) => l.includes('是 → '));
619
- if (yesLine) {
620
- const m = yesLine.match(/intents\/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[^ )]*\.md/);
621
- const ref = m ? m[0] : null;
622
- if (!ref) blockers.push(`- [回路断档] ${name} 选「是」但未指明 intent 文件路径`);
623
- else if (!fs.existsSync(path.join(ROOT, WF, ref))) blockers.push(`- [回路断档] ${name} 引用的 intent 不存在:${ref}`);
624
- }
625
- }
626
- } // laneOn(3) 守卫闭合
627
-
628
- // --- 4. 引用有效性 [warning](.agents/ 路径须存在;skills 特例允许用户级 ~/.agents/skills)---
629
- if (laneOn(4)) { // lane=hygiene
630
- markGate('4', '引用有效性');
631
- {
632
- // 引用可带 {a,b,c} 花括号展开(仓库通写法 `fill-{intent,spec,plan}.mjs`)或 `*` 通配(`fill-*.mjs`)——
633
- // 花括号展开逐路查存在,任一路存在即有效;`*` 按目录枚举 glob 匹配,命中即有效;全不中才算断档
634
- // (2026-09-26 审查修复:正则字符类不含 {} *,曾把 `fill-{intent,spec,plan}.mjs` / `fill-*.mjs`
635
- // 截断成 `fill-` 误报引用断档)
636
- // 全角逗号不入字符类(2026-10-08 papercuts-cleanup-batch 修 4):中文文档路径引用后紧跟「,」时
637
- // 曾被并入引用串 → 引用断档误报(p0-gate-noise-batch 实证 2 条 + 本登记行自中);花括号保留({{VAR}} 引用形态)
638
- const refRe = /\.agents\/(commands|hooks|scripts|skills|roles)\/[A-Za-z0-9_][A-Za-z0-9_./{},*-]*/g;
639
- const expandRef = (ref) => {
640
- const m = ref.match(/^([^{]*)\{([^}]*)\}(.*)$/);
641
- if (!m) return [ref];
642
- return m[2].split(/[,,]/).map((v) => m[1] + v.trim() + m[3]);
643
- };
644
- // globExists:`*` 通配引用按目录枚举匹配(仅文件名层,`*` 不跨 /;目录不存在 = false)
645
- const globExists = (ref) => {
646
- const re = new RegExp('^' + path.basename(ref).replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '[^/\\\\]*') + '$');
647
- try { return fs.readdirSync(path.dirname(path.join(ROOT, ref))).some((f) => re.test(f)); } catch { return false; }
648
- };
649
- const refExists = (r) => (r.includes('*') ? globExists(r) : fs.existsSync(path.join(ROOT, r)));
650
- const HOME_DIR = process.env.HOME || process.env.USERPROFILE || '';
651
- const files = [];
652
- if (fs.existsSync(path.join(ROOT, 'AGENTS.md'))) files.push('AGENTS.md');
653
- for (const e of readdirOrNull(ROOT) || []) {
654
- const p = path.join(ROOT, e, 'AGENTS.md');
655
- if (isDirectoryOrNull(path.join(ROOT, e)) && fs.existsSync(p)) files.push(path.join(e, 'AGENTS.md'));
656
- }
657
- for (const f of readdirOrNull(path.join(ROOT, WF)) || []) {
658
- if (f.endsWith('.md')) files.push(`${WF}/${f}`); // workflow 根级 *.md(README 等)
659
- }
660
- for (const sub of DOC_DIRS) {
661
- const dir = path.join(ROOT, WF, sub);
662
- // 仅扫活跃态(draft/approved/open)——终态件的引用是历史叙述(提及已改名/已废文件属常态),
663
- // 扫了只会产生不可消除的 advisory 噪声,真漏点被淹没(2026-09-27 audit-gate-hardening)
664
- const activeSet = sub === 'incidents' ? ENUMS['incident.status.active'] : ENUMS['doc.status.active'];
665
- for (const f of readdirOrNull(dir) || []) {
666
- if (!f.endsWith('.md') || !(f === '_TEMPLATE.md' || /^\d/.test(f))) continue;
667
- if (f !== '_TEMPLATE.md' && !inSet(fmGet(path.join(dir, f), '状态'), activeSet)) continue;
668
- files.push(`${WF}/${sub}/${f}`);
669
- }
670
- }
671
- const cmdDir = path.join(ROOT, '.agents', 'commands');
672
- for (const f of readdirOrNull(cmdDir) || []) {
673
- if (f.endsWith('.md')) files.push(`.agents/commands/${f}`);
674
- }
675
- for (const rel of files) {
676
- const text = linesOf(path.join(ROOT, rel));
677
- if (!text) continue;
678
- const seen = new Set();
679
- for (const line of text) {
680
- for (const m of line.matchAll(refRe)) {
681
- const ref = m[0];
682
- if (seen.has(ref)) continue;
683
- seen.add(ref);
684
- const refs = expandRef(ref);
685
- if (refs.some(refExists)) continue;
686
- if (refs.some((r) => r.startsWith('.agents/skills/') && !r.includes('*') && fs.existsSync(path.join(HOME_DIR, r)))) continue;
687
- warnings.push(`- [WARN 引用断档] ${rel.split(path.sep).join('/')} 引用不存在的文件:${ref}`);
688
- }
689
- }
690
- }
691
- }
692
- } // laneOn(4) 守卫闭合
693
-
694
- // --- 5. 子智能体角色契约 + 宿主 Adapter 一致性 + 旧委派残留 + 钉死模型 [warning] ---
695
- if (laneOn(5)) { // lane=hygiene(清单 6:角色契约与 Adapter)
696
- markGate('5', '角色契约与宿主 Adapter');
697
- {
698
- const cmdFiles = () => (readdirOrNull(path.join(ROOT, '.agents', 'commands')) || [])
699
- .filter((f) => f.endsWith('.md')).map((f) => `.agents/commands/${f}`);
700
- // existsSync 守卫(2026-10-06-check19-entry-enoent 同类):AGENTS.md 等可合法缺失(调用方按空数组
701
- // 判定本就预期缺失态),fail-loud fs 读下按缺省跳过、不再响亮出账;其余调用方路径另有上游守卫
702
- const textOf = (rel) => {
703
- const p = path.join(ROOT, rel);
704
- return fs.existsSync(p) ? (linesOf(p) || []) : [];
705
- };
706
- for (const role of ['implementer', 'independent-reviewer', 'ui-verifier']) {
707
- const rolePath = `.agents/roles/${role}.md`;
708
- if (!fs.existsSync(path.join(ROOT, rolePath))) {
709
- warnings.push(`- [WARN 角色缺失] 公共角色契约不存在:${rolePath}`);
710
- continue;
711
- }
712
- if (fs.existsSync(path.join(ROOT, '.opencode', 'agents'))) {
713
- const p = `.opencode/agents/${role}.md`;
714
- if (!fs.existsSync(path.join(ROOT, p))) warnings.push(`- [WARN Adapter 缺失] OpenCode 缺 ${role}:${p}`);
715
- else {
716
- if (!/^mode:\s*subagent\s*$/m.test(textOf(p).join('\n'))) warnings.push(`- [WARN Adapter 无效] OpenCode ${role} 未声明 mode:subagent:${p}`);
717
- if (!textOf(p).some((l) => l.includes(rolePath))) warnings.push(`- [WARN Adapter 断线] OpenCode ${role} 未引用公共角色:${rolePath}`);
718
- }
719
- }
720
- if (fs.existsSync(path.join(ROOT, '.trae', 'agents'))) {
721
- const p = `.trae/agents/${role}.md`;
722
- if (!fs.existsSync(path.join(ROOT, p))) warnings.push(`- [WARN Adapter 缺失] Trae 缺 ${role}:${p}`);
723
- else {
724
- if (!new RegExp(`^name:\\s*${role}\\s*$`, 'm').test(textOf(p).join('\n'))) warnings.push(`- [WARN Adapter 无效] Trae ${role} 的 name 与文件名不一致:${p}`);
725
- if (!textOf(p).some((l) => l.includes(rolePath))) warnings.push(`- [WARN Adapter 断线] Trae ${role} 未引用公共角色:${rolePath}`);
726
- }
727
- }
728
- const zc = `.zcode/agents/${role}.md`;
729
- if (fs.existsSync(path.join(ROOT, zc))) { // .zcode/agents/ 现为入库件(2026-10-05 起宿主一律入库);缺失只说明宿主未装,不告警,存在时校验一致性
730
- if (!new RegExp(`^name:\\s*["']?${role}["']?\\s*$`, 'm').test(textOf(zc).join('\n'))) warnings.push(`- [WARN Adapter 无效] ZCode ${role} 的 name 与文件名不一致:${zc}`);
731
- if (!textOf(zc).some((l) => l.includes(rolePath))) warnings.push(`- [WARN Adapter 断线] ZCode ${role} 未引用公共角色:${rolePath}`);
732
- }
733
- const cited = ['AGENTS.md', ...cmdFiles()].some((f) => textOf(f).some((l) => l.includes(rolePath)));
734
- if (!cited) warnings.push(`- [WARN 命令断线] 工作流未引用公共角色:${rolePath}`);
735
- }
736
- // 旧委派残留 / 钉死模型(grep -nH 行格式 file:line:content)
737
- const legacyRe = /(^subagent:|subagent_type=|general_purpose_task|browser_use)/;
738
- const legacyHits = [];
739
- for (const f of ['AGENTS.md', ...cmdFiles()]) {
740
- textOf(f).forEach((l, i) => { if (legacyRe.test(l)) legacyHits.push(`${f}:${i + 1}:${l}`); });
741
- }
742
- if (legacyHits.length) warnings.push(`- [WARN 旧委派残留] 主规则或阶段命令仍含宿主特定/旧委派声明:\n${legacyHits.join('\n')}`);
743
- const modelHits = [];
744
- for (const h of ['.opencode', '.trae', '.zcode']) {
745
- for (const f of readdirOrNull(path.join(ROOT, h, 'agents')) || []) {
746
- if (!f.endsWith('.md')) continue;
747
- const rel = `${h}/agents/${f}`;
748
- textOf(rel).forEach((l, i) => { if (/^model:/.test(l) && !/^model:\s*inherit/.test(l)) modelHits.push(`${rel}:${i + 1}:${l}`); });
749
- }
750
- }
751
- if (modelHits.length) warnings.push(`- [WARN 宿主耦合] 薄 Adapter 不应固定模型:\n${modelHits.join('\n')}`);
752
- }
753
- } // laneOn(5) 守卫闭合
754
-
755
- // --- 6. 阶段索引同步 [warning](2026-10-09 engine-quality-round2 A1:实现迁 check-stage-index.mjs——
756
- // 先例 check-hygiene / check-metric-claims;段 id 沿 sh 版 '6',清单编号 7 与文案逐字不动;
757
- // 调用点位置即输出顺序契约)---
758
- if (laneOn(6)) warnings.push(...runCheckStageIndex({ root: ROOT, linesOf, gateStats })); // lane=hygiene(清单 7)
759
-
760
- // --- 共享:文件「首次加入 git」的日期索引(2026-09-28 check8-git-anchor)---
761
- // 用途:检查 8 的生效日锚从**可手填的文件名前缀**(项目命名规范本身即 `YYYY-MM-DD-<主题>`,作者
762
- // 日常手写该前缀,「写早」零成本、顺手即发生——一条 hard 门可被平凡绕过)改为**首次加入 git 的日期**。
763
- // **诚实边界(复核 P1 更正)**:该锚取 `git log --diff-filter=A --format=@%aI`,即 **author date
764
- // (作者自报时间戳)**,**不是** commit 时刻——`git commit --date=<过去>` 一条参数即可伪造,故
765
- // 「锚不可手填」的说法**不成立**。本改动的确切收益是:关掉「改文件名(日常必写、零成本)」这条通道,
766
- // 把伪造成本抬到「主动加参数伪造时间戳」——后者与「伪造台账」同属**本地信任边界内不可机器防**的范畴
767
- // (事后对质靠 git 历史与台账)。此处如实声明,不宣称「通道已关闭」。
768
- // 口径:git 按时间新→旧遍历,同一文件首遇即最早那次加入(与检查 10 的 addpath 同款判据)。
769
- // 非 git / 命令失败 → null,调用方按既有「非 git 跳过」语义退化(不 fail-loud)。
770
- // 注:检查 10 需要的是「文件→加入 commit」+「commit→文件清单」两份映射(判断同提交是否触及迁移 SQL),
771
- // 与本索引「文件→日期」不同构,故**不合并**——避免把两处判据耦死。
772
- // addedDates(2026-10-09 engine-quality-round3 W1):全史解析走持久缓存(HEAD 键)——
773
- // 同 HEAD 多入口复跑(verify/edit-face-check/pre-commit/CI)不再重复全算;git-dir 探测保留在前。
774
- const addedDates = gitOut(['rev-parse', '--git-dir']) === null ? null : addedDatesWithCache({
775
- head: gitOut(['rev-parse', 'HEAD']),
776
- gitLog: () => gitOut(['log', '--diff-filter=A', '--format=@%aI', '--name-only']),
777
- cachePath: path.join(ROOT, '.agents', 'cache', 'added-dates.json'),
778
- });
779
- // 某文档「首次加入日期」(YYYY-MM-DD);不可判定(非 git / 查不到)返回 ''
780
- const addedDateOf = (absDoc) => {
781
- if (!addedDates) return '';
782
- const rel = path.relative(ROOT, absDoc).split(path.sep).join('/');
783
- const iso = addedDates.get(rel);
784
- return iso ? iso.slice(0, 10) : '';
785
- };
786
-
787
- // 豁免/放行分支出账(fail-loud 口径——「裁决消失」不可归因的教训:豁免路径零痕迹;
788
- // 2026-10-05-check8-digit-sha-misfire):按 type 进程级去重,每类至多一条;stderr 不改 stdout 协议
789
- const evidenceExemptWarned = new Set();
790
- function warnEvidenceExempt(type, base) {
791
- if (evidenceExemptWarned.has(type)) return;
792
- evidenceExemptWarned.add(type);
793
- console.error(`check-loop: 证据豁免 ${type} ${base}——该文档的验收证据未做真相核验`);
794
- }
795
-
796
- // 证据真相校验:检查证据字符串是否包含合法的 commit SHA,且该 commit 触及了 plan 声明的文件
797
- // 测试绿声明对账(2026-10-07 verify-evidence):ctx = { verifyRelevant, hasFresh } 时,无 SHA 且命中
798
- // 关键词的证据走凭证对账——有 24h 绿行 → verify 型豁免出账;无 → verify-missing(聚合段出 warning,
799
- // 灰度第一档非 blocker)。ctx 由调用方按「intent 加入 git ≥ verifySince(v5 锚)」组装;锚不可判定
800
- // → ctx null → 维持 text 豁免(无判定依据不产出告警)。关键词表最小集起步(check2-datetime 先例:
801
- // 只豁免实证形态,变体实证再扩)。
802
- const VERIFY_GREEN_RE = /测试通过|测试全绿|测试绿|全绿/;
803
- function verifyEvidenceTruth(evidenceStr, planBase, root, ctx) {
804
- const shaMatch = evidenceStr.match(/\b([a-f0-9]{7,40})\b/i);
805
- if (!shaMatch) {
806
- if (ctx && ctx.verifyRelevant && VERIFY_GREEN_RE.test(evidenceStr)) {
807
- if (ctx.hasFresh) {
808
- warnEvidenceExempt('verify', planBase);
809
- return { ok: true, type: 'verify' };
810
- }
811
- return { ok: true, type: 'verify-missing' };
812
- }
813
- warnEvidenceExempt('text', planBase);
814
- return { ok: true, type: 'text' };
815
- }
816
-
817
- const sha = shaMatch[1];
818
- // 直连走 spawnGit(与 gitOut 同一 loud+retry 通道,注释互引):spawn 异常不再被静默算作业务失败;
819
- // 重试后仍异常按下方 status!==0 判定(fail-closed 保持——本地核验不了就按伪造拦)
820
- const revParse = spawnGit(['rev-parse', sha]);
821
- if (revParse.status !== 0) {
822
- // git 通道坏死(spawn 异常,非 git 的正常回答)→ 禁用下方两类豁免:「实证分流」依赖 rev-parse
823
- // 可用,通道失效时纯数字/外部引用都无法实证,按伪造拦(fail-closed,与 :672 注释一致)。
824
- // v1.3.0 Release CI 实证:fixture 短 sha 恰全数字(≈4%/run)时,纯数字 text 豁免曾把本场景
825
- // fail-closed 漏成 exit 0(ubuntu 腿);win32 sha 含字母走 forged 故本地恒绿——平台概率差异。
826
- if (revParse.error) {
827
- return { ok: false, type: 'forged', msg: `提交 ${sha} 不存在` };
828
- }
829
- // 纯数字串且解析失败 → 时间戳/ID 维持文本豁免(2026-10-05-check8-digit-sha-misfire:形态守卫
830
- // 曾把全数字短 SHA≈4.4%/夹具 误分类为文本致核验静默跳过——改由 rev-parse 实证分流)。
831
- // 纪律:文本启发式须可被实证兜底,禁以字符形态抢先分类。
832
- if (/^\d+$/.test(sha)) {
833
- warnEvidenceExempt('text', planBase);
834
- return { ok: true, type: 'text' };
835
- }
836
- // 区分本地伪造与外部仓库引用:
837
- // 剔除 SHA 与泛指词后仍有其他内容(如项目名、路径描述)→ 视为外部仓库引用,不硬拦(本地无法核验他仓哈希);
838
- // 剔除后为空(如纯「commit a1b2c3d」「提交 a1b2c3d」)→ 视为本地引用伪造,硬拦。
839
- const residue = evidenceStr.replace(sha, '')
840
- .replace(/证据[::]|commit|提交|[()()。—-]/gi, '')
841
- .trim();
842
- if (residue.length > 0) {
843
- warnEvidenceExempt('external', planBase);
844
- return { ok: true, type: 'external' };
845
- }
846
- return { ok: false, type: 'forged', msg: `提交 ${sha} 不存在` };
847
- }
848
-
849
- // 解析成功(含纯数字短 SHA 命中提交/ref 的情形)→ 真相核验
850
- const planPath = path.join(ROOT, WF, 'plans', planBase + '.md');
851
- if (!fs.existsSync(planPath)) {
852
- warnEvidenceExempt('no-plan', planBase);
853
- return { ok: true, type: 'no-plan' }; // 缺 plan 走 Check 1 拦截
854
- }
855
-
856
- const planLines = linesOf(planPath) || [];
857
- const declaredFiles = [];
858
- // 扫描「改动面」「任务拆解」或「改动方案」(L1 Quick-Plan 生成器 fill-plan 输出)节
859
- let inDeclaredSec = false;
860
- for (const line of planLines) {
861
- if (/^##\s+(改动面|任务拆解|改动方案)/.test(line)) { inDeclaredSec = true; continue; }
862
- if (inDeclaredSec && /^##\s+/.test(line)) { inDeclaredSec = false; continue; }
863
- if (inDeclaredSec) {
864
- const fileMatch = line.match(/([a-zA-Z0-9._/-]+\.[a-zA-Z0-9]+)/);
865
- if (fileMatch) declaredFiles.push(fileMatch[1]);
866
- }
867
- }
868
-
869
- const show = spawnGit(['show', '--name-only', sha]);
870
- if (show.status !== 0) return { ok: false, type: 'error', msg: `无法读取提交 ${sha} 的文件列表` };
871
-
872
- const changedFiles = show.stdout.split(/\r?\n/).filter(Boolean);
873
- const hasIntersection = changedFiles.some(f => declaredFiles.some(df => f.includes(df) || df.includes(f)));
874
-
875
- if (!hasIntersection) {
876
- // 过程证据(2026-10-03 check-evidence-process):执行器驱动的提交可作验收证据——提交信息带
877
- // 「pipeline-run <runId>」标记(docsCommit 四种格式共有段,runId 严格形态 日期8-时间4-主题-尾;
878
- // 与 run 事件流同源,git 历史留痕可对质)。只救 irrelevant:forged(SHA 不存在)在前已判,其余判据不动。
879
- // 记录型标志(2026-10-06-v114-backflow-batch):docs 系 Conventional Commit(冒烟报告 / 留痕 / 关单台账)
880
- // 不触 plan 声明面属预期——是否降级豁免由检查 8 聚合段判(须同文档存在可过检实现证据),此处只出标志。
881
- const subj = spawnGit(['log', '-1', '--format=%s', sha]);
882
- const recordCommit = subj.status === 0 && /^docs[(:]/.test(subj.stdout.trim());
883
- if (subj.status === 0 && /pipeline-run [0-9]{8}-[0-9]{4}-[A-Za-z0-9-]+/.test(subj.stdout)) {
884
- warnEvidenceExempt('process', planBase);
885
- return { ok: true, type: 'process' };
886
- }
887
- return { ok: false, type: 'irrelevant', msg: `提交 ${sha} 未触及 plan 声明的任何文件`, recordCommit };
888
- }
889
-
890
- return { ok: true, type: 'sha' };
891
- }
892
-
893
- // --- 3 扩展(§3x,编号沿源仓 3x 写法——gate-checklist 按 `N.` 解析,本段不入配对面).
894
- // incident 防复发验证证据门 [hard-block](2026-10-13 B6b-2 自源仓 s03x 回灌;出处沿革留痕在包源仓
895
- // git 历史与 CHANGELOG)。调用点位置 = 源仓 SECTIONS 段序(s03x 居卫生 4/5/6 之后、检查 8 之前),
896
- // 亦为本段消费 addedDateOf 的前置依赖位(git 建档日锚单源定义于上)---
897
- // incidents 模板「防复发验证」强制项的机器面:防复发验证必须落到自动化用例或回归清单条目,禁「只写已人工验证」。
898
- // fixed/closed 且 git 建档日 ≥ incidentRegrSince(policy v9;v1–v8 缺键 → 整体跳过)的 incident,
899
- // 正文无自动化用例 / 回归清单引用 → hard。判据 = 宽匹配正则(引擎 .test.mjs / 回归清单 / 冒烟 / 测试命令)
900
- // ——门的是「落到可复跑的验证资产」,不是猜具体测试名;存量(< 锚)豁免(不可判定亦不拦——无判定依据不出 hard)。
901
- // kit 适配(源仓→kit 逐条):证据正则剔除源仓实例路径面(backend/…Tests.cs、frontend/__tests__),
902
- // kit 口径保留通用形态(.test.mjs / workflow/regression-checklist.md(kit 模板同款件)/ 测试与门命令)。
903
- if (laneOn('3x')) { // lane=hard:防复发证据门
904
- markGate('3x', 'incident 防复发验证证据门');
905
- {
906
- const regrAnchor = kitPolicy.incidentRegrSince;
907
- if (regrAnchor) {
908
- const REGR_EVIDENCE_RE = /\.test\.mjs|workflow\/regression-checklist\.md|regression-smoke|npm\s+test|dotnet\s+test|run-tests|verify\.mjs/;
909
- for (const inc of docFiles('incidents')) {
910
- const incSt = fmGet(inc, '状态');
911
- if (!['fixed', 'closed'].includes(incSt)) continue;
912
- const add = addedDateOf(inc);
913
- if (!add || add < regrAnchor) continue; // 存量豁免(不可判定亦不拦——无判定依据不出 hard)
914
- const lines = linesOf(inc) || [];
915
- if (!lines.some((l) => REGR_EVIDENCE_RE.test(l))) {
916
- blockers.push(`- [回归证据缺失] ${path.basename(inc)} 已 ${incSt} 但防复发验证未落自动化用例/回归清单引用(模板强制项,禁「已人工验证」)`);
917
- }
918
- }
919
- }
920
- }
921
- } // laneOn('3x') 守卫闭合
922
-
923
- // --- 8. intent 验收标准对账(done 须逐条勾验并补证据;新建 hard,存量聚合 warning)---
924
- if (laneOn(8)) { // lane=hard:验收对账
925
- markGate('8', '验收标准对账');
926
- // 生效日锚 2026-09-28 改「git 首次加入日期」(此前取文件名前 10 字符——命名规范强制的字段、
927
- // 写早零成本)。非 git → 不可判定 → 走存量口径(不误报 hard)。
928
- {
929
- const accCutoff = '2026-09-12';
930
- let legacyUnaccounted = 0;
931
- // 测试绿缺凭证聚合面(2026-10-18 告警聚合口径批):**判据不变**(同一批文档/证据项照常检出),
932
- // 只改输出形态——单文档多证据项只计一份;跨运行当日去重(同文档当日只逐份点名一次,已点名的
933
- // 进一条聚合计数行,防静默被误读为已修)。背景:源仓 9 天遥测该 WARN 占全部告警 61%
934
- //(1062/1738,文档密集期 14.8 条/运行)——复读刷屏稀释 WARN 信号价值。状态面放 os.tmpdir()
935
- // 按 ROOT 派生键(本地机判、不进装户仓、无 gitignore 依赖、fail-open:读失败=全点名,落失败不影响裁决)。
936
- const verifyMissingDocs = new Map(); // rel -> base(去重键 = 仓内相对路径)
937
- // 测试绿凭证状态(2026-10-07 verify-evidence):台账读一次循环外缓存;policy 缺 verifySince
938
- //(v1-v4)→ ctxBase null → 对账整体跳过(向后兼容)
939
- const verifySinceOf = kitPolicy.verifySince;
940
- // 台账内容循环外读一次并缓存(doc 过滤是纯内存行匹配,不新增子进程——门禁成本零增加)。
941
- const verifyLines = (() => {
942
- try {
943
- const vp = path.join(ROOT, '.agents', 'verifications.jsonl');
944
- return fs.existsSync(vp) ? fs.readFileSync(vp, 'utf8').split(/\r?\n/) : null;
945
- } catch { return null; }
946
- })();
947
- // 全局绿行(v5 语义):仅供 v1-v5 装户走原路径,本仓 v6+ 不再消费它。
948
- const verifyFreshGlobal = verifyLines ? hasFreshVerifyLine(verifyLines) : false;
949
- // 2026-10-08 verify-doc-binding:v6+(verifyDocSince)按本 doc 精确匹配;缺键维持全局布尔。
950
- const verifyDocBound = typeof kitPolicy.verifyDocSince === 'string';
951
- // 2026-10-09 verifydoc-anchor:v6 精确匹配的**追溯边界**——只对「确认门 done ts ≥ verifyDocSince」的单生效。
952
- // 背景(用户 2026-10-09 拍板 D):4 单(verify-evidence / workflow-dashboard / selfmeasure / gate-roi-metrics)
953
- // 的 done ts 均 < v6 上线日(2026-10-08 17:37),它们关单时既无 --doc 机制、也无从补证——被精确匹配追责
954
- // 会产 9 条不可消退 advisory(补跑=自证,回溯不了关单当时全绿,与门禁本意相悖)。退回全局布尔 = v5 语义
955
- // (不误报、不伪造),与检查 15/18 生效日锚同构。done ts 台账读一次循环外缓存,零新增子进程。
956
- const verifyDocSinceTs = verifyDocBound ? kitPolicy.verifyDocSince : null;
957
- const doneTsOf = (() => {
958
- const map = new Map();
959
- try {
960
- // 读法收敛 ledger-loader(2026-10-12 ledger-loader-p1):末次 done 跳转取自物理读序,
961
- // loader 保持读序返回故「取末次」语义与逐处直读一致(分片按文件名序排在主台账之后=较新)
962
- for (const e of readLedgerRows(ROOT)) {
963
- if (e && e.doc && ['done', 'closed'].includes(e.stage)) map.set(e.doc, e.ts || '');
964
- }
965
- } catch { /* 台账不可读 → 无锚 → 全走全局布尔(fail-open,不误报 hard) */ }
966
- return map;
967
- })();
968
- // 该 doc 的确认门 done 是否落在 v6 追溯窗口内;无台账行 / 台账不可读 → false(存量豁免,退回全局布尔)
969
- // 2026-10-09 verifydoc-anchor:按 ISO 时刻比较(不再是日期粒度)——机制上线当日的更早时刻 done 的单
970
- // 仍在窗口外(日期粒度会把同日的早时刻误纳入,见 policy.mjs verifyDocSince 注释)。
971
- const verifyDocInWindow = (rel) => {
972
- if (!verifyDocSinceTs) return false;
973
- const ts = doneTsOf.get(rel);
974
- return !!ts && ts >= verifyDocSinceTs;
975
- };
976
- const verifyFreshFor = (rel) => (verifyLines
977
- ? hasFreshVerifyLine(verifyLines, Date.now(), verifyDocInWindow(rel) ? rel : null)
978
- : false);
979
- for (const intent of docFiles('intents')) {
980
- if (fmGet(intent, '状态') !== 'done') continue;
981
- const base = path.basename(intent);
982
- const rel = path.relative(ROOT, intent).split(path.sep).join('/'); // 与 verify.mjs --doc 落账口径同源
983
- const lines = linesOf(intent) || [];
984
- // 节扫描:hs=有验收节;insec 至下一个二级标题;uc=未勾项;ne=勾选缺证据;ex=存量豁免声明
985
- // 证据可写在 [x] 行的续行(仓库通写法「(证据:…)」另起一行)——pendX 记「待证据项」,
986
- // 遇证据行(全角「:」/半角「:」皆认)清零;遇下一条目 / 下一小节 / 节末仍无证据 → ne
987
- let hs = false, uc = false, ne = false;
988
- let insec = false, ex = false;
989
- let pendX = false; // 上一 [x] 项尚无证据,证据可能在紧随的续行
990
- let currentEvidence = ''; // 当前条目的证据内容,用于语义校验
991
- const evidenceItems = []; // 逐条证据(2026-10-06-v114-backflow-batch:两遍裁决——先文档级判实现证据在场,再逐条落判)
992
- const evRe = /证据[::]/;
993
- const closeItem = () => {
994
- if (pendX) {
995
- ne = true;
996
- pendX = false;
997
- }
998
- if (currentEvidence && !ex) {
999
- evidenceItems.push(currentEvidence);
1000
- }
1001
- currentEvidence = '';
1002
- };
1003
- for (const line of lines) {
1004
- if (/存量对账豁免(/.test(line)) ex = true;
1005
- if (/^\s*##\s+[^#]*验收标准/.test(line)) { hs = true; insec = true; closeItem(); continue; }
1006
- if (insec && /^\s*##\s/.test(line)) { insec = false; closeItem(); continue; }
1007
- if (!insec) continue;
1008
- if (/^\s*- \[ \]/.test(line)) { closeItem(); uc = true; continue; }
1009
- if (/^\s*- \[x\]/.test(line)) {
1010
- closeItem();
1011
- pendX = !evRe.test(line);
1012
- if (evRe.test(line)) currentEvidence = line.split(/证据[::]/)[1].trim();
1013
- continue;
1014
- }
1015
- if (pendX && evRe.test(line)) {
1016
- pendX = false;
1017
- currentEvidence = line.split(/证据[::]/)[1].trim();
1018
- } else if (currentEvidence && line.trim() && !/^\s*- /.test(line)) {
1019
- // 简单累加续行证据
1020
- currentEvidence += ' ' + line.trim();
1021
- }
1022
- }
1023
- closeItem(); // 节末(或全文末)仍无证据 → 计缺证据
1024
- // 两遍裁决(2026-10-06-v114-backflow-batch 记录型提交豁免):文档级先判「存在可过检实现证据」
1025
- // (sha / process 型任一),记录型提交(subject=docs 系)证据仅在实现证据在场时降级豁免告警——
1026
- // 冒烟报告 / approved 留痕 / 关单提交不改 plan 声明面属预期;仅引记录型而无实现证据 → 维持 hard-block
1027
- //(豁免通道不得独立成立,防「只引 docs 提交洗白代码改动」)。
1028
- if (evidenceItems.length) {
1029
- const planBase = base.replace(/.md$/, '');
1030
- // verify 对账 ctx:intent 首次加入 git ≥ verifySince(v5 锚)才参与;不可判定 → null 走 text 豁免
1031
- const iadd = addedDateOf(intent);
1032
- const vctx = typeof verifySinceOf === 'string' && iadd !== '' && iadd >= verifySinceOf
1033
- ? { verifyRelevant: true, hasFresh: verifyDocBound ? verifyFreshFor(rel) : verifyFreshGlobal } : null;
1034
- const results = evidenceItems.map((ev) => ({ t: verifyEvidenceTruth(ev, planBase, ROOT, vctx) }));
1035
- const hasImplEvidence = results.some((r) => r.t.ok && (r.t.type === 'sha' || r.t.type === 'process'));
1036
- for (const r of results) {
1037
- if (r.t.ok && r.t.type === 'verify-missing') {
1038
- verifyMissingDocs.set(rel, base); // 出账统一在循环外(聚合/当日去重,见声明处注释)
1039
- continue;
1040
- }
1041
- if (r.t.ok) continue;
1042
- if (r.t.type === 'irrelevant' && r.t.recordCommit && hasImplEvidence) {
1043
- warnEvidenceExempt('record', planBase);
1044
- continue;
1045
- }
1046
- blockers.push(`- [证据${r.t.type === 'forged' ? '伪造' : '无关'}] ${base} 验收证据校验失败: ${r.t.msg}`);
1047
- }
1048
- }
1049
- // 生效日锚 = git 首次加入日期(2026-09-28 改;此前取文件名前 10 字符)。**准确收益**:关掉
1050
- // 「改文件名日期(日常必写、零成本)即整段跳过 hard 门」这条通道;锚取 author date(%aI),
1051
- // 刻意伪造(`git commit --date=`)仍可绕过——与伪造台账同属本地信任边界内,不宣称"通道已关闭"。
1052
- // 非 git / 查不到 → '' → isNew=false → 走存量口径(与既有语义一致:不可判定时不误报 hard)。
1053
- const adddate = addedDateOf(intent);
1054
- const isNew = adddate !== '' && adddate >= accCutoff;
1055
- if (!hs) {
1056
- if (isNew) blockers.push(`- [验收未对账] done intent 缺「## 验收标准」节(勾验无从核对):${base}`);
1057
- else if (!ex) legacyUnaccounted++;
1058
- continue;
1059
- }
1060
- // 场景覆盖子判据(2026-10-10 scenario-coverage,灰度第一档 = warning):
1061
- // 同名 spec 写了「## 验收场景」节(GIVEN/WHEN/THEN,每条带 ID:S1、S2…)时,
1062
- // done intent 的验收标准须**逐场景 ID 引用**(`场景:S1`)。缺引用只出 warning——
1063
- // 有意不进 hard:新判据先灰度观察存量装户告警噪音,沿检查 8 自身 / 检查 15 / 检查 18
1064
- // 「先 WARN、装户吃过警告后升 FAIL」的既有路径;spec 无该节 = 原判据零变化。
1065
- // ID 提取单源 = 本块(spec 侧),引用匹配只认验收标准节内的 `场景:S<n>` 行。
1066
- // 引用断链子判据(2026-10-11 dangling-ref,P2-1,灰度第一档 = warning):
1067
- // 上判据的**反向对账**——验收标准引用了 spec 未声明的场景 ID = 悬空引用(改 ID 漏改 / 复制粘贴
1068
- // 残留的机器信号);spec 无场景节但引用了 S<n> 同样算断链(引用了不存在的场景)。与「场景未覆盖」
1069
- // 共用同一次 ID 解析与引用遍历(covered 一份两用),不重复解析。
1070
- // THEN 断言子判据(2026-10-11 then-assertion,P2-2,灰度第一档 = warning):
1071
- // 声明了场景却无 THEN 断言行 = 空壳场景——THEN 是可观测结果的机器对账锚(GIVEN/WHEN 可省),
1072
- // 聚合一条不逐场景刷屏;验收场景节本身可选,节不存在 → 零变化。
1073
- const specPath = path.join(ROOT, WF, 'specs', base);
1074
- if (fs.existsSync(specPath)) {
1075
- const sids = scenarioIdsOf(specPath);
1076
- // 引用遍历单次(覆盖/断链两方向共用):不锁进 sids.length 分支——spec 无场景节时引用同样悬空
1077
- const covered = new Set();
1078
- for (const line of lines) {
1079
- const m = line.match(/场景[::]\s*S(\d+)/);
1080
- if (m) covered.add(`S${m[1]}`);
1081
- }
1082
- if (sids.length) {
1083
- const missing = sids.filter((id) => !covered.has(id));
1084
- if (missing.length) {
1085
- warnings.push(`- [WARN 场景未覆盖] ${base} 同名 spec 有验收场景但验收标准未逐场景引用:缺 ${missing.join('、')}——在「## 验收标准」按「- [x] 场景:S<n> <判据>(证据:…)」补齐(advisory,灰度第一档;不写场景节的 spec 不适用)`);
1086
- }
1087
- // THEN 对账需 spec 全文(scenarioIdsOf 只回 ID);读取失败 = 不可判定 → 跳过不误报(fail-open)
1088
- let thenMap = null;
1089
- try { thenMap = extractThenByScenario(fs.readFileSync(specPath, 'utf8')); } catch { /* 极窄竞态,不判空壳 */ }
1090
- if (thenMap) {
1091
- const noThen = sids.filter((id) => !(thenMap.get(id) || []).length);
1092
- if (noThen.length) {
1093
- warnings.push(`- [WARN 场景无断言] ${base} 同名 spec 场景缺 THEN 断言:${noThen.join('、')}——每场景至少一行「- THEN <可观测结果>」(GIVEN/WHEN 可省;advisory,灰度第一档)`);
1094
- }
1095
- }
1096
- }
1097
- const dangling = [...covered].filter((id) => !sids.includes(id));
1098
- if (dangling.length) {
1099
- warnings.push(`- [WARN 场景引用断链] ${base} 验收标准引用了 spec 未声明的场景 ID:${dangling.join('、')}——修正 ID 或在 spec「## 验收场景」补该场景(advisory,灰度第一档)`);
1100
- }
1101
- }
1102
- // 沉淀追踪子判据(2026-10-10 sediment-tracking,灰度第一档 = warning):
1103
- // intent 高价值节(影响面 / 触达红线)是 wiki 沉淀的主源——frontmatter「沉淀: <相对仓根路径>」
1104
- // 登记去向(如 wiki/项目规范/xxx.md),「沉淀: 无」= 显式声明不沉淀。缺登记且内容高价值
1105
- // → WARN 未沉淀(advisory:沉淀是人工判断,机器只提醒不强制,不进 hard);登记了但文件
1106
- // 不存在 → WARN 沉淀断档(路径漂移);存在但空壳(无来源且非占位正文不足 3 行)→ WARN 落点
1107
- // 空壳(2026-10-11 landing-reality,P1-3 落点真实性)。高价值判据 = 两节之一有非占位正文内容。
1108
- // incident 侧对称(检查 3 内):closed 且复盘三件套齐全 = 最高价值沉淀源,同款提醒。
1109
- // 有意不加 policyVersion 锚:字段缺失 = 未登记,无字段语义零变化(沿场景覆盖子判据同款口径)。
1110
- const sed = fmGet(intent, '沉淀');
1111
- const highValue = sectionHasBody(lines, '影响面') || sectionHasBody(lines, '触达红线');
1112
- if (highValue && !sed) {
1113
- warnings.push(`- [WARN 未沉淀] ${base} 含高价值沉淀内容(影响面/触达红线)但未登记沉淀去向——整理到 wiki 后在 frontmatter 记「沉淀: wiki/<主题>/<文件>」,或显式写「沉淀: 无」(advisory,灰度第一档;沉淀是人工判断,机器只提醒不强制)`);
1114
- } else if (sed && sed !== '无' && !fs.existsSync(path.resolve(ROOT, sed))) {
1115
- warnings.push(`- [WARN 沉淀断档] ${base} frontmatter「沉淀: ${sed}」指向的文件不存在——沉淀文件移动/改名后须同步更新本字段(advisory,灰度第一档)`);
1116
- } else if (sed && sed !== '无') {
1117
- warnSedimentShell(base, sed); // 落点真实性(P1-3):存在但空壳 → WARN 落点空壳
1118
- }
1119
- if (!uc && !ne) continue;
1120
- if (isNew) {
1121
- if (uc) blockers.push(`- [验收未对账] done intent 验收标准有未勾验项:${base}(逐条勾验并补证据:commit/用例/冒烟输出)`);
1122
- if (ne) blockers.push(`- [验收缺证据] ${base} 验收标准勾选项缺「证据:」标注——证据是闭环准确性的唯一机器事实`);
1123
- } else if (!ex) {
1124
- legacyUnaccounted++;
1125
- }
1126
- }
1127
- // 测试绿缺凭证出账(判据见 collector;⚠️ 文案锚点硬约束:既有 check-loop.test.mjs 锚定
1128
- // 「测试绿缺凭证」四字连续,doc 与修复命令只能追加在整句之后,不得插进四字中间):
1129
- // 当日首次命中的文档逐份点名(可操作明细);当日已点名的聚合成一条计数行。
1130
- if (verifyMissingDocs.size) {
1131
- const today = new Date().toISOString().slice(0, 10);
1132
- const statePath = path.join(os.tmpdir(), `agentic-flow-kit-check8-warn-${ROOT.replace(/[^A-Za-z0-9]/g, '-').slice(-60)}.json`);
1133
- let warnedToday = {};
1134
- try { warnedToday = JSON.parse(fs.readFileSync(statePath, 'utf8')); } catch { /* 无状态/坏状态 = 空集 → 全部点名 */ }
1135
- const silent = [];
1136
- for (const [rel, base] of verifyMissingDocs) {
1137
- if (warnedToday[rel] === today) silent.push({ rel, base });
1138
- else {
1139
- warnings.push(`- [WARN 测试绿缺凭证] ${base} 验收证据声明「测试绿」但 24h 内无 verify 凭证(verifications.jsonl${verifyDocBound ? `;本单须带 --doc 落账` : ''})——跑 node .agents/scripts/verify.mjs${verifyDocBound ? ` --doc ${rel}` : ''} 后重跑(advisory,灰度第一档)`);
1140
- }
1141
- }
1142
- if (silent.length) {
1143
- warnings.push(`- [WARN 测试绿缺凭证] 另有 ${silent.length} 份在飞文档同日已点名、去重静默(${silent.slice(0, 5).map((d) => d.base).join('、')}${silent.length > 5 ? '…' : ''})——修法同上:跑 node .agents/scripts/verify.mjs${verifyDocBound ? ' --doc <本单>' : ''} 后重跑(advisory,灰度第一档)`);
1144
- }
1145
- try {
1146
- // 只留当日命中(隔日自动失效,状态面自洁;本机各 ROOT 独立键,互不串扰)
1147
- const next = {};
1148
- for (const [rel] of verifyMissingDocs) next[rel] = today;
1149
- fs.writeFileSync(statePath, JSON.stringify(next));
1150
- } catch { /* 落状态失败不影响裁决与输出(fail-open,advisory 层不因状态面故障改行为面) */ }
1151
- }
1152
- if (legacyUnaccounted > 0) {
1153
- warnings.push(`- [WARN 验收对账存量] ${legacyUnaccounted} 个存量 done intent 验收标准未对账(生效日锚之前加入仓库,豁免 hard,不回填)`);
1154
- }
1155
- }
1156
- } // laneOn(8) 守卫闭合
1157
-
1158
- // --- 10. 级别 vs 迁移文件一致性 [warning](启发式:入口文档加入提交触及迁移 SQL/Migrations → 疑似判低;非 git 跳过)---
1159
- if (laneOn(10)) { // lane=hygiene
1160
- markGate('10', '级别 vs 迁移文件');
1161
- if (gitOut(['rev-parse', '--git-dir']) !== null) {
1162
- const log = gitOut(['log', '--diff-filter=A', '--format=@%H', '--name-only']);
1163
- if (log !== null) {
1164
- const addpath = new Map(); // 文件 → 首次加入 commit(新→旧序首遇)
1165
- const cfiles = new Map(); // commit → 文件清单
1166
- let cur = null;
1167
- for (const line of log.split('\n')) {
1168
- if (line.startsWith('@')) { cur = line.slice(1); cfiles.set(cur, []); continue; }
1169
- if (line.trim() && cur && !addpath.has(line.trim())) {
1170
- addpath.set(line.trim(), cur);
1171
- cfiles.get(cur).push(line.trim());
1172
- }
1173
- }
1174
- const docs = [...docFiles('intents'), ...docFiles('incidents')];
1175
- for (const doc of docs) {
1176
- const rel = path.relative(ROOT, doc).split(path.sep).join('/');
1177
- const lvl = fmGet(doc, '级别');
1178
- if (lvl !== 'L1' && lvl !== 'L2') continue;
1179
- const c = addpath.get(rel);
1180
- if (!c) continue;
1181
- const hits = (cfiles.get(c) || []).filter((f) => /(^|\/)docs\/scripts\/.*\.sql$/.test(f) || /(^|\/)Migrations\//.test(f));
1182
- if (hits.length) {
1183
- warnings.push(`- [WARN 级别疑似判低] ${path.basename(doc)} 级别 ${lvl} 但其加入提交触及迁移文件(混合改动应就高不就低,请复核级别):\n${hits.join('\n')}`);
1184
- }
1185
- }
1186
- }
1187
- }
1188
- } // laneOn(10) 守卫闭合
1189
-
1190
- // --- 14. 新 done 的 spec/plan 须有确认留痕:git 历史「状态: approved」 或 confirmations.jsonl 台账 approved 行 [warning](恒 advisory;非 git 跳过)---
1191
- if (laneOn(14)) { // lane=hard:确认留痕
1192
- markGate('14', '确认留痕(approved 快照)');
1193
- // 2026-10-08 papercuts-cleanup-batch 修 3:两跳确认同批提交时 git 历史不出现行首「状态: approved」曾误报,
1194
- // 而台账已证明两跳均走(2026-09-28-adopter-derivers 实证)——判据改 OR 并集(git 判据保留不弱化,
1195
- // 台账为第二通道;确认事件以台账为准)。台账伪造面由检查 15 指纹 hard 门把关,本修仅消 advisory 误报。
1196
- if (gitOut(['rev-parse', '--git-dir']) !== null && gitOut(['rev-parse', '-q', '--verify', 'HEAD']) !== null) {
1197
- // 台账 approved 文档集合:单次读取(坏行容忍跳过,与检查 15 同口径);缺失视为空集(git 判据仍守门)
1198
- const ledgerApproved = new Set();
1199
- try {
1200
- for (const e of readLedgerRows(ROOT)) {
1201
- if (typeof e.doc === 'string' && e.stage === 'approved') ledgerApproved.add(e.doc);
1202
- }
1203
- } catch { /* 台账不可读视为无 approved 行 */ }
1204
- for (const sub of ['specs', 'plans']) {
1205
- for (const doc of docFiles(sub)) {
1206
- if (fmGet(doc, '状态') !== 'done') continue;
1207
- const base = path.basename(doc);
1208
- let d = fmGet(doc, '日期') || fmGet(doc, '发现');
1209
- if (!d) d = /^\d{4}-\d{2}-\d{2}$/.test(base.slice(0, 10)) ? base.slice(0, 10) : '';
1210
- if (!/^\d{4}-\d{2}-\d{2}$/.test(d) || d < kitPolicy.check14Since) continue; // policy.mjs check14Since
1211
- const lines = linesOf(doc) || [];
1212
- if (lines.some((l) => l.includes('存量确认态豁免('))) continue; // 保留:服务对象随修 3 自然消失,退役条件=连续两版本周期零命中
1213
- const rel = path.relative(ROOT, doc).split(path.sep).join('/');
1214
- // 命中判据单源(stage-gates.approvedTraceHit,2026-09-30 confirm-gate-approved-history):
1215
- // 返回 ''=从未出现 / <sha>=命中 / null=git 调用失败(不报,沿本段 fail-open 口径)
1216
- const hit = approvedTraceHit(ROOT, rel);
1217
- if (hit !== null && hit === '' && !ledgerApproved.has(rel)) {
1218
- warnings.push(`- [WARN 确认态缺失] ${base} 状态已 done 但 git 历史中从未出现行首「状态: approved」——确认环节未留痕(draft 直跳 done)`);
1219
- }
1220
- }
1221
- }
1222
- }
1223
- } // laneOn(14) 守卫闭合
1224
-
1225
- // --- 15. 确认指纹对账 [hard-block](2026-09-26 confirm-gate-machine;2026-09-27 confirm-gate-delegated 两形态;
1226
- // 生效日锚 2026-09-28 改台账 ts——此前锚取自文档自报「日期/发现」,新档只要把日期写早即整段跳过判定,
1227
- // incident 2026-09-28-confirm-gate-effective-date-anchor 实证)---
1228
- if (laneOn(15)) { // lane=hard:指纹链
1229
- markGate('15', '确认指纹对账');
1230
- // 确认两形态(confirm-doc.mjs):TTY 亲手键入「可以」/ --delegated 对话委托代录(用户对话内明确放行后
1231
- // AI 代录,台账行如实记 source=chat-delegated + quote 原话,永不伪装 TTY)。intents/specs/plans 凡
1232
- // approved/done 须有 confirm-doc 产生的 frontmatter 确认指纹 + 台账(.agents/confirmations.jsonl)
1233
- // 配对行——配对判据 doc/stage/fingerprint 三键,与 source 无关。
1234
- // **生效日锚 = 台账 ts(2026-09-28 起)**:受管准入 = 该 doc 在台账中有合法跳转行(stage ∈ approved/done/
1235
- // fixed/closed/superseded/cancelled,append-only 取末次);无台账行 = 存量豁免(不追溯)。自报日期
1236
- // (日期/发现/文件名)不再参与门禁判定——它可被作者手填,把「门是否生效」的决定权交给被约束对象本身
1237
- // 是自举漏洞;台账行是「确认确实发生过」的唯一机器事实。docs 与 incidents 共用同一锚(原 incidents
1238
- // 独立生效日 2026-09-28 常量退役:台账起算日 = docs 生效日,两档等价)。
1239
- // 台账坏行容忍跳过(审计件,jsonl 追加式);frontmatter 存 16 位、台账存 64 位,按前 16 位配对。
1240
- {
1241
- const EFFECTIVE = kitPolicy.confirmDocsEffective;
1242
- // 取数走 ledger-loader 的**带来源行号视图**(2026-10-12 ledger-shard-write):主台账 + 分片
1243
- // `.agents/confirmations.d/*.jsonl`。分片里的行同样受链校验——否则 `--shard` 写入就等于给台账开了
1244
- // 一个防伪盲区(门禁看得见分片行、却不验它们的链)。
1245
- // **此处曾刻意不走 loader**(单源化时留的例外,因当时要物理行号对齐);引入分片后该理由已不成立
1246
- // ——单一行号跨来源无法定位,故改用带 rel 的定位。第二处例外仍是 check-ledger-invariant.mjs
1247
- // (它审的是**盘面字节**的 append-only 前缀不变量,不是台账语义,见该文件头部)。
1248
- const ledger = [];
1249
- const ledgerRefs = []; // 与 ledger 同下标:{rel, no}——断裂报文的定位来源
1250
- for (const e of readLedgerEntries(ROOT)) {
1251
- if (e.row === null) continue; // 坏行跳过(容错口径同前;它占物理行号但不入 ledger 下标)
1252
- ledger.push(e.row);
1253
- ledgerRefs.push({ rel: e.rel, no: e.no });
1254
- }
1255
- // 台账哈希链校验(2026-10-09 engine-quality-round2 D;2026-10-12 ledger-doc-chain 改链域;
1256
- // 写入侧=confirm-doc appendLedger,哈希单源 policy.ledgerChainHash——判定零复刻)。
1257
- // **链域已从「文件物理序」改为「按 doc 的逻辑序」**(锚后生效,理由与不追溯口径见 POLICIES v8):
1258
- // 原判据 ① prevHash = 前一带 hash 行(物理)的 hash;新判据 ① = **同行 doc** 最后一个带 hash 行的
1259
- // hash。两者都要求 ② hash 可重算一致。无 hash 行仍按「链段重启」处理。
1260
- // 并发 append / git 并集合并 / 分片归并这三种**正常协作**都会打断物理链——门禁若继续据此 hard 拦,
1261
- // 必然被 --no-verify 绕过,治理失效;而 doc 链对就地改行 / 删行 / 插行三类篡改的检出能力不变。
1262
- // **坏行口径(复核 P2-1 勘误,此前注释误称「与写入侧一致」)**:坏行被本解析整体剔除、不重置游标
1263
- // ——坏行后写入的链行(写入侧读末行遇坏行 prevHash='')验链必失配出账。这是**预期 fail-loud**
1264
- // (坏行本身即台账完整性事故,应人工查验),非口径一致场景。
1265
- // 断裂 = hard「台账链断裂」(只报首断**物理行号** + 影响行计数,不做逐行刷屏)——就地改/删中间行
1266
- // 必留痕迹;边界:整文件重写可重建链,不可机器防,兜底 = 台账自身 git 历史(check-ledger-invariant)。
1267
- // 历史行(v1.5.0 前,无 hash 字段)零回填零告警——向后兼容。
1268
- {
1269
- let prevHash = '';
1270
- let brokenAt = 0;
1271
- let brokenCount = 0;
1272
- // 链域分界(2026-10-12 ledger-doc-chain):doc 链锚存在且合法时,**按行分域**验链——
1273
- // 锚前行(ts < 锚)维持物理链口径(存量零变化);锚后行(ts ≥ 锚)按「同行 doc 的最后一个
1274
- // 带 hash 行」接续,并同样要求 hash 可重算一致。锚缺键(v1-v7)→ 全表走物理链(= 旧行为)。
1275
- // byDoc 对**两种域的行都更新**:锚后行需要接到锚前该 doc 的最后一行,跨域才能连续。
1276
- const docChainOn = ledgerDocChainActive(kitPolicy);
1277
- const docChainSince = docChainOn ? kitPolicy.ledgerDocChainSince : '';
1278
- const byDoc = new Map();
1279
- const prunedHashSet = prunedHashesOf(ROOT); // 特许修剪凭据(无 manifest 时为空集,零 IO 成本)
1280
- ledger.forEach((row, idx) => {
1281
- if (!row || typeof row.hash !== 'string') { prevHash = ''; return; } // 存量行/无链字段 → 链段重启
1282
- const { hash, prevHash: p, ...rest } = row;
1283
- const inDocChain = docChainOn && typeof row.ts === 'string' && row.ts >= docChainSince;
1284
- const expected = inDocChain ? (byDoc.get(row.doc) ?? '') : prevHash;
1285
- // 特许修剪链段重启(2026-10-12 ledger-prune-manifest):删掉某 doc 的链行后,其后继行仍带被删行
1286
- // 的 prevHash,而该行已不在表内 → 必然失配。本行的 prevHash 若出现在 manifest 声明的被删哈希里,
1287
- // 即视为**有凭据的合法重启点**而非篡改(凭据 = .agents/ledger-prune-manifest.json,入库可对质)。
1288
- const prunedRestart = (p ?? '') !== expected && prunedHashSet.has(p ?? '');
1289
- const ok = ((p ?? '') === expected || prunedRestart) && ledgerChainHash(rest, p ?? '') === hash;
1290
- if (!ok) {
1291
- if (!brokenAt) brokenAt = idx + 1; // 1-based 下标,供 ledgerRefs 定位
1292
- brokenCount++;
1293
- }
1294
- prevHash = hash;
1295
- if (typeof row.doc === 'string') byDoc.set(row.doc, hash);
1296
- });
1297
- if (brokenAt) {
1298
- // 定位用 ledgerRefs(来源 + 行号):跨来源后单一行号无法定位;坏行占位不计入 ledger 下标
1299
- const at = ledgerRefs[brokenAt - 1] || { rel: LEDGER_REL, no: brokenAt };
1300
- const domain = docChainOn ? '锚前物理链 / 锚后 doc 链' : '物理链';
1301
- blockers.push(`- [台账链断裂] 自 ${at.rel}:${at.no} 起哈希链校验失败(${domain},共 ${brokenCount} 行不一致——append-only 台账出现就地改/删痕迹;prevHash 接续或内容重算不符。整文件重写不可机器防,对质走台账自身 git 历史)`);
1302
- }
1303
- }
1304
- // scope 子项(2026-10-09 审查 A1 干净版):受管台账行须带**机器派生**的改动面 scope{files,sha256}。
1305
- // 背景:委托代录的授权凭据原是 `--delegated` 的用户原话——自由文本机器不可校验、AI 可零成本复用
1306
- // (本仓实测「可以」133 次、「确认」60 次,406 行里仅 6 行 tty),整条授权链源头不可核对。
1307
- // 干净版把分辨力从「一句说过的话」换成「机器实测的这 N 个文件」:写入侧 confirm-doc.machineScope
1308
- // 自动派生(被确认文档 + `git status --porcelain` 未提交改动集),AI 无输入面。
1309
- // 判定(scopeSince 生效**时刻**锚,缺键 v1-v6 整体跳过——存量行零新增告警、不追溯):
1310
- // ① 缺 scope → warning(灰度第一档:新机制先观察,升 hard 走后续 policyVersion 演进)
1311
- // ② scope 存在但按其 files 重算 sha256 不符 → hard-block(「改了 files 没改摘要」= 同一信任
1312
- // 边界内的手改痕迹;哈希链本已覆盖就地改,本项兜住「整文件重写重建链」后二次篡改的场景)
1313
- // 注:scope 证明的是「放行时盘面上哪些文件在动」,**不是**「这些改动语义正确」——后者由 fingerprint
1314
- // (文档内容绑定)+ commit diff(事后对质)承担。不越界宣称(沿本检查既有口径纪律)。
1315
- {
1316
- const since = loadKitPolicy(ROOT).scopeSince;
1317
- if (typeof since === 'string' && Number.isFinite(Date.parse(since))) {
1318
- const sinceT = Date.parse(since);
1319
- const missing = [];
1320
- const mismatched = [];
1321
- for (const row of ledger) {
1322
- if (!row || typeof row.ts !== 'string') continue;
1323
- const t = Date.parse(row.ts);
1324
- if (!Number.isFinite(t) || t < sinceT) continue; // 存量豁免(不追溯)
1325
- const name = row.doc || '(未知 doc)';
1326
- if (!row.scope) { missing.push(name); continue; }
1327
- if (!scopeMatches(row)) mismatched.push(name);
1328
- }
1329
- if (missing.length) {
1330
- warnings.push(`- [WARN 缺机器改动面] ${missing.length} 条受管台账行无 scope 字段(${missing.slice(0, 3).join('、')}${missing.length > 3 ? ' …' : ''})——confirm-doc 落账自动派生 scope;此形态多见于手工/旧脚本写的行,advisory 不阻断`);
1331
- }
1332
- if (mismatched.length) {
1333
- blockers.push(`- [台账 scope 失配] ${mismatched.length} 条受管台账行的 scope.sha256 与其 files 重算不符(${mismatched.slice(0, 3).join('、')}${mismatched.length > 3 ? ' …' : ''})——「改了 files 没同步摘要」,同一信任边界内的手改痕迹;对质走台账 git 历史`);
1334
- }
1335
- }
1336
- }
1337
- // incidents 侧覆盖(2026-09-27 gate-coverage):fixed/closed 为已确认态(open = 起草态不加门——
1338
- // maintain.md 创建即对话确认的既有口径)
1339
- // 放弃态覆盖(2026-09-27 closing-coverage):superseded/cancelled 入配对集——confirm-doc --to 是唯一
1340
- // 合法产生通道(cancelled 自 draft/approved/open/fixed;superseded 自 approved/done/fixed/closed),
1341
- // 此前手改 frontmatter 即出账的口子收死
1342
- const CONFIRMED_BY_SUB = {
1343
- intents: ['approved', 'done', 'superseded', 'cancelled'],
1344
- specs: ['approved', 'done', 'superseded', 'cancelled'],
1345
- plans: ['approved', 'done', 'superseded', 'cancelled'],
1346
- incidents: ['fixed', 'closed', 'superseded', 'cancelled'],
1347
- };
1348
- // 合法跳转 stage 集(台账行「确认确实发生过」的判据;revert-draft / revert-open 类回退注记行不算)
1349
- const VALID_STAGES = new Set(['approved', 'done', 'fixed', 'closed', 'superseded', 'cancelled']);
1350
- for (const [sub, confirmedSet] of Object.entries(CONFIRMED_BY_SUB)) {
1351
- for (const doc of docFiles(sub)) {
1352
- const st = fmGet(doc, '状态');
1353
- if (!confirmedSet.includes(st)) continue;
1354
- const base = path.basename(doc);
1355
- const rel = path.relative(ROOT, doc).split(path.sep).join('/');
1356
- // 受管准入 = 两条件取或(2026-09-28 改锚):
1357
- // ① 台账中有该 doc 的合法跳转行——「确认确实发生过」的机器事实;它独立于自报日期成立,
1358
- // 故堵死「确认过却把日期写早以逃掉对账」这条攻破路径(本 incident 的核心缺陷);
1359
- // ② 自报日期 ≥ 生效日——覆盖「新档完全没跑 confirm-doc」的漏网面(此类无台账行,
1360
- // 仅靠 ① 会被误判为存量豁免而静默放行)。
1361
- // 两条件皆不满足 = 存量豁免(生效日前既有、从未走确认门,不追溯)。
1362
- const docEntries = ledger.filter((e) => e && e.doc === rel && VALID_STAGES.has(e.stage));
1363
- const eff = sub === 'incidents' ? kitPolicy.confirmIncidentsEffective : EFFECTIVE;
1364
- let d = fmGet(doc, '日期') || fmGet(doc, '发现');
1365
- if (!d) d = /^\d{4}-\d{2}-\d{2}$/.test(base.slice(0, 10)) ? base.slice(0, 10) : '';
1366
- const dateManaged = /^\d{4}-\d{2}-\d{2}$/.test(d) && d >= eff;
1367
- if (!docEntries.length && !dateManaged) continue; // 存量豁免
1368
- const fp = fmGet(doc, '确认指纹');
1369
- const ok = !!fp && docEntries.some((e) => e.stage === st
1370
- && typeof e.fingerprint === 'string' && e.fingerprint.startsWith(fp));
1371
- if (!ok) {
1372
- blockers.push(`- [确认未对账] ${base} 状态 ${st} 无用户确认记录——AI 不得代确认,用户在终端跑 node .agents/scripts/confirm-doc.mjs ${rel} 后重试`);
1373
- }
1374
- // 内容绑定(2026-09-27 audit-gate-hardening;生效锚 2026-09-27 gate-hardening-p2-batch 自文档自报日期
1375
- // 改为台账 done 行 ts):done 文档当前内容须与台账 done 行确认时的内容一致——按 prev 复原跳转前文本
1376
- // 重算比对,防「确认后篡改」(改验收标准/正文均触发)。复原口径 = confirm-doc computeFingerprint 的
1377
- // 逆推:CRLF 归一 → frontmatter 首个「状态:」行保分隔符换值为台账 prev(双空格等非规范分隔符不误伤,
1378
- // 与前向按原行字面计算对称)→ 剔「确认指纹:」行。两条降级路径:台账行缺 prev(schema 演进前存量,
1379
- // 无以复原)→ warning 不拦;entry.ts 早于 2026-09-28(UTC 字符串比较——该次确认在旧关单顺序时代完成)→
1380
- // 豁免绑定(配对判定已过,3 份失配存量即此列)。关单编辑顺序新约定不变:confirm-doc 是最后一次写入,
1381
- // 此后修订走 superseded 或新 intent。
1382
- if (ok && ['done', 'closed', 'superseded', 'cancelled'].includes(st)) {
1383
- const doneEntries = ledger.filter((e) => e && e.doc === rel && e.stage === st && typeof e.fingerprint === 'string');
1384
- const entry = doneEntries[doneEntries.length - 1]; // append-only 台账,末次生效(重确认场景)
1385
- if (!entry || !entry.prev) {
1386
- warnings.push(`- [WARN 绑定降级] ${base} 台账 stage=${st} 行缺 prev 字段(schema 演进前行),内容绑定跳过——仅配对判定`);
1387
- } else if (!(typeof entry.ts === 'string' && entry.ts >= kitPolicy.bindingTs)) {
1388
- // 该 done 确认发生在生效锚前(旧关单顺序时代)——豁免内容绑定,配对判定照常
1389
- } else if (bindingSha256(linesOf(doc) || [], entry.prev) !== entry.fingerprint) {
1390
- blockers.push(`- [确认内容漂移] ${base} ${st} 后内容与确认台账不符——已关单文档不得直接改(关单编辑先于关单确认);确需修订走 superseded 或新 intent 引用`);
1391
- }
1392
- }
1393
- }
1394
- }
1395
- // 并录批次审计(2026-09-28 batch-ledger-audit 改判据;原 2026-09-27 confirm-gate-one-per-call 引入):
1396
- // **读调用事实,不猜时间戳模式**。判据 = 台账行按 `batch` 分组,组内 `of > 1` → warning「确认并录」。
1397
- // batch/seq/of 由 confirm-doc 在**写入时**记录(那才是「本次调用落了几份」确定已知的时刻);
1398
- // 旧判据「同 quote + 相邻 ts 差 < 2s」是拿两个间接信号反推该事实,已实证四类失效并**整段退役**:
1399
- // ① 假阳性:合规逐件调用复用同句(用户两次都说「可以」)→ 必然误报;
1400
- // ② 假阴性:并录时给每份换不同 quote → 零告警(判据的实际效果是引导伪装者改 quote);
1401
- // ③ 噪声不可消退:不按日期门豁免,退役前本仓 22 条 advisory 中 14 条为该告警,且文案自认「不可区分」;
1402
- // ④ 字段职责冲突:`quote` 同时当「对质凭据」与「并录指纹」——现归还单一职责,只记用户原话。
1403
- // 无 `batch` 字段的历史行(schema 演进前,本仓全部 67 行均无该字段)→ **静默跳过**,不降级出账、不回溯:
1404
- // 按 audit-gate-hardening P3 教训(「扫了只产生不可消除的 advisory 噪声,真漏点被淹没」),无判定依据
1405
- // 的行不该产出告警。VALID_STAGES 复用外层声明(复核 P2-3 更正:此前本块内另有一份同名声明遮蔽外层)。
1406
- {
1407
- const byBatch = new Map(); // batch → 该批的台账行(仅计合法跳转 stage)
1408
- for (const e of ledger) {
1409
- if (!e || !VALID_STAGES.has(e.stage)) continue;
1410
- if (typeof e.batch !== 'string' || !e.batch) continue; // 历史行无 batch → 无判定依据,跳过
1411
- if (!byBatch.has(e.batch)) byBatch.set(e.batch, []);
1412
- byBatch.get(e.batch).push(e);
1413
- }
1414
- for (const [b, rows] of byBatch) {
1415
- // 判据取组内**任一行** of>1(复核 P2-3 更正:原取 rows[0].of 使结论依赖行序——同批首行 of=1、
1416
- // 次行 of=2 会漏报。confirm-doc 对同批所有行写同一个 of=docs.length,故正常批次组内一致;
1417
- // 改用 some 消除该顺序脆弱性,并对 craft 出来的不一致批次按「最大值」报,方向偏严不偏松)
1418
- if (!rows.some((r) => typeof r.of === 'number' && r.of > 1)) continue;
1419
- // of > 1 = 一次调用落多份态。delegated 形态下这正是「并录」(入口已拒多份,此处抓历史/绕行);
1420
- // TTY 形态天然逐份过目(用户亲手键入),of>1 不构成违规——故只对 delegated 行报。
1421
- if (!rows.some((r) => r.source === 'chat-delegated')) continue;
1422
- // 协作道批量豁免(2026-09-30 hybrid-governance-risk-lanes):confirm-doc --batch 仅受理 L1
1423
- // (逐份读级别,L2/L3 逐份拒绝),台账行带 brief:true——全行带标记的批次是 sanctioned 泳道行为
1424
- // (异步审计兜底),不出「确认并录」;缺标记(旧版脚本/手造台账)照旧告警,判据偏严不偏松。
1425
- if (rows.every((r) => r.brief === true)) continue;
1426
- const of = Math.max(...rows.map((r) => (typeof r.of === 'number' ? r.of : 0)));
1427
- const docs = rows.map((r) => String(r.doc).replace(/^workflow\//, '')).join('、');
1428
- warnings.push(`- [WARN 确认并录] 单次调用落账 ${rows.length} 份(batch ${b},of=${of}):${docs}——同一次 --delegated 调用放行多份,塌掉「逐件确认」门(build.md;口径见根 AGENTS.md「门禁与提交」确认门节)`);
1429
- }
1430
- }
1431
- }
1432
- } // laneOn(15) 守卫闭合
1433
-
1434
- // --- 16. 量化断言指标签名对账 [warning](2026-09-28 claim-exceeds-fix;登记表单源 .agents/metric-claims.txt)---
1435
- if (laneOn(16)) { // lane=hygiene
1436
- markGate('16', '量化断言签名对账');
1437
- // 判据要点:活跃态文档(draft/approved/open)中的 `{{指标名}}`(小写点分)签名须替换为实时值,留签名=未回填=
1438
- // warning;只查显式签名、不全文扫数字(历史叙述假阳性恒 0);未登记签名 / 取数器缺失 → fail-loud 出账;
1439
- // 登记表缺失 → 静默跳过(未启用该检查的装户零噪声);装户自有指标走 .agents/metric-derivers.cjs(CJS 契约,
1440
- // 内置优先)。实现自 2026-09-28 check16-inline-debt 起迁出至 check-metric-claims.mjs(原内联块,判据语义/
1441
- // 消息文案/exit 语义零变化,迁出经全量输出 diff 基线验证)。ctx 显式携带本检查引用的外层符号
1442
- // (ROOT/ENUMS/docFiles/fmGet/inSet/isTracked/linesOf/readdirOrNull/warnings,以代码实际引用集为准);
1443
- // 调用位置须保持在检查 15 之后、输出段之前——warnings 按插入序输出,位置变化会改变输出行序。
1444
- runCheck16({ ROOT, ENUMS, docFiles, fmGet, inSet, isTracked, linesOf, readdirOrNull, warnings });
1445
- } // laneOn(16) 守卫闭合
1446
-
1447
- // --- 17. 发版提交树上仍未收口的 intent/spec/plan [hard-block] ---
1448
- if (laneOn(17)) { // lane=hard:发版收口
1449
- markGate('17', '发版树未收口文档');
1450
- // 最近一次 package.json version 发生变化的提交里,当时状态已是 draft 或 approved 的
1451
- // intent/spec/plan,被扫描的树上仍是 draft 或 approved 则阻断。
1452
- // 当时已是 draft:不看版本锚。当时已是 approved:只在发版版本大于
1453
- // policy.check17UnclosedAfter 时阻断。版本 1 没有该键,因此不启用后两格。
1454
- // 版本按主、次、修订三段整数比较。沿 package.json 的全部历史查找,不设次数上限。
1455
- // 该提交之后新建的文件不在范围内。open 的 incident 不在此列。
1456
- // 快径(2026-10-16 减重 自源仓回灌):当前树 package.json 无 version 字段(装户非 node 仓 / 快照树)
1457
- // → 整段跳过——无 version 则「version 变化的提交」永不存在,本段恒不触发,省去全历史 git log+show
1458
- // 扫描。适配点:源仓 s17 为独立模块函数用 return 快返;kit 单体函数内改 if 包裹,保后续段照常执行。
1459
- {
1460
- let curVer = null;
1461
- try { curVer = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')).version; } catch { curVer = null; }
1462
- if (curVer) {
1463
- const log = gitOut(['log', '--format=%H', '--', 'package.json']);
1464
- if (log) {
1465
- let release = null;
1466
- let releaseVer = '';
1467
- for (const sha of log.split('\n').map((s) => s.trim()).filter(Boolean)) {
1468
- const curTxt = gitOut(['show', `${sha}:package.json`]);
1469
- if (!curTxt) continue;
1470
- let cur = null;
1471
- try { cur = JSON.parse(curTxt).version; } catch { continue; }
1472
- const prevTxt = gitOut(['show', `${sha}^:package.json`]);
1473
- let prev = null;
1474
- if (prevTxt) { try { prev = JSON.parse(prevTxt).version; } catch { prev = null; } }
1475
- if (cur && cur !== prev) { release = sha; releaseVer = cur; break; }
1476
- }
1477
- const tree = release && gitOut(['ls-tree', '-r', '--name-only', release, '--', `${WF}/intents`, `${WF}/specs`, `${WF}/plans`]);
1478
- if (release && tree) {
1479
- for (const rel of tree.split('\n').map((s) => s.trim()).filter(Boolean)) {
1480
- if (!rel.endsWith('.md') || rel.endsWith('_TEMPLATE.md')) continue;
1481
- const thenTxt = gitOut(['show', `${release}:${rel}`]);
1482
- if (!thenTxt) continue;
1483
- const thenSt = fmStatus(thenTxt);
1484
- const nowSt = fmGet(path.join(ROOT, rel), '状态');
1485
- if ((thenSt !== 'draft' && thenSt !== 'approved') || (nowSt !== 'draft' && nowSt !== 'approved')) continue;
1486
- if (thenSt === 'approved' && !versionGreater(releaseVer, kitPolicy.check17UnclosedAfter)) continue;
1487
- const here = REV ? `提交 ${REV.slice(0, 7)}` : '工作区';
1488
- blockers.push(`- [发版草稿] ${rel} 在 version=${releaseVer} 的提交 ${release.slice(0, 7)} 上已是 ${thenSt},${here}仍是 ${nowSt}。发版提交树上未收口的 intent/spec/plan 须先离开 draft 与 approved。覆盖面只含该提交当时已在树上的 intent/spec/plan;其后新建的文件不在此列`);
1489
- }
1490
- }
1491
- }
1492
- }
1493
- }
1494
- } // laneOn(17) 守卫闭合
1495
-
1496
- // --- 18. 委派台账对账 [warning] ---
1497
- if (laneOn(18)) { // lane=hygiene
1498
- markGate('18', '委派台账对账');
1499
- // L2/L3 的 intent、spec、plan 状态为 done,或同级别 incident 状态为 fixed 或 closed 时,
1500
- // 「委派结果」表与「自做任务结果」表均没有日期不早于文档日期、且含该文件名(带/不带 .md 均匹配)的一行,则警告。
1501
- // 缺级别、缺日期、以及其他状态不警告。audit:false 时 warnings.push 已被换成空函数。
1502
- // 两表解析口径与 agg-delegations.cjs splitTables 保持一致,一边改另一边须跟。
1503
- // 分片感知(2026-10-13 ledger-shard-ledgers):delegationResultRows 走 ledger-shards.readDelegationsText
1504
- // 合并读(主台账 ∪ delegations.d/*.md),分片行与本表行同一对账口径,判据零改动。
1505
- {
1506
- const rows = delegationResultRows(path.join(ROOT, WF, 'delegations.md'));
1507
- for (const sub of ['intents', 'specs', 'plans', 'incidents']) {
1508
- for (const abs of docFiles(sub)) {
1509
- const lvl = fmGet(abs, '级别');
1510
- if (lvl !== 'L2' && lvl !== 'L3') continue;
1511
- const st = fmGet(abs, '状态');
1512
- const inScope = sub === 'incidents' ? (st === 'fixed' || st === 'closed') : st === 'done';
1513
- if (!inScope) continue;
1514
- const date = sub === 'incidents' ? (fmGet(abs, '发现') || fmGet(abs, '日期')) : fmGet(abs, '日期');
1515
- if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) continue;
1516
- // delegationSince 生效日豁免(policy v4,2026-10-06 loop-audit-remediation):锚前文档为存量回溯件
1517
- // ——台账记法约定(delegations.md 头部「任务一句话含文件名」)自生效日才立,存量不回填;缺键
1518
- // (v1-v3)→ 维持原全量对账行为(向后兼容,检查面不放松)
1519
- if (typeof kitPolicy.delegationSince === 'string' && date < kitPolicy.delegationSince) continue;
1520
- const base = path.basename(abs);
1521
- const stripped = base.replace(/\.md$/, '');
1522
- if (rows.some((r) => r.date >= date && (r.line.includes(base) || r.line.includes(stripped)))) continue;
1523
- const rel = path.relative(ROOT, abs).split(path.sep).join('/');
1524
- warnings.push(`- [WARN 委派台账] ${rel} 在 ${date} 及之后的委派结果/自做任务结果表中没有该文件名`);
1525
- }
1526
- }
1527
- }
1528
- } // laneOn(18) 守卫闭合
1529
-
1530
- // --- 19. 逐阶段审计 [warning](2026-09-30 stage-gate-machine;口径与 stage-gates.mjs / fill-* / confirm-doc 前置门互引) ---
1531
- if (laneOn(19)) { // lane=hygiene
1532
- markGate('19', '逐阶段审计');
1533
- // 判据 A(在途扫描):同名 spec/plan 为 draft 且其日期 ≥ stageGateSince 时——入口未确认(intent:状态非
1534
- // approved/done、或缺台账行且非存量;incident:「时间线」小节缺行首「用户确认」条目)→ warning;
1535
- // 入口缺合法「级别」→ warning(与起草门 fail-closed 同口径,2026-09-30 复核 P2-7);
1536
- // plan 另判(入口级别 L2/L3 且 spec 未确认或缺失)→ warning。
1537
- // 判据 B(台账顺序):同主题 {intents,specs,plans} 的 approved 行(每 doc 取最早)时间须非降序;仅对
1538
- // 组内最早 ts 日期 ≥ stageGateSince 的主题判定;含更早 ts 的主题整组跳过(历史豁免)。
1539
- // 协作道豁免(2026-09-30 hybrid-governance-risk-lanes):入口 intent 为 draft 且级别 L1 → 判据 A 静默
1540
- // (「先动手后确认」是泳道语义;approved/done 无台账行仍照报);判据 B 对入口 L1 的主题豁免顺序
1541
- // 倒置判定(入口文件缺失不豁免)。
1542
- // stageGateSince 缺键(policy v1)→ 本检查整体跳过;全部 warning、不 hard-block。
1543
- {
1544
- const since = kitPolicy.stageGateSince;
1545
- if (typeof since === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(since)) {
1546
- const ledgerRows = [];
1547
- {
1548
- for (const e of readLedgerRows(ROOT)) ledgerRows.push(e);
1549
- }
1550
- const hasRow = (rel) => ledgerRows.some((e) => e && e.doc === rel && (e.stage === 'approved' || e.stage === 'done'));
1551
- const docConfirmed = (rel, abs) => {
1552
- const st = fmGet(abs, '状态');
1553
- if (st !== 'approved' && st !== 'done') return { ok: false, legacy: false, why: `状态「${st || '缺失'}」` };
1554
- if (hasRow(rel)) return { ok: true, level: fmGet(abs, '级别'), legacy: false };
1555
- const d = fmGet(abs, '日期') || fmGet(abs, '发现');
1556
- const legacy = (linesOf(abs) || []).some((l) => /^流程: legacy/.test(l))
1557
- || (/^\d{4}-\d{2}-\d{2}$/.test(d) && d < kitPolicy.confirmDocsEffective);
1558
- if (legacy) return { ok: true, level: fmGet(abs, '级别'), legacy: true };
1559
- return { ok: false, legacy: false, why: '无确认台账行' };
1560
- };
1561
- // incident 留痕判定:**直接复用 stage-gates.mjs 的 MARK_RE**(第七轮复核 N3:此前此处内联复制
1562
- // 一份同口径字面量,两处靠注释人工同步、无测试钉住——改为单源复用,从结构上消除漂移可能)。
1563
- // 判据同源:「## 时间线」小节内、行首列表条目含「用户确认」(词边界见 MARK_RE)。
1564
- const incidentMarked19 = (lines) => {
1565
- let inTimeline = false;
1566
- for (const l of lines || []) {
1567
- if (/^##\s/.test(l)) { inTimeline = /^##\s*时间线/.test(l); continue; }
1568
- if (inTimeline && MARK_RE.test(l)) return true;
1569
- }
1570
- return false;
1571
- };
1572
- const entryConfirmed19 = (base) => {
1573
- const irel = `${WF}/intents/${base}.md`;
1574
- const iabs = path.join(ROOT, irel);
1575
- if (fs.existsSync(iabs)) {
1576
- const st19 = fmGet(iabs, '状态');
1577
- const lvl19 = fmGet(iabs, '级别');
1578
- const r = docConfirmed(irel, iabs);
1579
- const body = (linesOf(iabs) || []).join('\n');
1580
- const d19 = fmGet(iabs, '日期') || fmGet(iabs, '发现');
1581
- const storLegacy = /^流程: legacy/m.test(body) || (/^\d{4}-\d{2}-\d{2}$/.test(d19) && d19 < kitPolicy.confirmDocsEffective);
1582
- return { ...r, level: lvl19, risk: fmGet(iabs, 'risk_level'), date: d19, entryDraft: st19 === 'draft', storageLegacy: storLegacy };
1583
- }
1584
- const crel = `${WF}/incidents/${base}.md`;
1585
- const cabs = path.join(ROOT, crel);
1586
- if (fs.existsSync(cabs)) {
1587
- const st = fmGet(cabs, '状态');
1588
- if ((st === 'open' || st === 'fixed' || st === 'closed') && incidentMarked19(linesOf(cabs))) {
1589
- return { ok: true, level: fmGet(cabs, '级别'), legacy: false, storageLegacy: false };
1590
- }
1591
- return { ok: false, legacy: false, storageLegacy: false, why: 'incident 未见过目留痕(时间线条目缺失)' };
1592
- }
1593
- return { ok: false, legacy: false, storageLegacy: false, why: '无同名入口' };
1594
- };
1595
- for (const sub of ['specs', 'plans']) {
1596
- for (const abs of docFiles(sub)) {
1597
- if (fmGet(abs, '状态') !== 'draft') continue;
1598
- const base = path.basename(abs).replace(/\.md$/, '');
1599
- // 日期:frontmatter 优先,缺则回落文件名前缀(plan 无「日期」字段;沿检查 15 口径)
1600
- let d = fmGet(abs, '日期');
1601
- if (!/^\d{4}-\d{2}-\d{2}$/.test(d)) d = /^\d{4}-\d{2}-\d{2}$/.test(base.slice(0, 10)) ? base.slice(0, 10) : '';
1602
- if (!(/^\d{4}-\d{2}-\d{2}$/.test(d) && d >= since)) continue;
1603
- const rel = path.relative(ROOT, abs).split(path.sep).join('/');
1604
- const ent = entryConfirmed19(base);
1605
- if (!ent.ok) {
1606
- // 协作道异步审计豁免(2026-09-30 hybrid-governance-risk-lanes;2026-10-02 caliber-convergence
1607
- // 起单源 laneOfEntry·方案 C):入口 intent 仍为 draft 且泳道 low(级别 L1)→「先动手后
1608
- // 确认」是泳道语义,不告警;suspect(缺失/非法/分歧)不豁免;approved/done 却无台账行仍照报
1609
- // (防手改状态冒充确认,与交叉一致性口径同);incident 入口不豁免(过目留痕本就轻量)。
1610
- if (ent.entryDraft && laneOfEntry(ent.level, ent.risk, kitPolicy.riskLevelSince, ent.date) === 'low') continue;
1611
- warnings.push(`- [WARN 逐阶段] ${rel} 起草先于入口确认(${ent.why})`); continue;
1612
- }
1613
- // 库存量形态(标记 / 日期早于生效日)短路 level 校验与 spec 档(与起草门同口径,N1)
1614
- const storLegacy = ent.storageLegacy === true;
1615
- if (!storLegacy && !/^L[0-3]$/.test(ent.level)) { warnings.push(`- [WARN 逐阶段] ${rel} 入口缺合法「级别」字段(无法判定前置深度;与起草门 fail-closed 同口径,库存量形态除外)`); continue; }
1616
- if (sub === 'plans' && !storLegacy && (ent.level === 'L2' || ent.level === 'L3')) {
1617
- const srel = `${WF}/specs/${base}.md`;
1618
- const sabs = path.join(ROOT, srel);
1619
- const sp = fs.existsSync(sabs) ? docConfirmed(srel, sabs) : { ok: false, why: '缺同名 spec' };
1620
- if (!sp.ok) warnings.push(`- [WARN 逐阶段] ${rel} 起草先于 spec 确认(${sp.why})`);
1621
- }
1622
- }
1623
- }
1624
- const firstApproved = new Map(); // base -> { intents?, specs?, plans? } 最早 approved ts
1625
- for (const e of ledgerRows) {
1626
- if (!e || e.stage !== 'approved' || typeof e.doc !== 'string') continue;
1627
- const m = /^workflow\/(intents|specs|plans)\/(.+)\.md$/.exec(e.doc);
1628
- if (!m) continue;
1629
- const rec = firstApproved.get(m[2]) || {};
1630
- if (!rec[m[1]] && typeof e.ts === 'string' && /^\d{4}-\d{2}-\d{2}T/.test(e.ts)) rec[m[1]] = e.ts;
1631
- firstApproved.set(m[2], rec);
1632
- }
1633
- for (const [base, rec] of firstApproved) {
1634
- const seq = ['intents', 'specs', 'plans'].filter((k) => rec[k]);
1635
- if (seq.length < 2) continue;
1636
- // 协作道豁免(2026-09-30 hybrid-governance-risk-lanes):入口 L1 的审批顺序倒置(如 plan 先于
1637
- // intent approved——「动手后确认」)是异步审计泳道语义,非流程违规;入口文件缺失(纯台账历史行 /
1638
- // incident 侧)不豁免,维持既有判据。
1639
- // existsSync 守卫(2026-10-06-check19-entry-enoent):incident 闭环主题无同名 intent,「读空判级」
1640
- // 惯用法(缺文件→级别空→不豁免,判定面不变)在 fail-loud fs 读(2026-10-05-gitout-fail-open)下
1641
- // 每次推送响亮出账 N 条 ENOENT 噪声——守卫跳过读取,语义与上注释一致;同款先例 entryConfirmed19
1642
- // 与下方 spec 读取。
1643
- const iabsB = path.join(ROOT, WF, 'intents', `${base}.md`);
1644
- const ilvlB = fs.existsSync(iabsB) ? fmGet(iabsB, '级别') : '';
1645
- if (ilvlB === 'L1') continue;
1646
- const earliest = seq.map((k) => rec[k]).sort()[0];
1647
- if (!(earliest.slice(0, 10) >= since)) continue;
1648
- let ordered = true;
1649
- for (let i = 1; i < seq.length; i++) if (rec[seq[i]] < rec[seq[i - 1]]) ordered = false;
1650
- if (!ordered) warnings.push(`- [WARN 逐阶段] 台账审批顺序倒置:${base}(${seq.map((k) => `${k}=${rec[k].slice(0, 19)}`).join(' / ')})`);
1651
- }
1652
- }
1653
- }
1654
- } // laneOn(19) 守卫闭合
1655
-
1656
- // --- 加固门(仅 --hardening 启用;2026-09-30 hybrid-governance-explore-hardening)[hard-block] ---
1657
- // 探索泳道(experiment/* 分支 + intent frontmatter「阶段: exploring」标记;「状态: exploring」亦认——
1658
- // 非法状态本就会在检查 5 出账)允许「先动手后确认」快速 PoC;成果转正(合入 main)前必须完成加固:
1659
- // ① intent 状态离开 draft → approved/done(探索作废走显式放弃态 superseded/cancelled——留档即出列,
1660
- // 不加固:放弃态无代码应随行);
1661
- // ② 同名 plan 在场且状态收口(∈ doc.status.confirmed——本门是转正门槛,不是配对门);
1662
- // ③ 泳道 L2/L3(级别优先、缺失/非法回落 risk_level,与 stage-gates 起草门同款取法)另须同名 spec
1663
- // 在场且收口。
1664
- // 触发面:.githooks/pre-push 对 remote=refs/heads/main 的推送以 --hardening 运行本脚本(hard 失败即阻断
1665
- // push);手跑 `node check-loop.mjs --hardening` 可转正前预检。诚实边界:分支名不进 commit,扫描树无法
1666
- // 机械判定「曾在 experiment/* 上」——标记靠泳道纪律写入(intent 模板 / workflow README 口径),漏标记的
1667
- // 探索件不被本门覆盖;本门拦的是「已标记未收口」。
1668
- if (HARDENING) {
1669
- for (const intent of docFiles('intents')) {
1670
- if (fmGet(intent, '阶段') !== 'exploring' && fmGet(intent, '状态') !== 'exploring') continue;
1671
- const base = path.basename(intent);
1672
- const st = fmGet(intent, '状态');
1673
- if (st === 'superseded' || st === 'cancelled') continue; // 放弃态:探索作废留档,不加固
1674
- const lvl = fmGet(intent, '级别');
1675
- // 泳道单源(2026-10-02 caliber-convergence 方案 C):suspect(缺失/非法/分歧)按 high——L2/L3 另须 spec
1676
- const lane = laneOfEntry(lvl, fmGet(intent, 'risk_level'), kitPolicy.riskLevelSince, fmGet(intent, '日期'));
1677
- if (st !== 'approved' && st !== 'done') {
1678
- blockers.push(`- [加固未过] exploring 任务入 main 须先收口:${base} intent 状态仍为『${st || '缺失'}』——先确认至 approved/done 并补齐同名 spec+plan,或显式放弃(superseded/cancelled)`);
1679
- continue;
1680
- }
1681
- const planAbs = path.join(ROOT, WF, 'plans', base);
1682
- const planSt = fs.existsSync(planAbs) ? fmGet(planAbs, '状态') : '';
1683
- if (!fs.existsSync(planAbs)) {
1684
- blockers.push(`- [加固未过] exploring 任务入 main 缺同名 plan:${base}(应在 ${WF}/plans/ 下同名)`);
1685
- } else if (!stOkDoc(planSt)) {
1686
- blockers.push(`- [加固未过] exploring 任务入 main 的 plan 未收口:${base}(plan 状态『${planSt || '缺失'}』须为 approved/done)`);
1687
- }
1688
- // 泳道单源(2026-10-02 caliber-convergence 方案 C;复核 P1-1 修正):suspect(缺失/非法/分歧)与
1689
- // high 同样另须同名 spec——仅 low(级别 L1)免 spec,只增不松。
1690
- if (lane !== 'low') {
1691
- const specAbs = path.join(ROOT, WF, 'specs', base);
1692
- const specSt = fs.existsSync(specAbs) ? fmGet(specAbs, '状态') : '';
1693
- if (!fs.existsSync(specAbs)) {
1694
- blockers.push(`- [加固未过] exploring 任务入 main 缺同名 spec:${base}(级别 ${lvl}/risk ${fmGet(intent, 'risk_level') || '缺失'},应在 ${WF}/specs/ 下同名)`);
1695
- } else if (!stOkDoc(specSt)) {
1696
- blockers.push(`- [加固未过] exploring 任务入 main 的 spec 未收口:${base}(spec 状态『${specSt || '缺失'}』须为 approved/done)`);
1697
- }
1698
- }
1699
- }
1700
- }
1701
-
1702
- // --- 20. 引擎脚本测试覆盖 [warning](2026-10-01 gate-script-test-coverage;仅包源环境) ---
1703
- if (laneOn(20)) { // lane=hygiene
1704
- markGate('20', '引擎脚本测试覆盖');
1705
- // 包源开发纪律:templates/_agents/scripts/ 下每个非 *.test.mjs 引擎脚本须有同名兄弟 .test.mjs,
1706
- // 或在 .agents/scripts-test-exempt.txt 登记豁免(managed 下发)。装户(无 templates/)整体跳过。
1707
- {
1708
- const scriptsDir = path.join(ROOT, 'templates', '_agents', 'scripts');
1709
- if (fs.existsSync(scriptsDir)) {
1710
- const exemptFile = path.join(ROOT, '.agents', 'scripts-test-exempt.txt');
1711
- const exempt = fs.existsSync(exemptFile)
1712
- ? fs.readFileSync(exemptFile, 'utf8').split(/\r?\n/)
1713
- .map((l) => l.trim())
1714
- .filter((l) => l && !l.startsWith('#'))
1715
- .map((l) => l.split('|')[0].trim())
1716
- .filter(Boolean)
1717
- : [];
1718
- const orphans = fs.readdirSync(scriptsDir)
1719
- .filter((f) => f.endsWith('.mjs') && !f.endsWith('.test.mjs') && !exempt.includes(f))
1720
- .filter((f) => !fs.existsSync(path.join(scriptsDir, f.replace(/\.mjs$/, '.test.mjs'))));
1721
- for (const f of orphans.sort()) {
1722
- warnings.push(`- [WARN 脚本测试缺失] ${f} 缺同名 .test.mjs——新增引擎脚本默认必须带测试;库件/工具可在 .agents/scripts-test-exempt.txt 登记豁免`);
1723
- }
1724
- }
1725
- }
1726
- } // laneOn(20) 守卫闭合
1727
-
1728
- // --- §21–§26 六段检查(2026-10-13 B6b-2 自源仓 s21–s26 回灌;段序沿源仓 SECTIONS 21→26,接在 §20 后)---
1729
- // ctx 只传既有共享面(与 check-hygiene / check-stage-index 的 ctx 同纪律:判定语义单源在段模块内,
1730
- // helper 单源在本文件——复刻即造口径分叉)。段体直接 push 进共享 warnings/blockers(不返回数组,
1731
- // check-16 先例),故 markGate 记账走共享收集器、增量天然正确(无需 appendSegs 中转)。
1732
- // 各段判据与适配清单见各模块文件头注。
1733
- const sharedCtx = { ROOT, WF, DOC_DIRS, ENUMS, inSet, docFiles, fmGet, linesOf, isTracked, readdirOrNull, addedDateOf, kitPolicy, warnings, blockers };
1734
- if (laneOn(21)) { markGate('21', 'spec 验证落地核查'); runSpecVerif(sharedCtx); } // lane=hygiene(锚 specVerifSince)
1735
- if (laneOn(22)) { markGate('22', '机制使用量台账'); runRegistry(sharedCtx); } // lane=hygiene(mechanism-registry 在场才启用)
1736
- if (laneOn(23)) { markGate('23', '判据级收敛对账'); runConvergence(sharedCtx); } // lane=hard(hard 档随 convergenceHardSince)
1737
- if (laneOn(24)) { markGate('24', 'incident 归因字段'); runAttribution(sharedCtx); } // lane=hygiene(锚 attributionSince)
1738
- if (laneOn(25)) { markGate('25', '路由预判一致性'); runPrejudgment(sharedCtx); } // lane=hard(内容纯 WARN 不阻断)
1739
- if (laneOn(26)) { markGate('26', '闭环漏斗协议前占比'); runFunnel(sharedCtx); } // lane=hygiene(metrics.md 在场才启用)
1740
-
1741
- // --- 输出(banner 沿 sh 版字样与格式 = 稳定输出契约:banner 后空行、条目 '- ' 前缀)---
1742
- // 门禁 ROI 收口(2026-10-08 gate-roi-metrics):末段结算(末段之后无下次 gateSeg 调用)+ 可选落盘。
1743
- // ⚠️ 结算在输出**之前**:否则检查 20 之后的段不计入。落盘只在 --gate-stats 时发生。
1744
- if (opts.gateStats) writeGateStats(ROOT, finishSegs(gateStats));
1745
- // --- 判定流水落账(2026-10-11 judgment-ledger,灰度消费端数据底座)---
1746
- // 每次真实运行追加一行 per-rule 判定计数到 .agents/judgments.jsonl(本地 gitignore;fixture 经
1747
- // CHECK_LOOP_ROOT 守卫自动跳过)——mechanism-registry 月度对账与 advisory→hard 升格判定的数据源
1748
- // 由「人工 grep 输出」升级为 agg-judgments.mjs 查账。fail-open:落账失败不改变门禁裁决与输出契约。
1749
- // mode 随分道传真实运行面(2026-10-13 B6b-1:hard/hygiene/all——原 'all' 硬编码随分道退役)。
1750
- recordRun({ root: ROOT, mode: LOOP_MODE, blockers, warnings });
1751
- if (blockers.length) {
1752
- process.stderr.write(`闭环骨架断档(check-loop.sh)— HARD-BLOCK:\n\n${blockers.join('\n')}\n\n`);
1753
- if (warnings.length) process.stderr.write(`WARN(advisory,不阻断):\n\n${warnings.join('\n')}\n`);
1754
- return { exitCode: 1, blockers, warnings };
1755
- }
1756
- if (warnings.length) {
1757
- process.stderr.write(`check-loop.sh WARN(advisory,不阻断):\n\n${warnings.join('\n')}\n`);
1758
- }
1759
- return { exitCode: 0, blockers, warnings };
1760
- }
1761
-
1762
- // ---- CLI 入口(isMain 守卫)——takeOpts 的用法错误仍 process.exit(1)(CLI 专属路径)----
1763
- const isMain = process.argv[1] && process.argv[1].replace(/\\/g, '/').endsWith('check-loop.mjs');
1764
- if (isMain) process.exit(runCheckLoop(takeOpts()).exitCode);
1765
-
1766
- export function delegationResultRows(file) {
1767
- // 分片感知读(2026-10-13 ledger-shard-ledgers):主台账 ∪ delegations.d/*.md,单源 = ledger-shards。
1768
- // file 为显式注入路径时只读该文件(测试语义不变);传默认主台账路径 → 走分片合并。
1769
- const text = readDelegationsText(path.dirname(path.dirname(file)), file);
1770
- const lines = text.split(/\r?\n/);
1771
- // 两表识别与 agg-delegations.cjs splitTables 表头签名同口径(一边改另一边须跟,2026-10-08 papercuts-cleanup-batch 修 2):
1772
- // 委派表头=含「被委派方」列;自做表头=首列「日期」且含「任务一句话」列——节标题只服务人类阅读,
1773
- // 表头才是数据边界(节标题漂移不再静默停解析);「##」节边界仍作收集终止符(表不跨节)。
1774
- let inTable = false;
1775
- const rows = [];
1776
- for (const line of lines) {
1777
- if (/^##\s+/.test(line)) { inTable = false; continue; }
1778
- if (!/^\s*\|/.test(line)) continue;
1779
- const cells = line.trim().replace(/^\|/, '').replace(/\|$/, '').split('|').map((c) => c.trim());
1780
- if (!cells.length || cells.every((c) => /^[-: ]*$/.test(c))) continue;
1781
- if (cells.some((c) => c.startsWith('被委派方')) || (cells[0] === '日期' && cells.some((c) => c.startsWith('任务一句话')))) {
1782
- inTable = true;
1783
- continue;
1784
- }
1785
- if (!inTable || !/^\d{4}-\d{2}-\d{2}$/.test(cells[0])) continue;
1786
- rows.push({ date: cells[0], line });
1787
- }
1788
- return rows;
1789
- }
1790
-
1791
- export function versionGreater(a, b) {
1792
- const parse = (v) => {
1793
- const m = /^(\d+)\.(\d+)\.(\d+)$/.exec(String(v ?? ''));
1794
- return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;
1795
- };
1796
- const x = parse(a);
1797
- const y = parse(b);
1798
- if (!x || !y) return false;
1799
- for (let i = 0; i < 3; i++) {
1800
- if (x[i] !== y[i]) return x[i] > y[i];
1801
- }
1802
- return false;
1803
- }
1804
-
1805
- export function fmStatus(text) {
1806
- const lines = String(text || '').split(/\r?\n/);
1807
- if (!/^---\s*$/.test(lines[0] || '')) return '';
1808
- for (let i = 1; i < lines.length; i++) {
1809
- if (/^---\s*$/.test(lines[i])) return '';
1810
- if (lines[i].startsWith('状态:')) return lines[i].slice('状态:'.length).trim();
1811
- }
1812
- return '';
1813
- }
1814
-
1815
- // bindingSha256:done 内容绑定的复原重算(检查 15 专用)——confirm-doc.mjs computeFingerprint 的逆推:
1816
- // lines 已 CRLF 归一(split(/\r?\n/)),frontmatter 区内首个「状态:」行保分隔符换值为 prev(`状态: done`
1817
- // 双空格 → `状态: approved`——与前向按原行字面计算对称,非规范分隔符不误伤;行尾空白等更奇异格式仍会
1818
- // 失配,触发前提本身已违反「确认落态唯一入口」约定,接受),全文剔「确认指纹:」行后 join('\n') 再 sha256。
1819
- // parseAddedDatesLog:git log(--diff-filter=A --format=@%aI --name-only)文本 → Map(rel → 加入 ISO 时间)。
1820
- // 新→旧序首遇 = 最新一次加入(复核 P2-1 勘误:旧注释「最早」系误述——行为原样零复刻,检查 8 isNew 取最新加入日期更保守)。
1821
- export function parseAddedDatesLog(logText) {
1822
- const m = new Map();
1823
- let cur = null;
1824
- for (const line of logText.split('\n')) {
1825
- if (line.startsWith('@')) { cur = line.slice(1); continue; }
1826
- if (line.trim() && cur && !m.has(line.trim())) m.set(line.trim(), cur);
1827
- }
1828
- return m;
1829
- }
1830
-
1831
- // addedDatesWithCache:addedDates 的持久缓存层(2026-10-09 engine-quality-round3 W1)。
1832
- // 键 = HEAD sha(同 commit 祖先不可变 → log 幂等;rebase 必改 HEAD 必重算;复核 P2-4:shallow→unshallow 同 HEAD 可见性增长有陈旧窗口——后果退化为旧行为 addedDateOf 返回 "",HEAD 变化自愈);
1833
- // 缓存位于 .agents/cache/(gitignored 运行态);读/写任一失败 fail-open 回退全算(门禁不失效);
1834
- // head 缺省(detached --rev worktree 等场景)→ 不读写缓存直接全算(语义不变)。
1835
- export function addedDatesWithCache({ head, gitLog, cachePath }) {
1836
- if (head) {
1837
- try {
1838
- const c = JSON.parse(fs.readFileSync(cachePath, 'utf8'));
1839
- if (c && c.head === head && c.map && Object.keys(c.map).length) return new Map(Object.entries(c.map));
1840
- } catch { /* 缓存缺失/损坏 → 全算 */ }
1841
- }
1842
- const log = gitLog();
1843
- if (log === null) return null;
1844
- const m = parseAddedDatesLog(log);
1845
- if (head) {
1846
- try {
1847
- fs.mkdirSync(path.dirname(cachePath), { recursive: true });
1848
- const tmp = cachePath + '.tmp';
1849
- fs.writeFileSync(tmp, JSON.stringify({ head, map: Object.fromEntries(m), savedAt: new Date().toISOString() }) + '\n');
1850
- fs.renameSync(tmp, cachePath);
1851
- } catch { /* 写失败 fail-open:本轮已用全算结果,缓存留待下次 */ }
1852
- }
1853
- return m;
1854
- }
1855
-
1856
- export function bindingSha256(lines, prevStatus) {
1857
- const isDelim = (l) => /^---\s*$/.test(l);
1858
- const out = [];
1859
- let i = 0;
1860
- if (isDelim(lines[0] || '')) {
1861
- out.push(lines[0]);
1862
- let replaced = false;
1863
- for (i = 1; i < lines.length; i++) {
1864
- if (isDelim(lines[i])) { out.push(lines[i]); i++; break; }
1865
- if (!replaced && /^状态:/.test(lines[i])) {
1866
- out.push(lines[i].replace(/^(\s*状态:\s*)\S.*$/, `$1${prevStatus}`));
1867
- replaced = true;
1868
- } else out.push(lines[i]);
1869
- }
1870
- }
1871
- for (; i < lines.length; i++) out.push(lines[i]);
1872
- return createHash('sha256').update(out.filter((l) => !/^确认指纹:/.test(l)).join('\n'), 'utf8').digest('hex');
1873
- }
1874
-
1875
- function readdirOrNull(dir) {
1876
- try { return fs.readdirSync(dir); } catch { return null; }
1877
- }
1878
- function isDirectoryOrNull(p) {
1879
- try { return fs.statSync(p).isDirectory(); } catch { return false; }
1880
- }
1881
-
1882
- // 场景 ID 提取(2026-10-10 scenario-coverage,检查 8 场景覆盖子判据的 spec 侧单源):
1883
- // 认「## 验收场景」节内的场景声明——三级标题 `### S1 <名>` 或列表项 `- S1 <名>`,
1884
- // 提取 S<n> 形 ID(按出现序去重)。节外不认(防「## 功能行为」里偶然出现的 S1 干扰)。
1885
- // 无该节 / 无场景声明 → 空数组(调用方按「不适用」跳过,原判据零变化)。
1886
- // 独立 export 供单元测试直测(纯函数:只吃文件路径、只读)。
1887
- export function scenarioIdsOf(specPath) {
1888
- let lines;
1889
- try { lines = fs.readFileSync(specPath, 'utf8').split(/\r?\n/); } catch { return []; }
1890
- const ids = [];
1891
- let inSec = false;
1892
- for (const line of lines) {
1893
- if (/^\s*##\s+[^#]*验收场景/.test(line)) { inSec = true; continue; }
1894
- if (inSec && /^\s*##\s/.test(line)) break; // 下一二级标题 = 节末
1895
- if (!inSec) continue;
1896
- const m = line.match(/^\s*(?:###|-)\s*\**S(\d+)\b/i);
1897
- if (m && !ids.includes(`S${m[1]}`)) ids.push(`S${m[1]}`);
1898
- }
1899
- return ids;
1900
- }
1901
-
1902
- // THEN 断言抽取(2026-10-11 then-assertion,检查 8「场景无断言」子判据的 spec 侧单源):
1903
- // 输入 spec 全文,定位「## 验收场景」节(节定位正则与 scenarioIdsOf 同款——口径单源,改写法时两处同步),
1904
- // 按场景块分组(`### S1 <名>` 三级标题或 `- S1 <名>` 列表项,声明正则同 scenarioIdsOf),抽块内 THEN 断言行。
1905
- // 行匹配口径:剥缩进后以 `- THEN` 开头(模板规定形式);`THEN:` / `THEN `(无连字符)也认——
1906
- // 防「写了断言但少了 `- ` 前缀」的写法漂移把断言误判为空;只认行首 THEN,GIVEN/WHEN 行中段的
1907
- // "THEN" 字样不误抽。返回 Map<S-ID, string[]>(声明即建键,无 THEN = 空数组——空壳判定交给调用方);
1908
- // 节不存在 / 非字符串输入 → 空 Map(验收场景节本身可选,调用方零变化)。
1909
- // 独立 export 供单元测试直测(纯函数:只吃文本、无 IO)。
1910
- export function extractThenByScenario(text) {
1911
- const byScen = new Map();
1912
- if (typeof text !== 'string') return byScen; // 读取失败(调用方传 null)→ 空 Map,调用方按不可判定跳过
1913
- const lines = text.split(/\r?\n/);
1914
- let cur = null; // 当前场景块 ID(null = 尚未进入任何场景块,节头说明行不算断言)
1915
- let inSec = false;
1916
- for (const line of lines) {
1917
- if (/^\s*##\s+[^#]*验收场景/.test(line)) { inSec = true; continue; }
1918
- if (inSec && /^\s*##\s/.test(line)) break; // 下一二级标题 = 节末
1919
- if (!inSec) continue;
1920
- const decl = line.match(/^\s*(?:###|-)\s*\**S(\d+)\b/i);
1921
- if (decl) {
1922
- const id = `S${decl[1]}`;
1923
- if (!byScen.has(id)) byScen.set(id, []);
1924
- cur = id;
1925
- continue;
1926
- }
1927
- if (cur === null) continue;
1928
- const s = line.trim();
1929
- if (/^-\s*THEN\b/i.test(s) || /^THEN\b/i.test(s)) byScen.get(cur).push(s);
1930
- }
1931
- return byScen;
1932
- }
1933
-
1934
- // 节体非空判定(2026-10-10 sediment-tracking,检查 8 沉淀追踪子判据的「高价值」信号):
1935
- // 认 `## <标题前缀>` 节内**标题之后**存在非空非占位行(占位 = `<…>` 单行包揽 / HTML 注释 / 引用)。
1936
- // 只有光标题(如模板未填的 `## 影响面`)= 未沉淀价值,不出告警——防模板未填段被误判为高价值。
1937
- // 前缀匹配(startsWith):兼容「## 影响面」「## 影响面与边界」等变体写法。
1938
- // 独立 export 供单元测试直测(纯函数:只吃行数组、无 IO)。
1939
- export function sectionHasBody(lines, headingPrefix) {
1940
- let inSec = false;
1941
- for (const line of lines) {
1942
- if (/^\s*##\s/.test(line)) {
1943
- const t = line.replace(/^\s*##\s*/, '').trim();
1944
- inSec = t.startsWith(headingPrefix);
1945
- continue;
1946
- }
1947
- if (!inSec) continue;
1948
- const s = line.trim();
1949
- if (!s) continue;
1950
- if (/^<.*>$/.test(s) || s.startsWith('<!--') || s.startsWith('>')) continue; // 占位 / 注释 / 引用
1951
- return true;
1952
- }
1953
- return false;
1954
- }
1955
-
1956
- // 沉淀落点空壳判定(2026-10-11 landing-reality,「存在 ≠ 有效」的落点真实性一环):
1957
- // 落点文件可能是只有标题没有内容的空壳。满足任一即**非**空壳(有效沉淀):
1958
- // ① frontmatter 含「来源:」键(人工已登记来源 = 真实整理的机器信号;frontmatter 口径同 fmGet 受限子集);
1959
- // ② frontmatter / 标题行 / 占位行剔除后的非空正文 ≥ 3 行(占位口径逐字对齐 sectionHasBody:
1960
- // `<…>` 单行包揽 / HTML 注释 / 引用块)——标题行不算正文,防「只有标题」凑行数绕过。
1961
- // text = 落点文件全文;非字符串(调用方读取失败传 null)按空壳处理,调用方在告警文案注明读取失败。
1962
- // 独立 export 供单元测试直测(纯函数:只吃文本、无 IO)。
1963
- export function sedimentLandingIsShell(text) {
1964
- if (typeof text !== 'string') return true; // 读取失败 → 按空壳
1965
- const lines = text.split(/\r?\n/);
1966
- const isDelim = (l) => /^---\s*$/.test(l); // 同 fmGet:首行 --- 进入、下一 --- 闭合
1967
- let inFm = isDelim(lines[0] || '');
1968
- if (inFm) {
1969
- for (let i = 1; i < lines.length; i++) {
1970
- if (isDelim(lines[i])) break; // 下一 --- = frontmatter 闭合
1971
- if (lines[i].startsWith('来源:')) return false; // ① 有来源登记 = 有效
1972
- }
1973
- }
1974
- let body = 0;
1975
- for (let i = inFm ? 1 : 0; i < lines.length; i++) {
1976
- if (inFm) {
1977
- if (isDelim(lines[i])) inFm = false; // frontmatter 闭合,其后才开始数正文
1978
- continue;
1979
- }
1980
- const s = lines[i].trim();
1981
- if (!s) continue;
1982
- if (s.startsWith('#')) continue; // 标题行 = 结构不算正文(空壳 = 只有标题没有内容)
1983
- if (/^<.*>$/.test(s) || s.startsWith('<!--') || s.startsWith('>')) continue; // 占位 / 注释 / 引用(同 sectionHasBody)
1984
- if (++body >= 3) return false; // ② 非占位正文 ≥ 3 行 = 有效
1985
- }
1986
- return true;
1987
- }