agentic-flow-kit 1.7.15 → 1.8.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 (206) hide show
  1. package/README.md +50 -8
  2. package/modules/hosts/claude/commands/wf-build.md +1 -1
  3. package/modules/hosts/claude/commands/wf-design.md +5 -4
  4. package/modules/hosts/claude/commands/wf-maintain.md +1 -1
  5. package/modules/hosts/claude/commands/wf-new-task.md +47 -25
  6. package/modules/hosts/claude/commands/wf-plan.md +1 -1
  7. package/modules/hosts/claude/commands/wf-review.md +2 -2
  8. package/modules/hosts/claude/commands/wf-sync-hosts.md +7 -13
  9. package/modules/hosts/claude/commands/wf-test.md +2 -2
  10. package/modules/hosts/codex/commands/wf-build.md +1 -1
  11. package/modules/hosts/codex/commands/wf-design.md +5 -4
  12. package/modules/hosts/codex/commands/wf-maintain.md +1 -1
  13. package/modules/hosts/codex/commands/wf-new-task.md +47 -25
  14. package/modules/hosts/codex/commands/wf-plan.md +1 -1
  15. package/modules/hosts/codex/commands/wf-review.md +2 -2
  16. package/modules/hosts/codex/commands/wf-sync-hosts.md +7 -13
  17. package/modules/hosts/codex/commands/wf-test.md +2 -2
  18. package/modules/hosts/cursor/commands/wf-build.md +1 -1
  19. package/modules/hosts/cursor/commands/wf-design.md +5 -4
  20. package/modules/hosts/cursor/commands/wf-maintain.md +1 -1
  21. package/modules/hosts/cursor/commands/wf-new-task.md +47 -25
  22. package/modules/hosts/cursor/commands/wf-plan.md +1 -1
  23. package/modules/hosts/cursor/commands/wf-review.md +2 -2
  24. package/modules/hosts/cursor/commands/wf-sync-hosts.md +7 -13
  25. package/modules/hosts/cursor/commands/wf-test.md +2 -2
  26. package/modules/hosts/opencode/commands/wf-build.md +1 -1
  27. package/modules/hosts/opencode/commands/wf-design.md +5 -4
  28. package/modules/hosts/opencode/commands/wf-maintain.md +1 -1
  29. package/modules/hosts/opencode/commands/wf-new-task.md +47 -25
  30. package/modules/hosts/opencode/commands/wf-plan.md +1 -1
  31. package/modules/hosts/opencode/commands/wf-review.md +2 -2
  32. package/modules/hosts/opencode/commands/wf-sync-hosts.md +7 -13
  33. package/modules/hosts/opencode/commands/wf-test.md +2 -2
  34. package/modules/hosts/trae/commands/wf-build.md +1 -1
  35. package/modules/hosts/trae/commands/wf-design.md +5 -4
  36. package/modules/hosts/trae/commands/wf-maintain.md +1 -1
  37. package/modules/hosts/trae/commands/wf-new-task.md +47 -25
  38. package/modules/hosts/trae/commands/wf-plan.md +1 -1
  39. package/modules/hosts/trae/commands/wf-review.md +2 -2
  40. package/modules/hosts/trae/commands/wf-sync-hosts.md +7 -13
  41. package/modules/hosts/trae/commands/wf-test.md +2 -2
  42. package/package.json +1 -1
  43. package/src/cli.mjs +47 -4
  44. package/src/doctor.mjs +48 -3
  45. package/src/executor.mjs +262 -0
  46. package/src/executor.test.mjs +295 -0
  47. package/src/fresh-init.test.mjs +1 -1
  48. package/src/init.mjs +27 -3
  49. package/src/profiles.mjs +10 -3
  50. package/src/render.mjs +3 -3
  51. package/src/rule-budget.test.mjs +2 -2
  52. package/src/stack-profile.test.mjs +6 -0
  53. package/src/sync-hosts.mjs +37 -43
  54. package/src/sync-hosts.test.mjs +67 -56
  55. package/src/validate.mjs +6 -1
  56. package/src/validate.test.mjs +1 -1
  57. package/templates/.gitattributes +12 -1
  58. package/templates/AGENTS.md +3 -3
  59. package/templates/_agents/commands/build.md +1 -1
  60. package/templates/_agents/commands/design.md +5 -4
  61. package/templates/_agents/commands/maintain.md +1 -1
  62. package/templates/_agents/commands/new-task.md +47 -25
  63. package/templates/_agents/commands/plan.md +1 -1
  64. package/templates/_agents/commands/review.md +2 -2
  65. package/templates/_agents/commands/sync-hosts.md +7 -13
  66. package/templates/_agents/commands/test.md +2 -2
  67. package/templates/_agents/control-surfaces.txt +1 -1
  68. package/templates/_agents/engine-lock.json +334 -0
  69. package/templates/_agents/hooks/check-index-incremental.mjs +48 -0
  70. package/templates/_agents/hooks/check-pairing-incremental.mjs +66 -0
  71. package/templates/_agents/hooks/check-wiki-ledger.mjs +30 -0
  72. package/templates/_agents/lane-surfaces.txt +5 -2
  73. package/templates/_agents/level-hints.txt +30 -0
  74. package/templates/_agents/loop/papercut-debt/DESIGN.md +112 -0
  75. package/templates/_agents/mechanism-registry.md +27 -0
  76. package/templates/_agents/rule-budgets.txt +2 -2
  77. package/templates/_agents/scripts/agg-delegations.cjs +21 -3
  78. package/templates/_agents/scripts/agg-delegations.test.mjs +5 -3
  79. package/templates/_agents/scripts/agg-gate-stats.mjs +3 -3
  80. package/templates/_agents/scripts/agg-judgments.mjs +80 -0
  81. package/templates/_agents/scripts/agg-judgments.test.mjs +45 -0
  82. package/templates/_agents/scripts/archive-sweep.mjs +233 -0
  83. package/templates/_agents/scripts/archive-sweep.test.mjs +129 -0
  84. package/templates/_agents/scripts/check-attribution.mjs +37 -0
  85. package/templates/_agents/scripts/check-convergence.mjs +119 -0
  86. package/templates/_agents/scripts/check-engine-integrity.mjs +59 -127
  87. package/templates/_agents/scripts/check-engine-integrity.test.mjs +33 -45
  88. package/templates/_agents/scripts/check-funnel.mjs +56 -0
  89. package/templates/_agents/scripts/check-hygiene.mjs +5 -5
  90. package/templates/_agents/scripts/check-index-incremental.test.mjs +73 -0
  91. package/templates/_agents/scripts/check-lane-surface.mjs +74 -25
  92. package/templates/_agents/scripts/check-lane-surface.test.mjs +71 -5
  93. package/templates/_agents/scripts/check-ledger-invariant.mjs +427 -78
  94. package/templates/_agents/scripts/check-ledger-invariant.test.mjs +438 -4
  95. package/templates/_agents/scripts/check-loop-rev.test.mjs +13 -8
  96. package/templates/_agents/scripts/check-loop-unit.test.mjs +8 -0
  97. package/templates/_agents/scripts/check-loop.mjs +264 -75
  98. package/templates/_agents/scripts/check-loop.test.mjs +587 -61
  99. package/templates/_agents/scripts/check-metric-claims.mjs +4 -2
  100. package/templates/_agents/scripts/check-prejudgment.mjs +59 -0
  101. package/templates/_agents/scripts/check-registry.mjs +45 -0
  102. package/templates/_agents/scripts/check-scope.mjs +96 -0
  103. package/templates/_agents/scripts/check-scope.test.mjs +96 -0
  104. package/templates/_agents/scripts/check-scripts-syntax.mjs +61 -0
  105. package/templates/_agents/scripts/check-scripts-syntax.test.mjs +72 -0
  106. package/templates/_agents/scripts/check-spec-verif.mjs +47 -0
  107. package/templates/_agents/scripts/compact-ledgers.mjs +97 -0
  108. package/templates/_agents/scripts/compact-ledgers.test.mjs +162 -0
  109. package/templates/_agents/scripts/confirm-doc.mjs +136 -31
  110. package/templates/_agents/scripts/confirm-doc.test.mjs +180 -4
  111. package/templates/_agents/scripts/doctor.test.mjs +44 -1
  112. package/templates/_agents/scripts/edit-face-check.mjs +5 -3
  113. package/templates/_agents/scripts/edit-face-check.test.mjs +5 -4
  114. package/templates/_agents/scripts/fill-intent.mjs +7 -5
  115. package/templates/_agents/scripts/fill-intent.test.mjs +19 -1
  116. package/templates/_agents/scripts/fill-plan.mjs +10 -6
  117. package/templates/_agents/scripts/fill-plan.test.mjs +19 -3
  118. package/templates/_agents/scripts/fill-spec.mjs +6 -3
  119. package/templates/_agents/scripts/fill-spec.test.mjs +12 -4
  120. package/templates/_agents/scripts/fixture-scripts.mjs +153 -0
  121. package/templates/_agents/scripts/fixture-scripts.test.mjs +112 -0
  122. package/templates/_agents/scripts/gate-checklist.mjs +10 -9
  123. package/templates/_agents/scripts/gate-checklist.test.mjs +2 -11
  124. package/templates/_agents/scripts/gate-seg.mjs +1 -1
  125. package/templates/_agents/scripts/gen-effective-policy.mjs +107 -0
  126. package/templates/_agents/scripts/gen-effective-policy.test.mjs +100 -0
  127. package/templates/_agents/scripts/gen-verify-evidence.mjs +107 -0
  128. package/templates/_agents/scripts/gen-verify-evidence.test.mjs +84 -0
  129. package/templates/_agents/scripts/gen-workflow-dashboard.mjs +16 -14
  130. package/templates/_agents/scripts/gen-workflow-dashboard.test.mjs +2 -1
  131. package/templates/_agents/scripts/gen-workflow-metrics.mjs +12 -36
  132. package/templates/_agents/scripts/git-core.mjs +45 -0
  133. package/templates/_agents/scripts/git-merge-jsonl.mjs +63 -0
  134. package/templates/_agents/scripts/git-merge-jsonl.test.mjs +125 -0
  135. package/templates/_agents/scripts/judgment-ledger.mjs +65 -0
  136. package/templates/_agents/scripts/judgment-ledger.test.mjs +129 -0
  137. package/templates/_agents/scripts/kb-search.mjs +19 -4
  138. package/templates/_agents/scripts/kb-search.test.mjs +33 -0
  139. package/templates/_agents/scripts/lane-surface-audit.mjs +143 -0
  140. package/templates/_agents/scripts/lane-surface-audit.test.mjs +93 -0
  141. package/templates/_agents/scripts/ledger-doc-chain.test.mjs +166 -0
  142. package/templates/_agents/scripts/ledger-loader.mjs +108 -0
  143. package/templates/_agents/scripts/ledger-loader.test.mjs +131 -0
  144. package/templates/_agents/scripts/ledger-prune.mjs +96 -0
  145. package/templates/_agents/scripts/ledger-prune.test.mjs +120 -0
  146. package/templates/_agents/scripts/ledger-shards.mjs +307 -0
  147. package/templates/_agents/scripts/ledger-shards.test.mjs +339 -0
  148. package/templates/_agents/scripts/ledger-ts-monotonic.test.mjs +135 -0
  149. package/templates/_agents/scripts/level-criteria.mjs +231 -0
  150. package/templates/_agents/scripts/level-criteria.test.mjs +281 -0
  151. package/templates/_agents/scripts/papercut-debt-controller.mjs +141 -0
  152. package/templates/_agents/scripts/papercut-debt-controller.test.mjs +127 -0
  153. package/templates/_agents/scripts/papercut-debt-sensor.mjs +170 -0
  154. package/templates/_agents/scripts/papercut-debt-sensor.test.mjs +146 -0
  155. package/templates/_agents/scripts/pipeline-run.mjs +10 -24
  156. package/templates/_agents/scripts/pipeline-run.test.mjs +22 -42
  157. package/templates/_agents/scripts/policy.mjs +75 -0
  158. package/templates/_agents/scripts/resolve-merge-conflicts.mjs +110 -0
  159. package/templates/_agents/scripts/resolve-merge-conflicts.test.mjs +87 -0
  160. package/templates/_agents/scripts/rewrite-file.mjs +133 -0
  161. package/templates/_agents/scripts/rewrite-file.test.mjs +148 -0
  162. package/templates/_agents/scripts/rule-budget.mjs +83 -0
  163. package/templates/_agents/scripts/run-tests.mjs +99 -0
  164. package/templates/_agents/scripts/run-tests.test.mjs +105 -0
  165. package/templates/_agents/scripts/solidify-task.test.mjs +1 -1
  166. package/templates/_agents/scripts/stage-gates.mjs +38 -21
  167. package/templates/_agents/scripts/trust-mode.mjs +4 -4
  168. package/templates/_agents/scripts/trust-mode.test.mjs +1 -1
  169. package/templates/_agents/scripts/verify.mjs +135 -58
  170. package/templates/_agents/scripts/verify.test.mjs +156 -47
  171. package/templates/_agents/scripts/wf-journal.mjs +8 -4
  172. package/templates/_agents/scripts/wf-journal.test.mjs +1 -1
  173. package/templates/_agents/scripts/wiki-search.test.mjs +5 -6
  174. package/templates/_agents/scripts/workflow-board-server.test.mjs +2 -2
  175. package/templates/_agents/scripts/workflow-enums.test.mjs +14 -5
  176. package/templates/_agents/scripts/workflows-check.mjs +1 -1
  177. package/templates/_agents/scripts-test-exempt.txt +1 -0
  178. package/templates/_agents/skills/papercut-fix/SKILL.md +60 -0
  179. package/templates/_agents/skills/papercut-fix/references/response-template.md +81 -0
  180. package/templates/_agents/workflow-enums.txt +8 -1
  181. package/templates/_agents/workflows/pipeline-closing.md +4 -5
  182. package/templates/_githooks/pre-commit +109 -120
  183. package/templates/_githooks/pre-merge-commit +27 -23
  184. package/templates/_githooks/pre-push +7 -6
  185. package/templates/_github/workflows/kit-ci.yml +4 -3
  186. package/templates/workflow/README.md +23 -5
  187. package/templates/workflow/incidents/_TEMPLATE.md +4 -1
  188. package/templates/workflow/intents/_TEMPLATE.md +4 -2
  189. package/templates/workflow/papercuts.md +2 -0
  190. package/templates/workflow/plans/_TEMPLATE.md +10 -5
  191. package/templates/workflow/regression-checklist.md +1 -0
  192. package/templates/workflow/specs/_TEMPLATE.md +17 -1
  193. package/modules/hosts/claude/commands/wf-source-sync-check.md +0 -89
  194. package/modules/hosts/codex/commands/wf-source-sync-check.md +0 -89
  195. package/modules/hosts/cursor/commands/wf-source-sync-check.md +0 -89
  196. package/modules/hosts/opencode/commands/wf-source-sync-check.md +0 -89
  197. package/modules/hosts/trae/commands/wf-source-sync-check.md +0 -90
  198. package/templates/_agents/commands/source-sync-check.md +0 -103
  199. package/templates/_agents/hooks/check-pairing-incremental.sh +0 -43
  200. package/templates/_agents/hooks/check-wiki-ledger.sh +0 -18
  201. package/templates/_agents/scripts/check-ledger.mjs +0 -109
  202. package/templates/_agents/scripts/check-ledger.test.mjs +0 -199
  203. package/templates/_agents/scripts/rule-budget.sh +0 -74
  204. package/templates/_agents/scripts/source-sync-check.mjs +0 -156
  205. package/templates/_agents/scripts/source-sync-check.test.mjs +0 -286
  206. package/templates/_agents/workflows/source-sync-repair.md +0 -30
@@ -13,9 +13,19 @@
13
13
  // 违例输出到 stderr 并 exit 1;只剩警告时 exit 0。
14
14
  //
15
15
  // 检查项清单(编号/标题/severity 逐条沿 sh 版头部——gate-checklist 配对登记表按 id 消费,不得增删改号):
16
- // 1. 入口文档/spec/plan 同名配对(L1 必须有 plan;L2/L3 必须有 spec+plan;L0 协作道豁免 plan;
17
- // L0/L1 勾触达红线 → 「红线判低」hard——协作道不受理 STOP 级改动,就高不就低,
18
- // 2026-09-30 hybrid-governance-risk-lanes) [hard-block]
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]
19
29
  // 2. 模板字段占位符残留(YYYY-MM-DD / <主题> 等未替换;<主题> 与 .md 同行 = 命名约定描述,豁免) [warning]
20
30
  // 3. incidents 复盘三件套完整性 + 状态严格枚举 + 新 intent 回路(回路断档=hard,其他=warning)
21
31
  // 4. 引用有效性(文档/指令中引用的 .agents/ 路径必须存在;支持 fill-{a,b,c}.mjs 花括号展开与 fill-*.mjs 通配;
@@ -40,8 +50,7 @@
40
50
  // wiki 侧(wiki/INDEX.md + 看板 DATA)由 doctor §6b 经 gen-wiki-board --check 校验,不在此重复
41
51
  // (2026-10-10:wiki 生成区此前零机器校验,现与 workflow 侧对称为 doctor 单路);
42
52
  // 12. frontmatter「模块:」合法性(枚举非法 / 2026-09-22 起新建缺字段=warning;词表单源 .agents/workflow-modules.txt)
43
- // 13. 常驻面体积预算(超限=warning;判定单源 rule-budget.sh——经 sh 调用,
44
- // 无 sh 环境静默跳过:advisory 级且 pre-commit 侧在 git 钩子 sh 环境照常硬拦)
53
+ // 13. 常驻面体积预算(超限=warning;判定单源 rule-budget.mjs——node 直跑,恒可跑)
45
54
  // 14. 新 done 的 spec/plan 须在 git 历史里出现过 `状态: approved`(确认环节留痕,2026-09-22;恒 advisory 永不升级 hard)
46
55
  // 15. 确认指纹对账(2026-09-27 起:approved/done 须 confirm-doc.mjs 确认指纹+台账配对,缺=hard-block;
47
56
  // 两形态——TTY 亲手 / --delegated 对话委托代录,台账 source 如实区分,配对判据与 source 无关)
@@ -99,6 +108,23 @@
99
108
  // 代价是覆盖面依赖作者登记。签名收窄为小写点分形态——装户模板占位符走全大写 SCREAMING_CASE
100
109
  // (由 init 渲染替换,如构建/端口/项目名三类,不属本检查面)。未登记签名 / 取数器缺失 → fail-loud 出账
101
110
  // (静默会让「登记了却没查」不可见);登记表不存在 → 静默跳过(未启用该检查的装户不应被噪声打扰)。
111
+ // 21. spec 验证落地核查(L2/L3 done spec 且 git 建档日 ≥ specVerifSince,「测试用例/验证计划/验证方式」
112
+ // 节无测试文件/验证命令引用 = warning;存量豁免;锚键缺 → 整段跳过) [warning]
113
+ // 22. 机制使用量台账(.agents/mechanism-registry.md 在场才启用;数据行行列数≠7/状态非法/待退役缺
114
+ // 处置期限/表无数据行 = warning;纯 WARN 永不 hard) [warning]
115
+ // 23. 判据级收敛对账(L2/L3 done spec 锚后「验收判据」表逐判据×证据对账;advisory 档 convergenceSince
116
+ // 起证据无效 = warning,hard 档 convergenceHardSince 起路径不存在/命令不在全量门/无对应全绿行 =
117
+ // hard-block;人工+空证据合法;无判据表两档都 = warning;存量豁免) [hard-block]
118
+ // 24. incident 归因字段核查(发现日 ≥ attributionSince 的新建件「来源/影响环境」必填且值在
119
+ // incident.source.all / incident.env.all 枚举 = warning;legacy 回填件与存量豁免) [warning]
120
+ // 25. 路由预判一致性(frontmatter「预判: kind= level=」在场才检;类型不符 intents≡require/incidents≡fix、
121
+ // 级别与「级别」字段不符、词表/枚举非法 = warning,不阻断;缺字段零告警;内容纯 WARN,lane=hard
122
+ // 随源仓 SECTIONS) [advisory]
123
+ // 26. 闭环漏斗「协议前」占比动作阈值(workflow/metrics.md 漏斗表日历相邻两月协议前占比均 >30% =
124
+ // warning,要求一轮归因;收口=0 的月不判;单月波动不触发) [warning]
125
+ // 3x(编号沿源仓 3x 写法,非独立清单号——gate-checklist 按 `N.` 解析,本条不入其配对面). incident 防复发
126
+ // 验证证据门(fixed/closed 且 git 建档日 ≥ incidentRegrSince,正文无自动化用例/回归清单引用 =
127
+ // hard-block;存量豁免;锚键缺 → 整段跳过) [hard-block]
102
128
  //
103
129
  // 注:清单条目 5(状态字段+L3 复核)与 1(配对)在同一遍 intents/specs/plans 循环里实现(沿 sh 版代码结构);
104
130
  // 条目 6 的旧委派残留/钉死模型子项在「角色契约与 Adapter」代码段实现。
@@ -108,17 +134,22 @@
108
134
  // (并行会话未跟踪半成品不拦别人的 push;ls-tree 失败退化为全扫,门禁不失效)。
109
135
  // --rev <sha>:把该提交剥到 commit 后挂到临时 detached worktree,ROOT 改到那里再扫。
110
136
  // 原工作区的未提交改动不进入这次扫描。与 CHECK_LOOP_ROOT 同时出现则 exit 1。全 0 sha exit 1。
137
+ // --all | --hygiene:分道运行面(2026-10-13 B6b-1,机读单源 LANE_OF)——缺省只跑硬门,口径见头部「用法」。
111
138
  // 文档协议:机器字段一律由文件头 YAML frontmatter(受限子集:每行 `键: 值`)承载,本脚本只扫 frontmatter 取字段;
112
139
  // 叙述性字段(独立复核/复盘三件套/验收勾验)按正文行锚定。枚举单源 .agents/workflow-enums.txt
113
140
  // (缺文件/缺键 fail-loud exit 1;经 workflow-enums.mjs 读取,CRLF 天然容忍)。
114
141
  // 已确认状态: approved/done=已批或闭环; superseded/cancelled=放弃留档(仍算确认,不挡 push); incident: fixed/closed
115
- // 用法:node .agents/scripts/check-loop.mjs [--rev <sha>] [--hardening] (或经 check-loop.sh shim)
142
+ // 用法:node .agents/scripts/check-loop.mjs [--rev <sha>] [--all | --hygiene] [--hardening] [--gate-stats] (或经 check-loop.sh shim)
143
+ // 分道(2026-10-13 B6b-1,源仓 check-loop SECTIONS 同款口径):默认只跑硬门(配对/判低/指纹/证据/
144
+ // 发版未收口)——关单/pre-push 门;--hygiene 只跑卫生段(索引/宿主/词表/指标签名/委派/体积预算等
145
+ // WARN 面,不进关单——要看时另跑);--all 两段都跑(= 分道前的裸跑全量)。--all 与 --hygiene 同给
146
+ // 报用法错。每段判据零变化,lane 只决定段归属哪个运行面;机读单源 = 本文件 LANE_OF 表。
116
147
  // --hardening:追加「加固门」(experiment 泳道 exploring 任务入 main 的转正门槛,hard-block;
117
148
  // .githooks/pre-push 对 remote=refs/heads/main 的推送传入;不占 1-20 编号,gate-checklist 登记表
118
149
  // 按号配对面不变,门体说明见加固门段注释)
119
150
  // 测试:node templates/_agents/scripts/check-loop.test.mjs(fixture 注入 CHECK_LOOP_ROOT)
120
151
  // import 契约(2026-10-08 checkloop-importable):import { runCheckLoop, delegationResultRows, versionGreater, fmStatus, bindingSha256 }
121
- // ——零副作用;runCheckLoop({root?, rev?, hardening?}) 返回 { exitCode, blockers, warnings }(输出打印照旧,静默断言自行重定向 stderr)
152
+ // ——零副作用;runCheckLoop({root?, rev?, mode?, hardening?}) 返回 { exitCode, blockers, warnings }(输出打印照旧,静默断言自行重定向 stderr)
122
153
  import fs from 'node:fs';
123
154
  import os from 'node:os';
124
155
  import path from 'node:path';
@@ -126,8 +157,12 @@ import { spawnSync } from 'node:child_process';
126
157
  import { createHash } from 'node:crypto';
127
158
  import { loadEnums } from './workflow-enums.mjs';
128
159
  import { runCheck16 } from './check-metric-claims.mjs';
129
- import { auditEnabled, loadKitPolicy, hasFreshVerifyLine, ledgerChainHash, scopeMatches } from './policy.mjs';
160
+ import { auditEnabled, loadKitPolicy, hasFreshVerifyLine, ledgerChainHash, ledgerDocChainActive, scopeMatches } from './policy.mjs';
130
161
  import { laneOfEntry } from './stage-gates.mjs';
162
+ import { readLedgerRows, readLedgerEntries, LEDGER_REL } from './ledger-loader.mjs';
163
+ import { prunedHashes as prunedHashesOf } from './ledger-prune.mjs';
164
+ // 委派台账分片感知读(2026-10-13 ledger-shard-ledgers 回灌):主台账 ∪ delegations.d/*.md 文本单源。
165
+ import { readDelegationsText } from './ledger-shards.mjs';
131
166
  // MARK_RE:incident 留痕形态的单源(第七轮复核 N3——此前 check-loop 内联复制一份同口径字面量,
132
167
  // 两处靠注释与人工同步;改为复用 stage-gates.mjs 的导出,从结构上消除漂移可能)
133
168
  import { MARK_RE, approvedTraceHit } from './stage-gates.mjs';
@@ -137,36 +172,87 @@ import { MARK_RE, approvedTraceHit } from './stage-gates.mjs';
137
172
  import { runCheckHygiene } from './check-hygiene.mjs';
138
173
  // 检查 7 拆模块(2026-10-09 engine-quality-round2 A1):阶段索引同步迁 check-stage-index.mjs
139
174
  import { runCheckStageIndex } from './check-stage-index.mjs';
175
+ // 六段检查模块(2026-10-13 B6b-2,自 Shipyard.Material check-loop-sections s21–s26 回灌;出处沿革
176
+ // 留痕在包源仓 git 历史与 CHANGELOG)。模块形态 = 各文件 export run(ctx):判定语义单源在段内,
177
+ // ctx 只传本文件既有共享面(helper 零复刻);段体调 wall 位置即输出顺序位(稳定输出契约)。
178
+ import { run as runSpecVerif } from './check-spec-verif.mjs';
179
+ import { run as runRegistry } from './check-registry.mjs';
180
+ import { run as runConvergence } from './check-convergence.mjs';
181
+ import { run as runAttribution } from './check-attribution.mjs';
182
+ import { run as runPrejudgment } from './check-prejudgment.mjs';
183
+ import { run as runFunnel } from './check-funnel.mjs';
140
184
  import { gateSeg, finishSegs, makeCollector } from './gate-seg.mjs';
185
+ // 判定流水落账(2026-10-11 judgment-ledger):每次真实运行追加一行 per-rule 计数(观测面,fail-open)
186
+ import { recordRun } from './judgment-ledger.mjs';
141
187
 
142
188
  // CHECK_LOOP_GIT:测试注入钩子(指向不存在/不可执行路径可稳定触发 spawn 异常);未设置时与原行为逐字节一致(2026-10-05-gitout-fail-open)
143
189
  const GIT = process.env.CHECK_LOOP_GIT || (process.platform === 'win32' ? 'git.exe' : 'git');
144
190
 
191
+ // usage:用法错误统一出口(2026-10-13 分道随源仓 usage() 口径逐字对齐;行 1 追加 kit 自有旗标)。
192
+ // 未知参数 / --rev 缺值 / --all 与 --hygiene 同给 → 此处 exit 1(CLI 专属路径;runCheckLoop import 面
193
+ // 不经此,mode 由 opts.mode 直给)。
194
+ function usage() {
195
+ console.error('check-loop: 用法 node check-loop.mjs [--rev <sha>] [--all | --hygiene] [--hardening] [--gate-stats]');
196
+ console.error(' 默认只跑硬门(配对/判低/指纹/证据/发版未收口)。--hygiene 只跑卫生段。--all 两段都跑。');
197
+ process.exit(1);
198
+ }
145
199
  function takeOpts() {
146
200
  const args = process.argv.slice(2);
147
- const opts = { rev: null, hardening: false, gateStats: false };
201
+ const opts = { rev: null, mode: 'hard', hardening: false, gateStats: false };
148
202
  for (let i = 0; i < args.length; i++) {
149
203
  if (args[i] === '--rev') {
150
204
  opts.rev = args[++i] ?? '';
151
- if (!opts.rev) {
152
- console.error('check-loop: 用法 node check-loop.mjs [--rev <sha>] [--hardening] [--gate-stats]');
153
- process.exit(1);
154
- }
205
+ if (!opts.rev) usage();
206
+ } else if (args[i] === '--all') {
207
+ if (opts.mode === 'hygiene') usage(); // 互斥组合报用法错(源仓 takeOpts 同款)
208
+ opts.mode = 'all';
209
+ } else if (args[i] === '--hygiene') {
210
+ if (opts.mode === 'all') usage();
211
+ opts.mode = 'hygiene';
155
212
  } else if (args[i] === '--hardening') {
156
213
  opts.hardening = true; // 加固门(2026-09-30 hybrid-governance-explore-hardening):pre-push 对 main 目标传入
157
214
  } else if (args[i] === '--gate-stats') {
158
215
  opts.gateStats = true; // 门禁 ROI 落盘(2026-10-08 gate-roi-metrics):默认路径输出逐字节不变
159
- } else {
160
- console.error('check-loop: 用法 node check-loop.mjs [--rev <sha>] [--hardening] [--gate-stats]');
161
- process.exit(1);
162
- }
216
+ } else usage();
163
217
  }
164
218
  return opts;
165
219
  }
166
220
 
221
+ // ---- 分道 lane 表(2026-10-13 B6b-1,源仓 check-loop.mjs SECTIONS 同款语义;机读单源)----
222
+ // id = 段插桩 id(markGate / check-hygiene / check-stage-index / runCheck16 的 gateSeg 同名),
223
+ // 值 = 运行面。守卫只决定段跑不跑,段体判据零变化。清单 5(状态/L3 复核)在检查 1 循环内实现、
224
+ // 无独立段 id,随 '1' 同道(hard)。§21–26 与 '3x' 已随 B6b-2 落地登记(2026-10-13)。
225
+ const LANE_OF = {
226
+ 1: 'hard', // 清单 1+5:配对 + 状态确认 + L3 复核 + 红线判低
227
+ 2: 'hygiene', 9: 'hygiene', 11: 'hygiene', 12: 'hygiene', 13: 'hygiene', // check-hygiene.mjs 五段
228
+ 3: 'hard', // 复盘三件套 + 新 intent 回路
229
+ 4: 'hygiene', // 引用有效性
230
+ 5: 'hygiene', // 角色契约与宿主 Adapter(清单 6)
231
+ 6: 'hygiene', // 阶段索引同步(清单 7;check-stage-index.mjs)
232
+ 8: 'hard', // 验收标准对账
233
+ 10: 'hygiene', // 级别 vs 迁移文件
234
+ 14: 'hard', // 确认留痕(approved 快照)
235
+ 15: 'hard', // 确认指纹对账(指纹链)
236
+ 16: 'hygiene', // 量化断言签名对账
237
+ 17: 'hard', // 发版树未收口
238
+ 18: 'hygiene', // 委派台账对账
239
+ 19: 'hygiene', // 逐阶段审计
240
+ 20: 'hygiene', // 引擎脚本测试覆盖
241
+ // B6b-2 六段(2026-10-13 自源仓 SECTIONS 回灌;lane 沿源仓:21/22/24/26 hygiene,23/25 hard)
242
+ 21: 'hygiene', // spec 验证落地核查(§21;锚 specVerifSince)
243
+ 22: 'hygiene', // 机制使用量台账(§22;.agents/mechanism-registry.md 在场才启用)
244
+ 23: 'hard', // 判据级收敛对账(§23;hard 档随 convergenceHardSince,锚前 advisory WARN)
245
+ 24: 'hygiene', // incident 归因字段核查(§24;锚 attributionSince)
246
+ 25: 'hard', // 路由预判一致性(§25;内容纯 WARN 不阻断,lane=hard 随源仓 SECTIONS)
247
+ 26: 'hygiene', // 闭环漏斗「协议前」占比动作阈值(§26)
248
+ '3x': 'hard', // incident 防复发验证证据门(§3 扩展,编号沿源仓 3x 写法;锚 incidentRegrSince)
249
+ };
250
+
167
251
  // ---- runCheckLoop:门禁主流程可 import 化(2026-10-08 checkloop-importable;2026-10-04 isMain 行点名单独立项)----
168
- // import 本模块零副作用(isMain 主守卫,board-kb-p1 先例);opts = { root?, rev?, hardening? }——root 显式参数
169
- // 优先于 CHECK_LOOP_ROOT env 优先于 git toplevel(CLI 缺省行为逐字节不变);返回 { exitCode, blockers, warnings },
252
+ // import 本模块零副作用(isMain 主守卫,board-kb-p1 先例);opts = { root?, rev?, mode?, hardening? }——root 显式参数
253
+ // 优先于 CHECK_LOOP_ROOT env 优先于 git toplevel(CLI 缺省行为逐字节不变);mode = 运行面(2026-10-13 分道:
254
+ // 'hard'(缺省,关单/pre-push 面)| 'hygiene'(只卫生段)| 'all'(两段都跑=分道前裸跑全量);CLI 由 takeOpts
255
+ // 注入,import 面按需显式给——需要全量语义的消费方传 'all',勿依赖缺省);返回 { exitCode, blockers, warnings },
170
256
  // 输出打印照旧在本函数内(稳定输出契约:banner 后空行、条目 `- ` 前缀、HARD-BLOCK/WARN 两段式——消费者 .githooks/pre-push)。
171
257
  // opts.rev 的 worktree 清理挂 process.on('exit')——进程内多次调用累计监听器(测试场景 ≤3 次,可接受)。
172
258
  // ---- 门禁 ROI 插桩件已抽至 gate-seg.mjs(2026-10-08 gate-roi-metrics)----
@@ -195,6 +281,9 @@ export function writeGateStats(root, segs) {
195
281
  export function runCheckLoop(opts = {}) {
196
282
  const REV_ARG = opts.rev ?? null;
197
283
  const HARDENING = !!opts.hardening;
284
+ const LOOP_MODE = opts.mode || 'hard'; // 分道运行面(2026-10-13 B6b-1):hard(缺省)| hygiene | all
285
+ // laneOn(id):本运行面是否执行该段——all 全跑;hard/hygiene 只跑同名面(源仓 SECTIONS 过滤同款)。
286
+ const laneOn = (id) => LOOP_MODE === 'all' || LANE_OF[id] === LOOP_MODE;
198
287
  if (REV_ARG && (opts.root || process.env.CHECK_LOOP_ROOT)) {
199
288
  console.error('check-loop: --rev 不能同时使用 root 参数 / CHECK_LOOP_ROOT');
200
289
  return { exitCode: 1, blockers: [], warnings: [] };
@@ -378,6 +467,7 @@ export function runCheckLoop(opts = {}) {
378
467
  };
379
468
 
380
469
  // --- 1. intent/spec/plan 同名配对 + 状态确认 + L3 确认三件 + 风险泳道一致性 [hard-block] ---
470
+ if (laneOn(1)) { // lane=hard:默认关单/pre-push 面(清单 5 随本段循环实现,同 lane)
381
471
  markGate('1', '意图/spec/plan 配对');
382
472
  for (const intent of docFiles('intents')) {
383
473
  const base = path.basename(intent);
@@ -394,8 +484,8 @@ export function runCheckLoop(opts = {}) {
394
484
  blockers.push(`- [配对断裂] intent 缺 spec:${base}(应在 ${WF}/specs/ 下同名)`);
395
485
  }
396
486
  }
397
- // 协作道(L0)豁免 plan 配对——异步审计兜底(hybrid-governance-risk-lanes);L1 仍须 plan,L2/L3 须 spec+plan
398
- if (lvl !== 'L0' && !fs.existsSync(path.join(ROOT, WF, 'plans', base))) {
487
+ // plan 配对全级别强制(2026-10-13 L0 退役,自源仓收敛系列 1 回灌:原 L0 协作道豁免随级别退役删除;L2/L3 另须 spec)
488
+ if (!fs.existsSync(path.join(ROOT, WF, 'plans', base))) {
399
489
  blockers.push(`- [配对断裂] intent 缺 plan:${base}(应在 ${WF}/plans/ 下同名)`);
400
490
  }
401
491
  // 风险泳道一致性(2026-10-02 caliber-convergence 起单源 laneOfEntry·方案 C 分歧双严):非 high
@@ -429,6 +519,18 @@ export function runCheckLoop(opts = {}) {
429
519
  blockers.push(`- [L3 复核缺失] ${base} 必须记录新会话独立复核结论`);
430
520
  }
431
521
  }
522
+ // 独立复核上下文标识(2026-10-13 B6b-2 自源仓 s01 回灌,policy v12 reviewerSince advisory):
523
+ // 独立性声明须带可证伪基底——复核行落「复核上下文:<会话/子代理 id>」,使「主智能体自查冒充」
524
+ // 从遗漏升级为积极伪造。只扫有独立复核行的 spec;锚前存量豁免不回填;缺键(v1–v11)→ 本子检整体跳过。
525
+ if (kitPolicy.reviewerSince) {
526
+ const rvDate = fmGet(spec, '日期') || (/^\d{4}-\d{2}-\d{2}$/.test(base.slice(0, 10)) ? base.slice(0, 10) : '');
527
+ if (rvDate >= kitPolicy.reviewerSince) {
528
+ const rvLine = (linesOf(spec) || []).find((l) => /^- 独立复核:/.test(l));
529
+ if (rvLine && !/复核上下文:/.test(rvLine)) {
530
+ warnings.push(`- [WARN 复核上下文缺失] ${base} 独立复核行缺「复核上下文:<会话/子代理 id>」——独立性声明无可证伪基底(C2,reviewerSince ${kitPolicy.reviewerSince})`);
531
+ }
532
+ }
533
+ }
432
534
  }
433
535
 
434
536
  for (const plan of docFiles('plans')) {
@@ -436,13 +538,16 @@ export function runCheckLoop(opts = {}) {
436
538
  const st = fmGet(plan, '状态');
437
539
  const lvl = fmGet(plan, '级别');
438
540
  const hasEntry = fs.existsSync(path.join(ROOT, WF, 'intents', base)) || fs.existsSync(path.join(ROOT, WF, 'incidents', base));
439
- if (!hasEntry) blockers.push(`- [配对断裂] plan 缺 intent/incident:${base}(应在 ${WF}/intents/ 或 ${WF}/incidents/ 下同名)`);
541
+ // L1 plan 即入口(2026-10-13 B6b-2 自源仓 s01 回灌):级别恰好为 L1 的 plan 自己就是入口,无同名
542
+ // intent/incident 不拦。级别缺失或 L2/L3 仍要求入口(fail-closed)。已写的 intent 不论级别仍要求同名 plan。
543
+ if (lvl !== 'L1' && !hasEntry) blockers.push(`- [配对断裂] plan 缺 intent/incident:${base}(应在 ${WF}/intents/ 或 ${WF}/incidents/ 下同名)`);
440
544
  if (!stOkDoc(st)) {
441
545
  const msg = `${base}(frontmatter 状态键当前值:『${st || '缺失'}』)`;
442
546
  if (lvl === 'L3') blockers.push(`- [状态未确认] L3 plan 必须为 approved/done/superseded/cancelled:${msg}`);
443
547
  else warnings.push(`- [WARN 状态未确认] plan 必须为 approved/done/superseded/cancelled:${msg}`);
444
548
  }
445
549
  }
550
+ } // laneOn(1) 守卫闭合
446
551
 
447
552
  // --- 卫生类检查 2 / 9 / 11 / 12 / 13(2026-10-08 selfmeasure-and-modularize 拆出)---
448
553
  // ⚠️ 调用点位置即输出顺序位:原实现分处五处,逐条顺序 2 → 9 → 11 → 12 → 13,而 warnings 按插入序输出、
@@ -452,8 +557,11 @@ export function runCheckLoop(opts = {}) {
452
557
  // ctx 只传既有 helper、模块内零复刻:docFiles 的 tracked 过滤、fmGet 的 frontmatter 受限子集、
453
558
  // linesOf 的读异常响亮出账各自承载不可漂移语义,复刻即造口径分叉。audit:false 下 warnings.push 是
454
559
  // no-op,卫生项因此不出账(硬规则语义保持)。
455
- warnings.push(...runCheckHygiene({ root: ROOT, WF, DOC_DIRS, docFiles, linesOf, fmGet, isTracked, readdirOrNull, kitPolicy, gateStats }));
560
+ // 分道(2026-10-13):本调用是卫生段(2/9/11/12/13,lane=hygiene)唯一入口——硬门默认面整段跳过
561
+ // (连带省掉检查 11/13 的生成器子进程);--hygiene / --all 才执行。
562
+ if (laneOn(2)) warnings.push(...runCheckHygiene({ root: ROOT, WF, DOC_DIRS, docFiles, linesOf, fmGet, isTracked, readdirOrNull, kitPolicy, gateStats }));
456
563
  // --- 3. incidents 复盘三件套 + 状态严格枚举 + 新 intent 回路(回路断档 = hard)---
564
+ if (laneOn(3)) { // lane=hard
457
565
  markGate('3', 'incidents 复盘三件套');
458
566
  for (const inc of docFiles('incidents')) {
459
567
  const name = path.basename(inc);
@@ -467,7 +575,7 @@ export function runCheckLoop(opts = {}) {
467
575
 
468
576
  if (fmGet(inc, '流程') !== 'legacy') {
469
577
  if (!inSet(incLvl, ENUMS['level.all'])) {
470
- warnings.push(`- [WARN 级别缺失] ${name} 必须填写 L0/L1/L2/L3(配对检查已跳过——补级别后重跑本脚本校验配对)`);
578
+ warnings.push(`- [WARN 级别缺失] ${name} 必须填写 L1/L2/L3(配对检查已跳过——补级别后重跑本脚本校验配对)`);
471
579
  } else {
472
580
  if (['L1', 'L2', 'L3'].includes(incLvl) && !fs.existsSync(path.join(ROOT, WF, 'plans', name))) {
473
581
  blockers.push(`- [配对断裂] incident 缺 plan:${name}(应在 ${WF}/plans/ 下同名)`);
@@ -513,8 +621,10 @@ export function runCheckLoop(opts = {}) {
513
621
  else if (!fs.existsSync(path.join(ROOT, WF, ref))) blockers.push(`- [回路断档] ${name} 引用的 intent 不存在:${ref}`);
514
622
  }
515
623
  }
624
+ } // laneOn(3) 守卫闭合
516
625
 
517
626
  // --- 4. 引用有效性 [warning](.agents/ 路径须存在;skills 特例允许用户级 ~/.agents/skills)---
627
+ if (laneOn(4)) { // lane=hygiene
518
628
  markGate('4', '引用有效性');
519
629
  {
520
630
  // 引用可带 {a,b,c} 花括号展开(仓库通写法 `fill-{intent,spec,plan}.mjs`)或 `*` 通配(`fill-*.mjs`)——
@@ -577,8 +687,10 @@ export function runCheckLoop(opts = {}) {
577
687
  }
578
688
  }
579
689
  }
690
+ } // laneOn(4) 守卫闭合
580
691
 
581
692
  // --- 5. 子智能体角色契约 + 宿主 Adapter 一致性 + 旧委派残留 + 钉死模型 [warning] ---
693
+ if (laneOn(5)) { // lane=hygiene(清单 6:角色契约与 Adapter)
582
694
  markGate('5', '角色契约与宿主 Adapter');
583
695
  {
584
696
  const cmdFiles = () => (readdirOrNull(path.join(ROOT, '.agents', 'commands')) || [])
@@ -636,11 +748,12 @@ export function runCheckLoop(opts = {}) {
636
748
  }
637
749
  if (modelHits.length) warnings.push(`- [WARN 宿主耦合] 薄 Adapter 不应固定模型:\n${modelHits.join('\n')}`);
638
750
  }
751
+ } // laneOn(5) 守卫闭合
639
752
 
640
753
  // --- 6. 阶段索引同步 [warning](2026-10-09 engine-quality-round2 A1:实现迁 check-stage-index.mjs——
641
754
  // 先例 check-hygiene / check-metric-claims;段 id 沿 sh 版 '6',清单编号 7 与文案逐字不动;
642
755
  // 调用点位置即输出顺序契约)---
643
- warnings.push(...runCheckStageIndex({ root: ROOT, linesOf, gateStats }));
756
+ if (laneOn(6)) warnings.push(...runCheckStageIndex({ root: ROOT, linesOf, gateStats })); // lane=hygiene(清单 7)
644
757
 
645
758
  // --- 共享:文件「首次加入 git」的日期索引(2026-09-28 check8-git-anchor)---
646
759
  // 用途:检查 8 的生效日锚从**可手填的文件名前缀**(项目命名规范本身即 `YYYY-MM-DD-<主题>`,作者
@@ -775,7 +888,38 @@ export function runCheckLoop(opts = {}) {
775
888
  return { ok: true, type: 'sha' };
776
889
  }
777
890
 
891
+ // --- 3 扩展(§3x,编号沿源仓 3x 写法——gate-checklist 按 `N.` 解析,本段不入配对面).
892
+ // incident 防复发验证证据门 [hard-block](2026-10-13 B6b-2 自源仓 s03x 回灌;出处沿革留痕在包源仓
893
+ // git 历史与 CHANGELOG)。调用点位置 = 源仓 SECTIONS 段序(s03x 居卫生 4/5/6 之后、检查 8 之前),
894
+ // 亦为本段消费 addedDateOf 的前置依赖位(git 建档日锚单源定义于上)---
895
+ // incidents 模板「防复发验证」强制项的机器面:防复发验证必须落到自动化用例或回归清单条目,禁「只写已人工验证」。
896
+ // fixed/closed 且 git 建档日 ≥ incidentRegrSince(policy v9;v1–v8 缺键 → 整体跳过)的 incident,
897
+ // 正文无自动化用例 / 回归清单引用 → hard。判据 = 宽匹配正则(引擎 .test.mjs / 回归清单 / 冒烟 / 测试命令)
898
+ // ——门的是「落到可复跑的验证资产」,不是猜具体测试名;存量(< 锚)豁免(不可判定亦不拦——无判定依据不出 hard)。
899
+ // kit 适配(源仓→kit 逐条):证据正则剔除源仓实例路径面(backend/…Tests.cs、frontend/__tests__),
900
+ // kit 口径保留通用形态(.test.mjs / workflow/regression-checklist.md(kit 模板同款件)/ 测试与门命令)。
901
+ if (laneOn('3x')) { // lane=hard:防复发证据门
902
+ markGate('3x', 'incident 防复发验证证据门');
903
+ {
904
+ const regrAnchor = kitPolicy.incidentRegrSince;
905
+ if (regrAnchor) {
906
+ const REGR_EVIDENCE_RE = /\.test\.mjs|workflow\/regression-checklist\.md|regression-smoke|npm\s+test|dotnet\s+test|run-tests|verify\.mjs/;
907
+ for (const inc of docFiles('incidents')) {
908
+ const incSt = fmGet(inc, '状态');
909
+ if (!['fixed', 'closed'].includes(incSt)) continue;
910
+ const add = addedDateOf(inc);
911
+ if (!add || add < regrAnchor) continue; // 存量豁免(不可判定亦不拦——无判定依据不出 hard)
912
+ const lines = linesOf(inc) || [];
913
+ if (!lines.some((l) => REGR_EVIDENCE_RE.test(l))) {
914
+ blockers.push(`- [回归证据缺失] ${path.basename(inc)} 已 ${incSt} 但防复发验证未落自动化用例/回归清单引用(模板强制项,禁「已人工验证」)`);
915
+ }
916
+ }
917
+ }
918
+ }
919
+ } // laneOn('3x') 守卫闭合
920
+
778
921
  // --- 8. intent 验收标准对账(done 须逐条勾验并补证据;新建 hard,存量聚合 warning)---
922
+ if (laneOn(8)) { // lane=hard:验收对账
779
923
  markGate('8', '验收标准对账');
780
924
  // 生效日锚 2026-09-28 改「git 首次加入日期」(此前取文件名前 10 字符——命名规范强制的字段、
781
925
  // 写早零成本)。非 git → 不可判定 → 走存量口径(不误报 hard)。
@@ -805,16 +949,10 @@ export function runCheckLoop(opts = {}) {
805
949
  const doneTsOf = (() => {
806
950
  const map = new Map();
807
951
  try {
808
- const lp = path.join(ROOT, '.agents', 'confirmations.jsonl');
809
- if (fs.existsSync(lp)) {
810
- for (const line of fs.readFileSync(lp, 'utf8').split(/\r?\n/)) {
811
- if (!line.trim()) continue;
812
- try {
813
- const e = JSON.parse(line);
814
- // append-only 取末次 done 跳转(同一 doc 多次 done 取最后一条 ts)
815
- if (e && e.doc && ['done', 'closed'].includes(e.stage)) map.set(e.doc, e.ts || '');
816
- } catch { /* 坏行跳过(同检查 15 口径) */ }
817
- }
952
+ // 读法收敛 ledger-loader(2026-10-12 ledger-loader-p1):末次 done 跳转取自物理读序,
953
+ // loader 保持读序返回故「取末次」语义与逐处直读一致(分片按文件名序排在主台账之后=较新)
954
+ for (const e of readLedgerRows(ROOT)) {
955
+ if (e && e.doc && ['done', 'closed'].includes(e.stage)) map.set(e.doc, e.ts || '');
818
956
  }
819
957
  } catch { /* 台账不可读 → 无锚 → 全走全局布尔(fail-open,不误报 hard) */ }
820
958
  return map;
@@ -984,8 +1122,10 @@ export function runCheckLoop(opts = {}) {
984
1122
  warnings.push(`- [WARN 验收对账存量] ${legacyUnaccounted} 个存量 done intent 验收标准未对账(生效日锚之前加入仓库,豁免 hard,不回填)`);
985
1123
  }
986
1124
  }
1125
+ } // laneOn(8) 守卫闭合
987
1126
 
988
1127
  // --- 10. 级别 vs 迁移文件一致性 [warning](启发式:入口文档加入提交触及迁移 SQL/Migrations → 疑似判低;非 git 跳过)---
1128
+ if (laneOn(10)) { // lane=hygiene
989
1129
  markGate('10', '级别 vs 迁移文件');
990
1130
  if (gitOut(['rev-parse', '--git-dir']) !== null) {
991
1131
  const log = gitOut(['log', '--diff-filter=A', '--format=@%H', '--name-only']);
@@ -1014,8 +1154,10 @@ export function runCheckLoop(opts = {}) {
1014
1154
  }
1015
1155
  }
1016
1156
  }
1157
+ } // laneOn(10) 守卫闭合
1017
1158
 
1018
1159
  // --- 14. 新 done 的 spec/plan 须有确认留痕:git 历史「状态: approved」 或 confirmations.jsonl 台账 approved 行 [warning](恒 advisory;非 git 跳过)---
1160
+ if (laneOn(14)) { // lane=hard:确认留痕
1019
1161
  markGate('14', '确认留痕(approved 快照)');
1020
1162
  // 2026-10-08 papercuts-cleanup-batch 修 3:两跳确认同批提交时 git 历史不出现行首「状态: approved」曾误报,
1021
1163
  // 而台账已证明两跳均走(2026-09-28-adopter-derivers 实证)——判据改 OR 并集(git 判据保留不弱化,
@@ -1024,15 +1166,8 @@ export function runCheckLoop(opts = {}) {
1024
1166
  // 台账 approved 文档集合:单次读取(坏行容忍跳过,与检查 15 同口径);缺失视为空集(git 判据仍守门)
1025
1167
  const ledgerApproved = new Set();
1026
1168
  try {
1027
- const lp = path.join(ROOT, '.agents', 'confirmations.jsonl');
1028
- if (fs.existsSync(lp)) {
1029
- for (const line of fs.readFileSync(lp, 'utf8').split(/\r?\n/)) {
1030
- if (!line.trim()) continue;
1031
- try {
1032
- const e = JSON.parse(line);
1033
- if (e && typeof e.doc === 'string' && e.stage === 'approved') ledgerApproved.add(e.doc);
1034
- } catch { /* 坏行容忍跳过 */ }
1035
- }
1169
+ for (const e of readLedgerRows(ROOT)) {
1170
+ if (typeof e.doc === 'string' && e.stage === 'approved') ledgerApproved.add(e.doc);
1036
1171
  }
1037
1172
  } catch { /* 台账不可读视为无 approved 行 */ }
1038
1173
  for (const sub of ['specs', 'plans']) {
@@ -1054,10 +1189,12 @@ export function runCheckLoop(opts = {}) {
1054
1189
  }
1055
1190
  }
1056
1191
  }
1192
+ } // laneOn(14) 守卫闭合
1057
1193
 
1058
1194
  // --- 15. 确认指纹对账 [hard-block](2026-09-26 confirm-gate-machine;2026-09-27 confirm-gate-delegated 两形态;
1059
1195
  // 生效日锚 2026-09-28 改台账 ts——此前锚取自文档自报「日期/发现」,新档只要把日期写早即整段跳过判定,
1060
1196
  // incident 2026-09-28-confirm-gate-effective-date-anchor 实证)---
1197
+ if (laneOn(15)) { // lane=hard:指纹链
1061
1198
  markGate('15', '确认指纹对账');
1062
1199
  // 确认两形态(confirm-doc.mjs):TTY 亲手键入「可以」/ --delegated 对话委托代录(用户对话内明确放行后
1063
1200
  // AI 代录,台账行如实记 source=chat-delegated + quote 原话,永不伪装 TTY)。intents/specs/plans 凡
@@ -1071,18 +1208,26 @@ export function runCheckLoop(opts = {}) {
1071
1208
  // 台账坏行容忍跳过(审计件,jsonl 追加式);frontmatter 存 16 位、台账存 64 位,按前 16 位配对。
1072
1209
  {
1073
1210
  const EFFECTIVE = kitPolicy.confirmDocsEffective;
1074
- const ledgerPath = path.join(ROOT, '.agents', 'confirmations.jsonl');
1211
+ // 取数走 ledger-loader 的**带来源行号视图**(2026-10-12 ledger-shard-write):主台账 + 分片
1212
+ // `.agents/confirmations.d/*.jsonl`。分片里的行同样受链校验——否则 `--shard` 写入就等于给台账开了
1213
+ // 一个防伪盲区(门禁看得见分片行、却不验它们的链)。
1214
+ // **此处曾刻意不走 loader**(单源化时留的例外,因当时要物理行号对齐);引入分片后该理由已不成立
1215
+ // ——单一行号跨来源无法定位,故改用带 rel 的定位。第二处例外仍是 check-ledger-invariant.mjs
1216
+ // (它审的是**盘面字节**的 append-only 前缀不变量,不是台账语义,见该文件头部)。
1075
1217
  const ledger = [];
1076
- const ledgerBadLines = []; // 坏行(JSON.parse 失败)的物理行号(复核 P2-1:报文行号须对齐物理行)
1077
- if (fs.existsSync(ledgerPath)) {
1078
- for (const [lineNo, line] of (linesOf(ledgerPath) || []).entries()) {
1079
- if (!line.trim()) continue;
1080
- try { ledger.push(JSON.parse(line)); } catch { ledgerBadLines.push(lineNo + 1); }
1081
- }
1218
+ const ledgerRefs = []; // 与 ledger 同下标:{rel, no}——断裂报文的定位来源
1219
+ for (const e of readLedgerEntries(ROOT)) {
1220
+ if (e.row === null) continue; // 坏行跳过(容错口径同前;它占物理行号但不入 ledger 下标)
1221
+ ledger.push(e.row);
1222
+ ledgerRefs.push({ rel: e.rel, no: e.no });
1082
1223
  }
1083
- // 台账哈希链校验(2026-10-09 engine-quality-round2 D;写入侧=confirm-doc appendLedger,哈希单源
1084
- // policy.ledgerChainHash——判定零复刻)。判据:连续带 hash 行段内,① prevHash 须等于前一带 hash
1085
- // 行的 hash(无 hash 行后链段重启 '',与写入侧读末行口径一致);② hash 须可重算一致。
1224
+ // 台账哈希链校验(2026-10-09 engine-quality-round2 D;2026-10-12 ledger-doc-chain 改链域;
1225
+ // 写入侧=confirm-doc appendLedger,哈希单源 policy.ledgerChainHash——判定零复刻)。
1226
+ // **链域已从「文件物理序」改为「按 doc 的逻辑序」**(锚后生效,理由与不追溯口径见 POLICIES v8):
1227
+ // 原判据 ① prevHash = 前一带 hash 行(物理)的 hash;新判据 ① = **同行 doc** 最后一个带 hash 行的
1228
+ // hash。两者都要求 ② hash 可重算一致。无 hash 行仍按「链段重启」处理。
1229
+ // 并发 append / git 并集合并 / 分片归并这三种**正常协作**都会打断物理链——门禁若继续据此 hard 拦,
1230
+ // 必然被 --no-verify 绕过,治理失效;而 doc 链对就地改行 / 删行 / 插行三类篡改的检出能力不变。
1086
1231
  // **坏行口径(复核 P2-1 勘误,此前注释误称「与写入侧一致」)**:坏行被本解析整体剔除、不重置游标
1087
1232
  // ——坏行后写入的链行(写入侧读末行遇坏行 prevHash='')验链必失配出账。这是**预期 fail-loud**
1088
1233
  // (坏行本身即台账完整性事故,应人工查验),非口径一致场景。
@@ -1093,19 +1238,36 @@ export function runCheckLoop(opts = {}) {
1093
1238
  let prevHash = '';
1094
1239
  let brokenAt = 0;
1095
1240
  let brokenCount = 0;
1241
+ // 链域分界(2026-10-12 ledger-doc-chain):doc 链锚存在且合法时,**按行分域**验链——
1242
+ // 锚前行(ts < 锚)维持物理链口径(存量零变化);锚后行(ts ≥ 锚)按「同行 doc 的最后一个
1243
+ // 带 hash 行」接续,并同样要求 hash 可重算一致。锚缺键(v1-v7)→ 全表走物理链(= 旧行为)。
1244
+ // byDoc 对**两种域的行都更新**:锚后行需要接到锚前该 doc 的最后一行,跨域才能连续。
1245
+ const docChainOn = ledgerDocChainActive(kitPolicy);
1246
+ const docChainSince = docChainOn ? kitPolicy.ledgerDocChainSince : '';
1247
+ const byDoc = new Map();
1248
+ const prunedHashSet = prunedHashesOf(ROOT); // 特许修剪凭据(无 manifest 时为空集,零 IO 成本)
1096
1249
  ledger.forEach((row, idx) => {
1097
1250
  if (!row || typeof row.hash !== 'string') { prevHash = ''; return; } // 存量行/无链字段 → 链段重启
1098
1251
  const { hash, prevHash: p, ...rest } = row;
1099
- const ok = (p ?? '') === prevHash && ledgerChainHash(rest, p ?? '') === hash;
1252
+ const inDocChain = docChainOn && typeof row.ts === 'string' && row.ts >= docChainSince;
1253
+ const expected = inDocChain ? (byDoc.get(row.doc) ?? '') : prevHash;
1254
+ // 特许修剪链段重启(2026-10-12 ledger-prune-manifest):删掉某 doc 的链行后,其后继行仍带被删行
1255
+ // 的 prevHash,而该行已不在表内 → 必然失配。本行的 prevHash 若出现在 manifest 声明的被删哈希里,
1256
+ // 即视为**有凭据的合法重启点**而非篡改(凭据 = .agents/ledger-prune-manifest.json,入库可对质)。
1257
+ const prunedRestart = (p ?? '') !== expected && prunedHashSet.has(p ?? '');
1258
+ const ok = ((p ?? '') === expected || prunedRestart) && ledgerChainHash(rest, p ?? '') === hash;
1100
1259
  if (!ok) {
1101
- if (!brokenAt) brokenAt = idx + 1;
1260
+ if (!brokenAt) brokenAt = idx + 1; // 1-based 下标,供 ledgerRefs 定位
1102
1261
  brokenCount++;
1103
1262
  }
1104
1263
  prevHash = hash;
1264
+ if (typeof row.doc === 'string') byDoc.set(row.doc, hash);
1105
1265
  });
1106
1266
  if (brokenAt) {
1107
- const physical = brokenAt + ledgerBadLines.filter((n) => n <= brokenAt).length; // 物理行号(复核 P2-1:剔除坏行会令数组下标漂移)
1108
- blockers.push(`- [台账链断裂] confirmations.jsonl 自第 ${physical} 行(物理)起哈希链校验失败(共 ${brokenCount} 行不一致——append-only 台账出现就地改/删痕迹;prevHash 接续或内容重算不符。整文件重写不可机器防,对质走台账自身 git 历史)`);
1267
+ // 定位用 ledgerRefs(来源 + 行号):跨来源后单一行号无法定位;坏行占位不计入 ledger 下标
1268
+ const at = ledgerRefs[brokenAt - 1] || { rel: LEDGER_REL, no: brokenAt };
1269
+ const domain = docChainOn ? '锚前物理链 / 锚后 doc 链' : '物理链';
1270
+ blockers.push(`- [台账链断裂] 自 ${at.rel}:${at.no} 起哈希链校验失败(${domain},共 ${brokenCount} 行不一致——append-only 台账出现就地改/删痕迹;prevHash 接续或内容重算不符。整文件重写不可机器防,对质走台账自身 git 历史)`);
1109
1271
  }
1110
1272
  }
1111
1273
  // scope 子项(2026-10-09 审查 A1 干净版):受管台账行须带**机器派生**的改动面 scope{files,sha256}。
@@ -1226,7 +1388,7 @@ export function runCheckLoop(opts = {}) {
1226
1388
  // of > 1 = 一次调用落多份态。delegated 形态下这正是「并录」(入口已拒多份,此处抓历史/绕行);
1227
1389
  // TTY 形态天然逐份过目(用户亲手键入),of>1 不构成违规——故只对 delegated 行报。
1228
1390
  if (!rows.some((r) => r.source === 'chat-delegated')) continue;
1229
- // 协作道批量豁免(2026-09-30 hybrid-governance-risk-lanes):confirm-doc --batch 仅受理 L0/L1
1391
+ // 协作道批量豁免(2026-09-30 hybrid-governance-risk-lanes):confirm-doc --batch 仅受理 L1
1230
1392
  // (逐份读级别,L2/L3 逐份拒绝),台账行带 brief:true——全行带标记的批次是 sanctioned 泳道行为
1231
1393
  // (异步审计兜底),不出「确认并录」;缺标记(旧版脚本/手造台账)照旧告警,判据偏严不偏松。
1232
1394
  if (rows.every((r) => r.brief === true)) continue;
@@ -1236,8 +1398,10 @@ export function runCheckLoop(opts = {}) {
1236
1398
  }
1237
1399
  }
1238
1400
  }
1401
+ } // laneOn(15) 守卫闭合
1239
1402
 
1240
1403
  // --- 16. 量化断言指标签名对账 [warning](2026-09-28 claim-exceeds-fix;登记表单源 .agents/metric-claims.txt)---
1404
+ if (laneOn(16)) { // lane=hygiene
1241
1405
  markGate('16', '量化断言签名对账');
1242
1406
  // 判据要点:活跃态文档(draft/approved/open)中的 `{{指标名}}`(小写点分)签名须替换为实时值,留签名=未回填=
1243
1407
  // warning;只查显式签名、不全文扫数字(历史叙述假阳性恒 0);未登记签名 / 取数器缺失 → fail-loud 出账;
@@ -1247,8 +1411,10 @@ export function runCheckLoop(opts = {}) {
1247
1411
  // (ROOT/ENUMS/docFiles/fmGet/inSet/isTracked/linesOf/readdirOrNull/warnings,以代码实际引用集为准);
1248
1412
  // 调用位置须保持在检查 15 之后、输出段之前——warnings 按插入序输出,位置变化会改变输出行序。
1249
1413
  runCheck16({ ROOT, ENUMS, docFiles, fmGet, inSet, isTracked, linesOf, readdirOrNull, warnings });
1414
+ } // laneOn(16) 守卫闭合
1250
1415
 
1251
1416
  // --- 17. 发版提交树上仍未收口的 intent/spec/plan [hard-block] ---
1417
+ if (laneOn(17)) { // lane=hard:发版收口
1252
1418
  markGate('17', '发版树未收口文档');
1253
1419
  // 最近一次 package.json version 发生变化的提交里,当时状态已是 draft 或 approved 的
1254
1420
  // intent/spec/plan,被扫描的树上仍是 draft 或 approved 则阻断。
@@ -1287,13 +1453,17 @@ export function runCheckLoop(opts = {}) {
1287
1453
  }
1288
1454
  }
1289
1455
  }
1456
+ } // laneOn(17) 守卫闭合
1290
1457
 
1291
1458
  // --- 18. 委派台账对账 [warning] ---
1459
+ if (laneOn(18)) { // lane=hygiene
1292
1460
  markGate('18', '委派台账对账');
1293
1461
  // L2/L3 的 intent、spec、plan 状态为 done,或同级别 incident 状态为 fixed 或 closed 时,
1294
1462
  // 「委派结果」表与「自做任务结果」表均没有日期不早于文档日期、且含该文件名(带/不带 .md 均匹配)的一行,则警告。
1295
1463
  // 缺级别、缺日期、以及其他状态不警告。audit:false 时 warnings.push 已被换成空函数。
1296
1464
  // 两表解析口径与 agg-delegations.cjs splitTables 保持一致,一边改另一边须跟。
1465
+ // 分片感知(2026-10-13 ledger-shard-ledgers):delegationResultRows 走 ledger-shards.readDelegationsText
1466
+ // 合并读(主台账 ∪ delegations.d/*.md),分片行与本表行同一对账口径,判据零改动。
1297
1467
  {
1298
1468
  const rows = delegationResultRows(path.join(ROOT, WF, 'delegations.md'));
1299
1469
  for (const sub of ['intents', 'specs', 'plans', 'incidents']) {
@@ -1317,8 +1487,10 @@ export function runCheckLoop(opts = {}) {
1317
1487
  }
1318
1488
  }
1319
1489
  }
1490
+ } // laneOn(18) 守卫闭合
1320
1491
 
1321
1492
  // --- 19. 逐阶段审计 [warning](2026-09-30 stage-gate-machine;口径与 stage-gates.mjs / fill-* / confirm-doc 前置门互引) ---
1493
+ if (laneOn(19)) { // lane=hygiene
1322
1494
  markGate('19', '逐阶段审计');
1323
1495
  // 判据 A(在途扫描):同名 spec/plan 为 draft 且其日期 ≥ stageGateSince 时——入口未确认(intent:状态非
1324
1496
  // approved/done、或缺台账行且非存量;incident:「时间线」小节缺行首「用户确认」条目)→ warning;
@@ -1326,8 +1498,8 @@ export function runCheckLoop(opts = {}) {
1326
1498
  // plan 另判(入口级别 L2/L3 且 spec 未确认或缺失)→ warning。
1327
1499
  // 判据 B(台账顺序):同主题 {intents,specs,plans} 的 approved 行(每 doc 取最早)时间须非降序;仅对
1328
1500
  // 组内最早 ts 日期 ≥ stageGateSince 的主题判定;含更早 ts 的主题整组跳过(历史豁免)。
1329
- // 协作道豁免(2026-09-30 hybrid-governance-risk-lanes):入口 intent 为 draft 且级别 L0/L1 → 判据 A 静默
1330
- // (「先动手后确认」是泳道语义;approved/done 无台账行仍照报);判据 B 对入口 L0/L1 的主题豁免顺序
1501
+ // 协作道豁免(2026-09-30 hybrid-governance-risk-lanes):入口 intent 为 draft 且级别 L1 → 判据 A 静默
1502
+ // (「先动手后确认」是泳道语义;approved/done 无台账行仍照报);判据 B 对入口 L1 的主题豁免顺序
1331
1503
  // 倒置判定(入口文件缺失不豁免)。
1332
1504
  // stageGateSince 缺键(policy v1)→ 本检查整体跳过;全部 warning、不 hard-block。
1333
1505
  {
@@ -1335,13 +1507,7 @@ export function runCheckLoop(opts = {}) {
1335
1507
  if (typeof since === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(since)) {
1336
1508
  const ledgerRows = [];
1337
1509
  {
1338
- const lp = path.join(ROOT, '.agents', 'confirmations.jsonl');
1339
- if (fs.existsSync(lp)) {
1340
- for (const line of linesOf(lp) || []) {
1341
- if (!line.trim()) continue;
1342
- try { ledgerRows.push(JSON.parse(line)); } catch { /* 坏行跳过(同检查 15 口径) */ }
1343
- }
1344
- }
1510
+ for (const e of readLedgerRows(ROOT)) ledgerRows.push(e);
1345
1511
  }
1346
1512
  const hasRow = (rel) => ledgerRows.some((e) => e && e.doc === rel && (e.stage === 'approved' || e.stage === 'done'));
1347
1513
  const docConfirmed = (rel, abs) => {
@@ -1400,7 +1566,7 @@ export function runCheckLoop(opts = {}) {
1400
1566
  const ent = entryConfirmed19(base);
1401
1567
  if (!ent.ok) {
1402
1568
  // 协作道异步审计豁免(2026-09-30 hybrid-governance-risk-lanes;2026-10-02 caliber-convergence
1403
- // 起单源 laneOfEntry·方案 C):入口 intent 仍为 draft 且泳道 low(两字段一致 L0/L1)→「先动手后
1569
+ // 起单源 laneOfEntry·方案 C):入口 intent 仍为 draft 且泳道 low(级别 L1)→「先动手后
1404
1570
  // 确认」是泳道语义,不告警;suspect(缺失/非法/分歧)不豁免;approved/done 却无台账行仍照报
1405
1571
  // (防手改状态冒充确认,与交叉一致性口径同);incident 入口不豁免(过目留痕本就轻量)。
1406
1572
  if (ent.entryDraft && laneOfEntry(ent.level, ent.risk, kitPolicy.riskLevelSince, ent.date) === 'low') continue;
@@ -1429,7 +1595,7 @@ export function runCheckLoop(opts = {}) {
1429
1595
  for (const [base, rec] of firstApproved) {
1430
1596
  const seq = ['intents', 'specs', 'plans'].filter((k) => rec[k]);
1431
1597
  if (seq.length < 2) continue;
1432
- // 协作道豁免(2026-09-30 hybrid-governance-risk-lanes):入口 L0/L1 的审批顺序倒置(如 plan 先于
1598
+ // 协作道豁免(2026-09-30 hybrid-governance-risk-lanes):入口 L1 的审批顺序倒置(如 plan 先于
1433
1599
  // intent approved——「动手后确认」)是异步审计泳道语义,非流程违规;入口文件缺失(纯台账历史行 /
1434
1600
  // incident 侧)不豁免,维持既有判据。
1435
1601
  // existsSync 守卫(2026-10-06-check19-entry-enoent):incident 闭环主题无同名 intent,「读空判级」
@@ -1438,7 +1604,7 @@ export function runCheckLoop(opts = {}) {
1438
1604
  // 与下方 spec 读取。
1439
1605
  const iabsB = path.join(ROOT, WF, 'intents', `${base}.md`);
1440
1606
  const ilvlB = fs.existsSync(iabsB) ? fmGet(iabsB, '级别') : '';
1441
- if (ilvlB === 'L0' || ilvlB === 'L1') continue;
1607
+ if (ilvlB === 'L1') continue;
1442
1608
  const earliest = seq.map((k) => rec[k]).sort()[0];
1443
1609
  if (!(earliest.slice(0, 10) >= since)) continue;
1444
1610
  let ordered = true;
@@ -1447,13 +1613,14 @@ export function runCheckLoop(opts = {}) {
1447
1613
  }
1448
1614
  }
1449
1615
  }
1616
+ } // laneOn(19) 守卫闭合
1450
1617
 
1451
1618
  // --- 加固门(仅 --hardening 启用;2026-09-30 hybrid-governance-explore-hardening)[hard-block] ---
1452
1619
  // 探索泳道(experiment/* 分支 + intent frontmatter「阶段: exploring」标记;「状态: exploring」亦认——
1453
1620
  // 非法状态本就会在检查 5 出账)允许「先动手后确认」快速 PoC;成果转正(合入 main)前必须完成加固:
1454
1621
  // ① intent 状态离开 draft → approved/done(探索作废走显式放弃态 superseded/cancelled——留档即出列,
1455
1622
  // 不加固:放弃态无代码应随行);
1456
- // ② 同名 plan 在场且状态收口(∈ doc.status.confirmed;L0 亦不豁免——本门是转正门槛,不是配对门);
1623
+ // ② 同名 plan 在场且状态收口(∈ doc.status.confirmed——本门是转正门槛,不是配对门);
1457
1624
  // ③ 泳道 L2/L3(级别优先、缺失/非法回落 risk_level,与 stage-gates 起草门同款取法)另须同名 spec
1458
1625
  // 在场且收口。
1459
1626
  // 触发面:.githooks/pre-push 对 remote=refs/heads/main 的推送以 --hardening 运行本脚本(hard 失败即阻断
@@ -1481,7 +1648,7 @@ export function runCheckLoop(opts = {}) {
1481
1648
  blockers.push(`- [加固未过] exploring 任务入 main 的 plan 未收口:${base}(plan 状态『${planSt || '缺失'}』须为 approved/done)`);
1482
1649
  }
1483
1650
  // 泳道单源(2026-10-02 caliber-convergence 方案 C;复核 P1-1 修正):suspect(缺失/非法/分歧)与
1484
- // high 同样另须同名 spec——仅 low(两字段一致 L0/L1)免 spec,只增不松。
1651
+ // high 同样另须同名 spec——仅 low(级别 L1)免 spec,只增不松。
1485
1652
  if (lane !== 'low') {
1486
1653
  const specAbs = path.join(ROOT, WF, 'specs', base);
1487
1654
  const specSt = fs.existsSync(specAbs) ? fmGet(specAbs, '状态') : '';
@@ -1495,6 +1662,7 @@ export function runCheckLoop(opts = {}) {
1495
1662
  }
1496
1663
 
1497
1664
  // --- 20. 引擎脚本测试覆盖 [warning](2026-10-01 gate-script-test-coverage;仅包源环境) ---
1665
+ if (laneOn(20)) { // lane=hygiene
1498
1666
  markGate('20', '引擎脚本测试覆盖');
1499
1667
  // 包源开发纪律:templates/_agents/scripts/ 下每个非 *.test.mjs 引擎脚本须有同名兄弟 .test.mjs,
1500
1668
  // 或在 .agents/scripts-test-exempt.txt 登记豁免(managed 下发)。装户(无 templates/)整体跳过。
@@ -1517,11 +1685,31 @@ export function runCheckLoop(opts = {}) {
1517
1685
  }
1518
1686
  }
1519
1687
  }
1688
+ } // laneOn(20) 守卫闭合
1689
+
1690
+ // --- §21–§26 六段检查(2026-10-13 B6b-2 自源仓 s21–s26 回灌;段序沿源仓 SECTIONS 21→26,接在 §20 后)---
1691
+ // ctx 只传既有共享面(与 check-hygiene / check-stage-index 的 ctx 同纪律:判定语义单源在段模块内,
1692
+ // helper 单源在本文件——复刻即造口径分叉)。段体直接 push 进共享 warnings/blockers(不返回数组,
1693
+ // check-16 先例),故 markGate 记账走共享收集器、增量天然正确(无需 appendSegs 中转)。
1694
+ // 各段判据与适配清单见各模块文件头注。
1695
+ const sharedCtx = { ROOT, WF, DOC_DIRS, ENUMS, inSet, docFiles, fmGet, linesOf, isTracked, readdirOrNull, addedDateOf, kitPolicy, warnings, blockers };
1696
+ if (laneOn(21)) { markGate('21', 'spec 验证落地核查'); runSpecVerif(sharedCtx); } // lane=hygiene(锚 specVerifSince)
1697
+ if (laneOn(22)) { markGate('22', '机制使用量台账'); runRegistry(sharedCtx); } // lane=hygiene(mechanism-registry 在场才启用)
1698
+ if (laneOn(23)) { markGate('23', '判据级收敛对账'); runConvergence(sharedCtx); } // lane=hard(hard 档随 convergenceHardSince)
1699
+ if (laneOn(24)) { markGate('24', 'incident 归因字段'); runAttribution(sharedCtx); } // lane=hygiene(锚 attributionSince)
1700
+ if (laneOn(25)) { markGate('25', '路由预判一致性'); runPrejudgment(sharedCtx); } // lane=hard(内容纯 WARN 不阻断)
1701
+ if (laneOn(26)) { markGate('26', '闭环漏斗协议前占比'); runFunnel(sharedCtx); } // lane=hygiene(metrics.md 在场才启用)
1520
1702
 
1521
1703
  // --- 输出(banner 沿 sh 版字样与格式 = 稳定输出契约:banner 后空行、条目 '- ' 前缀)---
1522
1704
  // 门禁 ROI 收口(2026-10-08 gate-roi-metrics):末段结算(末段之后无下次 gateSeg 调用)+ 可选落盘。
1523
1705
  // ⚠️ 结算在输出**之前**:否则检查 20 之后的段不计入。落盘只在 --gate-stats 时发生。
1524
1706
  if (opts.gateStats) writeGateStats(ROOT, finishSegs(gateStats));
1707
+ // --- 判定流水落账(2026-10-11 judgment-ledger,灰度消费端数据底座)---
1708
+ // 每次真实运行追加一行 per-rule 判定计数到 .agents/judgments.jsonl(本地 gitignore;fixture 经
1709
+ // CHECK_LOOP_ROOT 守卫自动跳过)——mechanism-registry 月度对账与 advisory→hard 升格判定的数据源
1710
+ // 由「人工 grep 输出」升级为 agg-judgments.mjs 查账。fail-open:落账失败不改变门禁裁决与输出契约。
1711
+ // mode 随分道传真实运行面(2026-10-13 B6b-1:hard/hygiene/all——原 'all' 硬编码随分道退役)。
1712
+ recordRun({ root: ROOT, mode: LOOP_MODE, blockers, warnings });
1525
1713
  if (blockers.length) {
1526
1714
  process.stderr.write(`闭环骨架断档(check-loop.sh)— HARD-BLOCK:\n\n${blockers.join('\n')}\n\n`);
1527
1715
  if (warnings.length) process.stderr.write(`WARN(advisory,不阻断):\n\n${warnings.join('\n')}\n`);
@@ -1538,8 +1726,9 @@ const isMain = process.argv[1] && process.argv[1].replace(/\\/g, '/').endsWith('
1538
1726
  if (isMain) process.exit(runCheckLoop(takeOpts()).exitCode);
1539
1727
 
1540
1728
  export function delegationResultRows(file) {
1541
- let text = '';
1542
- try { text = fs.readFileSync(file, 'utf8'); } catch { return []; }
1729
+ // 分片感知读(2026-10-13 ledger-shard-ledgers):主台账 ∪ delegations.d/*.md,单源 = ledger-shards。
1730
+ // file 为显式注入路径时只读该文件(测试语义不变);传默认主台账路径 → 走分片合并。
1731
+ const text = readDelegationsText(path.dirname(path.dirname(file)), file);
1543
1732
  const lines = text.split(/\r?\n/);
1544
1733
  // 两表识别与 agg-delegations.cjs splitTables 表头签名同口径(一边改另一边须跟,2026-10-08 papercuts-cleanup-batch 修 2):
1545
1734
  // 委派表头=含「被委派方」列;自做表头=首列「日期」且含「任务一句话」列——节标题只服务人类阅读,