@event4u/agent-config 16.1.0 → 16.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (467) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +98 -257
  5. package/README.md +14 -12
  6. package/dist/agent-src/commands/analyze/inbox.md +1 -1
  7. package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
  8. package/dist/agent-src/commands/bug/fix.md +17 -2
  9. package/dist/agent-src/commands/feature/plan.md +1 -1
  10. package/dist/agent-src/commands/feature/roadmap.md +1 -1
  11. package/dist/agent-src/commands/fix/ci.md +1 -1
  12. package/dist/agent-src/commands/implement-ticket.md +1 -1
  13. package/dist/agent-src/commands/jira-ticket.md +1 -1
  14. package/dist/agent-src/commands/roadmap/create.md +1 -1
  15. package/dist/agent-src/commands/roadmap/materialize.md +1 -1
  16. package/dist/agent-src/commands/roadmap/process-full.md +5 -5
  17. package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
  18. package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
  19. package/dist/agent-src/commands/roadmap.md +18 -4
  20. package/dist/agent-src/commands/tests/create.md +17 -3
  21. package/dist/agent-src/commands/tests/execute.md +22 -5
  22. package/dist/agent-src/commands/work.md +4 -0
  23. package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
  24. package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
  25. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
  26. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +4 -8
  27. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
  28. package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
  29. package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
  30. package/dist/agent-src/rules/active-remediation.md +1 -1
  31. package/dist/agent-src/rules/autonomous-execution.md +1 -0
  32. package/dist/agent-src/rules/broken-access-control.md +1 -0
  33. package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
  34. package/dist/agent-src/rules/context-hygiene.md +1 -1
  35. package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
  36. package/dist/agent-src/rules/design-fidelity.md +13 -16
  37. package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
  38. package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
  39. package/dist/agent-src/rules/domain-safety-pii.md +1 -0
  40. package/dist/agent-src/rules/domain-safety-retention.md +1 -0
  41. package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
  42. package/dist/agent-src/rules/evaluator-independence.md +3 -2
  43. package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
  44. package/dist/agent-src/rules/finance-safety-floor.md +1 -0
  45. package/dist/agent-src/rules/git-history-discipline.md +1 -0
  46. package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
  47. package/dist/agent-src/rules/legal-safety-floor.md +3 -2
  48. package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
  49. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
  50. package/dist/agent-src/rules/media-governance-routing.md +14 -17
  51. package/dist/agent-src/rules/persona-governance.md +2 -2
  52. package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
  53. package/dist/agent-src/rules/question-not-instruction.md +1 -0
  54. package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
  55. package/dist/agent-src/rules/runtime-safety.md +1 -0
  56. package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
  57. package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
  58. package/dist/agent-src/rules/session-canary.md +8 -62
  59. package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
  60. package/dist/agent-src/rules/source-confidentiality.md +1 -0
  61. package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
  62. package/dist/agent-src/rules/tool-safety.md +1 -0
  63. package/dist/agent-src/rules/ui-audit-gate.md +1 -2
  64. package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
  65. package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
  66. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  67. package/dist/agent-src/scripts/deferral_carry.ts +339 -0
  68. package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
  69. package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +1 -1
  70. package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +2 -2
  71. package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
  72. package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
  73. package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
  74. package/dist/agent-src/skills/design-review/SKILL.md +30 -4
  75. package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
  76. package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
  77. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +18 -3
  78. package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
  79. package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
  80. package/dist/agent-src/skills/iconography/SKILL.md +1 -1
  81. package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
  82. package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
  83. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
  84. package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
  85. package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
  86. package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
  87. package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
  88. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  89. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
  90. package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
  91. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
  92. package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
  93. package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
  94. package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
  95. package/dist/agent-src/skills/ui-component-architect/SKILL.md +25 -2
  96. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  97. package/dist/agent-src/templates/roadmaps.md +30 -0
  98. package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
  99. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
  100. package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
  101. package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
  102. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  103. package/dist/agent-src/templates/scripts/work_engine/state.ts +57 -7
  104. package/dist/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
  105. package/dist/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
  106. package/dist/cli/python/knowledge_ingest.js +1 -1
  107. package/dist/cli/python/workspace_drive.js +1 -1
  108. package/dist/cli/registry.js +1 -1
  109. package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
  110. package/dist/cli-delegate/check_update_banner.js +12 -1
  111. package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
  112. package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
  113. package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
  114. package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
  115. package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
  116. package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
  117. package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
  118. package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
  119. package/dist/cli-delegate/{chunk-UNCRJBT3.js → chunk-JQVYKIZA.js} +41 -0
  120. package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
  121. package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
  122. package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-KR6EM23A.js} +235 -1455
  123. package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
  124. package/dist/cli-delegate/chunk-NQ7WT43P.js +2729 -0
  125. package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
  126. package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
  127. package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
  128. package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
  129. package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
  130. package/dist/cli-delegate/{chunk-HDVVGPQW.js → chunk-RQNNW7IF.js} +1405 -567
  131. package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-S4UMZNES.js} +1 -1
  132. package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
  133. package/dist/cli-delegate/{chunk-GJCBB2UG.js → chunk-TRI6DQZ6.js} +3054 -325
  134. package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
  135. package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
  136. package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
  137. package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
  138. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  139. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  140. package/dist/cli-delegate/cmd_conformance.js +1862 -809
  141. package/dist/cli-delegate/cmd_doctor.js +13 -6
  142. package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
  143. package/dist/cli-delegate/cmd_explain.js +5 -5
  144. package/dist/cli-delegate/cmd_export.js +11 -8
  145. package/dist/cli-delegate/cmd_fleet.js +3 -3
  146. package/dist/cli-delegate/cmd_handoff.js +10 -7
  147. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  148. package/dist/cli-delegate/cmd_memory_get.js +3 -1
  149. package/dist/cli-delegate/cmd_migrate.js +2 -2
  150. package/dist/cli-delegate/cmd_packs_active.js +3 -3
  151. package/dist/cli-delegate/cmd_preflight.js +6 -6
  152. package/dist/cli-delegate/cmd_prune.js +11 -8
  153. package/dist/cli-delegate/cmd_refresh.js +2 -1
  154. package/dist/cli-delegate/cmd_route_audit.js +8 -6
  155. package/dist/cli-delegate/cmd_route_explain.js +4 -4
  156. package/dist/cli-delegate/cmd_session_recycle.js +4 -3
  157. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  158. package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
  159. package/dist/cli-delegate/cmd_settings_set.js +4 -4
  160. package/dist/cli-delegate/cmd_sync.js +11 -8
  161. package/dist/cli-delegate/cmd_uninstall.js +11 -8
  162. package/dist/cli-delegate/cmd_update.js +1 -1
  163. package/dist/cli-delegate/cmd_upgrade.js +3 -2
  164. package/dist/cli-delegate/cmd_validate.js +11 -8
  165. package/dist/cli-delegate/cmd_versions.js +1 -1
  166. package/dist/cli-delegate/deferral_carry.js +16 -0
  167. package/dist/cli-delegate/gate_execute.js +2 -2
  168. package/dist/cli-delegate/roadmap_gates.js +5 -5
  169. package/dist/cli-delegate/update_roadmap_progress.js +1 -1
  170. package/dist/discovery/deprecation-report.md +1 -1
  171. package/dist/discovery/discovery-manifest.json +132 -80
  172. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  173. package/dist/discovery/discovery-manifest.summary.md +3 -3
  174. package/dist/discovery/dormancy-report.md +1 -1
  175. package/dist/discovery/orphan-report.md +1 -1
  176. package/dist/discovery/packs.json +7 -5
  177. package/dist/discovery/trust-report.md +2 -2
  178. package/dist/discovery/workspaces.json +6 -4
  179. package/dist/hooks/dispatch.js +7972 -5186
  180. package/dist/hooks/dispatch.sha256 +1 -0
  181. package/dist/install/claudePathsPlan.js +47 -6
  182. package/dist/install/claudeRuleRewrite.js +7 -0
  183. package/dist/install/emit_host_rules_cli.js +39 -36
  184. package/dist/install/globalRuleScope.js +87 -0
  185. package/dist/install/host_rule_ownership.js +160 -0
  186. package/dist/install/install.mjs +2226 -1055
  187. package/dist/install/installThinLayer.js +261 -0
  188. package/dist/install/installedRuleLinks.js +176 -0
  189. package/dist/install/wizard-plan.js +24 -0
  190. package/dist/mcp/registry-manifest.json +3 -3
  191. package/dist/mcp/server.json +2 -2
  192. package/dist/mcp/server.mjs +40913 -34865
  193. package/dist/scripts/_lib/agent_settings.js +11 -0
  194. package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
  195. package/dist/scripts/_lib/installed_layer.js +378 -0
  196. package/dist/scripts/_lib/lean_projection_mode.js +218 -15
  197. package/dist/scripts/_lib/rule_consequence_class.js +45 -0
  198. package/dist/scripts/_lib/rule_injection.js +67 -10
  199. package/dist/scripts/_lib/rule_law_section.js +122 -0
  200. package/dist/scripts/_lib/thin_rules.js +458 -0
  201. package/dist/scripts/_lib/windsurf_render.js +60 -0
  202. package/dist/scripts/condense.js +14 -26
  203. package/dist/scripts/project_thin_rules.js +14 -294
  204. package/dist/server/schemas/settings.js +29 -0
  205. package/dist/shared/skillRanking.js +74 -13
  206. package/dist/ui/assets/index-Cwq4d0hX.js +23 -0
  207. package/dist/ui/assets/index-Cyjy8bWO.css +1 -0
  208. package/dist/ui/index.html +2 -2
  209. package/docs/contracts/settings-classes.md +10 -6
  210. package/package.json +4 -4
  211. package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  212. package/src/agent-src/scripts/deferral_carry.ts +339 -0
  213. package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
  214. package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
  215. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
  216. package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
  217. package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
  218. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  219. package/src/agent-src/templates/scripts/work_engine/state.ts +57 -7
  220. package/src/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
  221. package/src/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
  222. package/src/config/agent-settings.template.yml +91 -22
  223. package/src/config/ci-local-parity.yml +18 -0
  224. package/src/config/continuity-surface.json +9 -2
  225. package/src/config/evaluator-budgets.json +4 -4
  226. package/src/config/gate-coverage.yml +327 -3
  227. package/src/config/gate-violation-baselines.json +21 -9
  228. package/src/config/hook-bundle-budget.json +25 -0
  229. package/src/config/hook-latency-budget.json +21 -0
  230. package/src/config/hook-token-budget.json +8 -3
  231. package/src/config/host-instruction-limits.json +33 -0
  232. package/src/config/metric-registry.yml +114 -0
  233. package/src/config/placeholder-drift-budget.json +10 -0
  234. package/src/config/routing-coverage-seed.json +38 -3
  235. package/src/config/rule-activation-census.json +7 -3
  236. package/src/config/rule-consequence-class.json +161 -0
  237. package/src/config/rule-law-ceilings.json +99 -0
  238. package/src/install/claudePathsPlan.ts +46 -4
  239. package/src/install/claudeRuleRewrite.ts +10 -1
  240. package/src/install/emit_host_rules_cli.ts +43 -34
  241. package/src/install/globalRuleScope.ts +109 -0
  242. package/src/install/host_rule_ownership.ts +170 -0
  243. package/src/install/installThinLayer.ts +312 -0
  244. package/src/install/installedRuleLinks.ts +220 -0
  245. package/src/install/wizard-plan.ts +24 -0
  246. package/src/scripts/_cli/cmd_doctor.ts +28 -90
  247. package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
  248. package/src/scripts/_cli/doctor_execution.ts +100 -17
  249. package/src/scripts/_cli/doctor_network_posture.ts +226 -0
  250. package/src/scripts/_dispatch.bash +16 -2
  251. package/src/scripts/_lib/agent_settings.ts +11 -0
  252. package/src/scripts/_lib/body_portable.ts +102 -0
  253. package/src/scripts/_lib/cc_transcript.ts +132 -1
  254. package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
  255. package/src/scripts/_lib/concern_sla_window.ts +200 -0
  256. package/src/scripts/_lib/estate_offsets.ts +241 -0
  257. package/src/scripts/_lib/exemption_shape.ts +143 -0
  258. package/src/scripts/_lib/fnv.ts +23 -0
  259. package/src/scripts/_lib/foreign_scan.ts +106 -0
  260. package/src/scripts/_lib/forge_protection.ts +114 -0
  261. package/src/scripts/_lib/forge_reader.ts +558 -0
  262. package/src/scripts/_lib/gitignore_block.ts +314 -0
  263. package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
  264. package/src/scripts/_lib/graph_feeder_record.ts +214 -0
  265. package/src/scripts/_lib/hook_settings.ts +73 -0
  266. package/src/scripts/_lib/host_capability.ts +40 -19
  267. package/src/scripts/_lib/host_env_write.ts +111 -0
  268. package/src/scripts/_lib/host_hook_merge.ts +165 -0
  269. package/src/scripts/_lib/installed_layer.ts +538 -0
  270. package/src/scripts/_lib/json_merge.ts +82 -0
  271. package/src/scripts/_lib/json_pointers.ts +93 -11
  272. package/src/scripts/_lib/lean_projection_mode.ts +275 -15
  273. package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
  274. package/src/scripts/_lib/machine_wake.ts +16 -3
  275. package/src/scripts/_lib/neighbour_census.ts +760 -0
  276. package/src/scripts/_lib/neighbour_scan.ts +122 -0
  277. package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
  278. package/src/scripts/_lib/obligations.ts +119 -8
  279. package/src/scripts/_lib/probe_inputs.ts +271 -0
  280. package/src/scripts/_lib/prompt_shape.ts +46 -0
  281. package/src/scripts/_lib/read_surface_scan.ts +322 -0
  282. package/src/scripts/_lib/release_highlights.ts +2 -1
  283. package/src/scripts/_lib/release_migration_gate.ts +19 -3
  284. package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
  285. package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
  286. package/src/scripts/_lib/review_coverage.ts +134 -0
  287. package/src/scripts/_lib/rule_consequence_class.ts +71 -0
  288. package/src/scripts/_lib/rule_injection.ts +130 -10
  289. package/src/scripts/_lib/rule_law_section.ts +147 -0
  290. package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
  291. package/src/scripts/_lib/shell_write_shapes.ts +108 -0
  292. package/src/scripts/_lib/skill_origin.ts +254 -0
  293. package/src/scripts/_lib/structural_hiding.ts +622 -0
  294. package/src/scripts/_lib/structured_ask.ts +64 -21
  295. package/src/scripts/_lib/thin_rules.ts +540 -0
  296. package/src/scripts/_lib/touched_file_quality.ts +434 -0
  297. package/src/scripts/_lib/turn_end_refusals.ts +600 -4
  298. package/src/scripts/_lib/turn_end_transcript.ts +216 -0
  299. package/src/scripts/_lib/verification_command.ts +324 -0
  300. package/src/scripts/_lib/verification_evidence.ts +647 -0
  301. package/src/scripts/_lib/verify_clause.ts +280 -0
  302. package/src/scripts/_lib/windsurf_render.ts +63 -0
  303. package/src/scripts/ai_council/cli_call_budget.ts +13 -5
  304. package/src/scripts/ai_council/clients.ts +26 -57
  305. package/src/scripts/ai_council/config.ts +1 -1
  306. package/src/scripts/ai_council/vendor_defaults.ts +45 -0
  307. package/src/scripts/ai_team/team_dispatch.ts +4 -0
  308. package/src/scripts/audit_skill_overlap.ts +261 -0
  309. package/src/scripts/before_complete_hook.ts +573 -25
  310. package/src/scripts/bench_hook_latency.ts +412 -5
  311. package/src/scripts/bench_touched_file_quality.ts +238 -0
  312. package/src/scripts/cache_realization_report.ts +61 -1
  313. package/src/scripts/check_argument_hint.ts +287 -0
  314. package/src/scripts/check_claims.ts +125 -1
  315. package/src/scripts/check_enforcement_coverage.ts +38 -9
  316. package/src/scripts/check_enforcement_matrix.ts +621 -22
  317. package/src/scripts/check_estate_count.ts +130 -153
  318. package/src/scripts/check_finding_dispositions.ts +138 -7
  319. package/src/scripts/check_generator_sync.ts +71 -0
  320. package/src/scripts/check_hook_bundle_composition.ts +370 -0
  321. package/src/scripts/check_host_docs_digest.ts +786 -0
  322. package/src/scripts/check_host_format_column.ts +559 -0
  323. package/src/scripts/check_input_references.ts +228 -0
  324. package/src/scripts/check_inputs_parity.ts +235 -0
  325. package/src/scripts/check_kernel_edit_ratified.ts +89 -9
  326. package/src/scripts/check_kill_switch_table.ts +294 -0
  327. package/src/scripts/check_memory.ts +7 -1
  328. package/src/scripts/check_placeholder_drift.ts +221 -0
  329. package/src/scripts/check_read_surface_coverage.ts +515 -0
  330. package/src/scripts/check_release_highlights.ts +10 -0
  331. package/src/scripts/check_release_holds.ts +2 -1
  332. package/src/scripts/check_release_pr_shape.ts +38 -15
  333. package/src/scripts/check_routing_coverage.ts +378 -11
  334. package/src/scripts/check_standing_rule_delivery.ts +33 -13
  335. package/src/scripts/check_static_parity.ts +17 -0
  336. package/src/scripts/check_verify_expectation_delta.ts +521 -0
  337. package/src/scripts/ci_settle.ts +145 -19
  338. package/src/scripts/closure_scan.ts +115 -1
  339. package/src/scripts/code_graph/detect.ts +127 -7
  340. package/src/scripts/code_graph/foreign.ts +194 -0
  341. package/src/scripts/code_graph/query.ts +217 -4
  342. package/src/scripts/code_graph/types.ts +26 -2
  343. package/src/scripts/code_graph/validate.ts +3 -1
  344. package/src/scripts/code_graph/verbs.ts +103 -0
  345. package/src/scripts/compile_hook_manifest.ts +90 -14
  346. package/src/scripts/condense.ts +14 -27
  347. package/src/scripts/estate_exemption_shape.ts +202 -0
  348. package/src/scripts/external_sources_denylist.json +29 -4
  349. package/src/scripts/generate_host_cost_table.ts +1 -1
  350. package/src/scripts/hook_manifest.json +1 -1
  351. package/src/scripts/hook_manifest.yaml +192 -14
  352. package/src/scripts/hooks/block_config_weakening.ts +294 -4
  353. package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
  354. package/src/scripts/hooks/block_plumbing_writes.ts +342 -0
  355. package/src/scripts/hooks/bundle_integrity.ts +291 -0
  356. package/src/scripts/hooks/chain_nudge_hook.ts +1 -2
  357. package/src/scripts/hooks/code_graph_context_hook.ts +253 -25
  358. package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
  359. package/src/scripts/hooks/concern_failure_policy.ts +280 -0
  360. package/src/scripts/hooks/concern_registry.ts +2 -0
  361. package/src/scripts/hooks/concern_timings.ts +94 -0
  362. package/src/scripts/hooks/delegation_nudge_hook.ts +1 -2
  363. package/src/scripts/hooks/design_pass_hook.ts +100 -9
  364. package/src/scripts/hooks/design_slop_hook.ts +1 -2
  365. package/src/scripts/hooks/dispatch_hook.ts +77 -71
  366. package/src/scripts/hooks/edit_shape_hook.ts +1 -2
  367. package/src/scripts/hooks/end_review_nudge_hook.ts +1 -1
  368. package/src/scripts/hooks/evidence_independence.ts +1 -2
  369. package/src/scripts/hooks/exit_codes.ts +129 -0
  370. package/src/scripts/hooks/host_lowering.json +1 -0
  371. package/src/scripts/hooks/host_lowering.ts +146 -3
  372. package/src/scripts/hooks/host_lowering.yaml +262 -46
  373. package/src/scripts/hooks/host_semantics.ts +30 -2
  374. package/src/scripts/hooks/injection_budget.ts +9 -2
  375. package/src/scripts/hooks/interruption_ledger_hook.ts +1 -2
  376. package/src/scripts/hooks/journal_record_hook.ts +1 -2
  377. package/src/scripts/hooks/memory_recall_hook.ts +1 -2
  378. package/src/scripts/hooks/obligation_settle_hook.ts +151 -5
  379. package/src/scripts/hooks/one_question_per_ask_hook.ts +43 -6
  380. package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
  381. package/src/scripts/hooks/payload_stub.ts +10 -1
  382. package/src/scripts/hooks/permission_gate.ts +1 -2
  383. package/src/scripts/hooks/push_settle_hook.ts +1 -3
  384. package/src/scripts/hooks/replay_hook.ts +2 -1
  385. package/src/scripts/hooks/reread_guard_hook.ts +1 -2
  386. package/src/scripts/hooks/review_baseline_hook.ts +1 -2
  387. package/src/scripts/hooks/rtk_wrap_hook.ts +1 -2
  388. package/src/scripts/hooks/rule_inject_hook.ts +765 -68
  389. package/src/scripts/hooks/run_continuation_hook.ts +13 -15
  390. package/src/scripts/hooks/skill_route_hook.ts +1 -2
  391. package/src/scripts/hooks/source_first_gate_hook.ts +1 -2
  392. package/src/scripts/hooks/spawn_guard_shadow_hook.ts +1 -2
  393. package/src/scripts/hooks/subagent_ledger_hook.ts +1 -2
  394. package/src/scripts/hooks/suggestion_capture_hook.ts +1 -1
  395. package/src/scripts/hooks/table_fingerprint.ts +70 -0
  396. package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
  397. package/src/scripts/hooks/telemetry_usage_hook.ts +65 -10
  398. package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
  399. package/src/scripts/hooks/turn_end_gate_hook.ts +421 -324
  400. package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
  401. package/src/scripts/hooks_status.ts +112 -0
  402. package/src/scripts/injection_scan_hook.ts +7 -0
  403. package/src/scripts/install.ts +75 -189
  404. package/src/scripts/installed_layer_report.ts +103 -0
  405. package/src/scripts/language_mirror_hook.ts +15 -6
  406. package/src/scripts/learning_sidecar.ts +119 -8
  407. package/src/scripts/lint_deny_text.ts +419 -0
  408. package/src/scripts/lint_exit_codes.ts +262 -0
  409. package/src/scripts/lint_hook_manifest.ts +108 -0
  410. package/src/scripts/lint_major_migration_sections.ts +156 -26
  411. package/src/scripts/lint_pack_boundaries.ts +63 -5
  412. package/src/scripts/lint_roadmap_blockers.ts +78 -12
  413. package/src/scripts/lint_rule_law_section.ts +517 -0
  414. package/src/scripts/lint_skill_descriptions.ts +1 -1
  415. package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
  416. package/src/scripts/lint_workflow_security.ts +161 -5
  417. package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
  418. package/src/scripts/mcp_server/graph_tools.ts +72 -3
  419. package/src/scripts/mcp_server/prompts.ts +142 -1
  420. package/src/scripts/measure_routing_signal.ts +54 -16
  421. package/src/scripts/measure_skill_ranker_baseline.ts +515 -53
  422. package/src/scripts/measure_turn_end_gate.ts +193 -0
  423. package/src/scripts/memory_learn_hook.ts +91 -6
  424. package/src/scripts/memory_lookup.ts +1 -1
  425. package/src/scripts/model_rule_injection.ts +52 -5
  426. package/src/scripts/prepack-check.mjs +53 -0
  427. package/src/scripts/project_thin_rules.ts +34 -327
  428. package/src/scripts/release_publication.ts +13 -1
  429. package/src/scripts/report_evidence_temperature.ts +657 -0
  430. package/src/scripts/report_installed_rule_links.ts +157 -0
  431. package/src/scripts/report_invocation_surface.ts +383 -0
  432. package/src/scripts/report_label_agreement.ts +233 -0
  433. package/src/scripts/report_obligation_carriers.ts +699 -0
  434. package/src/scripts/report_obligation_mechanism.ts +230 -0
  435. package/src/scripts/report_obligation_writer_split.ts +236 -0
  436. package/src/scripts/report_single_token_triggers.ts +277 -0
  437. package/src/scripts/report_skill_menu_census.ts +208 -0
  438. package/src/scripts/report_skill_ranker_confusion.ts +442 -0
  439. package/src/scripts/report_standing_payload_by_host.ts +188 -15
  440. package/src/scripts/report_verification_record_coverage.ts +306 -0
  441. package/src/scripts/roadmap_verify_share.ts +213 -0
  442. package/src/scripts/rule_activation_census.ts +5 -2
  443. package/src/scripts/rule_trigger_eval.ts +9 -9
  444. package/src/scripts/schemas/command.schema.json +44 -0
  445. package/src/scripts/schemas/review-findings.schema.json +7 -2
  446. package/src/scripts/schemas/rule.schema.json +5 -0
  447. package/src/scripts/schemas/skill.schema.json +44 -0
  448. package/src/scripts/self_review_gate.ts +421 -17
  449. package/src/scripts/semantic_parity_census.ts +314 -0
  450. package/src/scripts/session_eol_report.ts +54 -1
  451. package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
  452. package/src/scripts/sweep_dead_scan_roots.ts +1 -1
  453. package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
  454. package/src/scripts/sync_gitignore.ts +29 -235
  455. package/src/scripts/trigger_eval_grandfather.json +0 -7
  456. package/src/scripts/trigger_eval_rotation.ts +122 -27
  457. package/src/scripts/ui_conformance_probe.ts +156 -4
  458. package/src/scripts/update_prices.ts +85 -3
  459. package/src/scripts/write_bundle_digest.mjs +74 -0
  460. package/src/server/schemas/settings.ts +41 -0
  461. package/src/shared/skillRanking.ts +117 -11
  462. package/src/templates/consumer-settings/ONBOARDING.md +1 -0
  463. package/dist/cli-delegate/chunk-FXYUYU4N.js +0 -4416
  464. package/dist/cli-delegate/chunk-QJWAUMJW.js +0 -1072
  465. package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
  466. package/dist/ui/assets/index-DH1xc62v.js +0 -29
  467. package/dist/ui/assets/index-jSfMW8_t.css +0 -1
@@ -0,0 +1,521 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * A `verify:` clause this change ADDS names what its command must produce.
4
+ *
5
+ * THE DEFECT. `verify: `cat notes.md`` is a legal, green, fully-conforming step
6
+ * field whose oracle cannot say no: the step gets flipped on a command that was
7
+ * never able to fail. The grammar that fixes it shipped in
8
+ * `_lib/verify_clause.ts` — the optional `-> 0` / `-> /regex/` tail — and
9
+ * `closure_scan` reports the unfalsifiable share as a number. Reporting is
10
+ * where it stopped. Measured over the active estate on 2026-10-01: 173 clauses,
11
+ * 99 naming a command, 34 naming an expectation, and all 34 authored in one
12
+ * round. The grammar exists and nothing asks anyone to use it.
13
+ *
14
+ * WHY DIFF-SCOPED, AND WHY THAT IS NOT A WEAKER VERSION OF ESTATE-SCOPED.
15
+ * Gating the estate would red 139 clauses across every roadmap active before
16
+ * this round, on a day nobody authored any of them. A gate that arrives red on
17
+ * most of its corpus is a backlog with an exit code, and the predictable end is
18
+ * that it gets weakened until it finds nothing. This reads only clauses the
19
+ * change under review ADDED or CHANGED, so the corpus is whatever the author is
20
+ * already writing, and the old clauses stay legal exactly as prose does.
21
+ *
22
+ * REPLAYED BEFORE IT WAS WRITTEN, not after. Over the last thirty merges on
23
+ * the trunk that touched a roadmap: 145 added command-bearing
24
+ * clauses, 96 already carrying an expectation, 49 bare — and **6 of the 30
25
+ * merges would have gone red**, 39 of the 49 sitting in a single bulk-authoring
26
+ * round. 20% is under the one-in-four share at which this ratchet was to be
27
+ * withdrawn as too costly. `--replay <n>` reproduces that table on demand,
28
+ * which is the whole measurement rather than a memory of it.
29
+ *
30
+ * THE POINTER CARVE-OUT, and it is measured rather than assumed. 8 of those 49
31
+ * bare clauses are not commands at all: a backticked FILE PATH or test id
32
+ * written after the label, which the shared parser reads as a command because
33
+ * that is what a backticked token looks like to it. Demanding `-> 0` from
34
+ * `docs/CLAIMS.md` teaches authors to paste a meaningless arrow, which is the
35
+ * failure this gate exists to prevent arriving through its own front door. So a
36
+ * single whitespace-free token ending in a source or document extension, with
37
+ * an optional `:line` suffix, is a POINTER and is not asked for an oracle.
38
+ * Anything containing a space is a command: `cat file.md` still has to answer.
39
+ *
40
+ * The carve-out lives HERE and not in the parser. Widening `verify_clause.ts`
41
+ * would change what `closure_scan` and the run-continuation hook see, and both
42
+ * were measured on the current grammar.
43
+ *
44
+ * THE ARROW IS NOT PARSED HERE AT ALL. This gate asks `parseVerifyClause`
45
+ * whether a clause carries an expectation and never looks at the arrow itself:
46
+ * a second arrow regex is how a grammar and its gate drift, and a drifted pair
47
+ * fails silently — an expectation simply stops being read and a conforming
48
+ * clause is refused. An earlier version re-exported `VERIFY_ARROW_SOURCE` so a
49
+ * test could assert equality with the parser's copy; a reviewer pointed out
50
+ * that comparing two equal STRINGS proves nothing about where either came
51
+ * from, and the re-export is gone. What is asserted instead is behavioural —
52
+ * the gate's verdict changes when the parser's grammar does, because the
53
+ * parser is the only thing that reads it.
54
+ *
55
+ * CLI:
56
+ * ./scripts-run src/scripts/check_verify_expectation_delta
57
+ * ./scripts-run src/scripts/check_verify_expectation_delta --base origin/main
58
+ * ./scripts-run src/scripts/check_verify_expectation_delta --replay 30
59
+ * ./scripts-run src/scripts/check_verify_expectation_delta --self-test
60
+ *
61
+ * Exit codes: 0 clean · 1 a bare clause was added · 2 usage error or no base ref.
62
+ */
63
+ import { spawnSync } from 'node:child_process';
64
+ import * as fs from 'node:fs';
65
+ import * as os from 'node:os';
66
+ import * as path from 'node:path';
67
+ import process from 'node:process';
68
+ import { fileURLToPath, pathToFileURL } from 'node:url';
69
+
70
+ import { parseVerifyClause } from './_lib/verify_clause.js';
71
+ import { resolveBaseRef } from './_lib/ratchet_base_ref.js';
72
+ import { reportScanned, DeadScopeError } from './_lib/scan_scope.js';
73
+ import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
74
+
75
+ const _HERE = path.resolve(fileURLToPath(import.meta.url));
76
+ const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
77
+ const GATE = 'check_verify_expectation_delta';
78
+ const ROADMAPS_REL = 'agents/roadmaps';
79
+ const SCRIPT_REL = 'src/scripts/check_verify_expectation_delta.ts';
80
+
81
+ /** Declared here so a truncated case list is a visible diff, not a quiet pass. */
82
+ const SELF_TEST_MIN_CASES = 6;
83
+ const SELF_TEST_MIN_REJECT = 3;
84
+
85
+ /**
86
+ * A backticked value that points AT something rather than running.
87
+ *
88
+ * One token, no whitespace, a source or document extension, optionally a
89
+ * `:line` suffix. Measured at 8 of 49 bare clauses over thirty merges — a sixth
90
+ * of what an uncarved gate would have fired on.
91
+ *
92
+ * THE INVOCATION PREFIX IS EXCLUDED, and that is a review finding rather than a
93
+ * refinement: `./src/scripts/check.ts` ends in `.ts` and this pattern exempted
94
+ * it, while being exactly the shape a shebang-bearing script is RUN as in this
95
+ * tree. A path written to be executed starts with `./` or `/`; a pointer is
96
+ * written relative and bare. That is a convention, not a proof — the honest
97
+ * statement is that this discriminates the shapes the tree actually contains
98
+ * and cannot infer intent in general.
99
+ *
100
+ * KNOWN AND NOT FIXED, because the fix is worse than the gap: `Makefile`,
101
+ * `README` and `script.sh` are pointers this refuses, and a path containing a
102
+ * space is a command by the rule above. Widening the extension list buys those
103
+ * and costs the executable-script direction again. Both directions are pinned
104
+ * by test so a later change to this pattern is deliberate.
105
+ */
106
+ const POINTER_RE = /^(?!\.{0,2}\/)[^\s`]+\.(?:ts|tsx|js|mjs|cjs|md|json|ya?ml|html|txt|lock)(?::\d+)?$/i;
107
+
108
+ /** Does this clause body name something to RUN, as opposed to something to open? */
109
+ export function isPointer(command: string): boolean {
110
+ return POINTER_RE.test(command.trim());
111
+ }
112
+
113
+ export interface BareClause {
114
+ /** Repo-relative path of the roadmap the clause was added to. */
115
+ readonly file: string;
116
+ /** The command half, as written. */
117
+ readonly command: string;
118
+ }
119
+
120
+ /** A git invocation that FAILED. Never collapsed into an empty-but-plausible read. */
121
+ export class GitReadError extends Error {
122
+ constructor(args: readonly string[], stderr: string) {
123
+ super(`git ${args.join(' ')} failed: ${stderr.trim().split('\n')[0] ?? '(no stderr)'}`);
124
+ this.name = 'GitReadError';
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Run git, or throw.
130
+ *
131
+ * `{ ok: false, stdout: '' }` was the inherited shape and it is the wrong one
132
+ * HERE, because both readers below treat stdout as their whole corpus: a failed
133
+ * spawn, a missing ref or a `maxBuffer` overrun would have become "no merges"
134
+ * and "no clauses", and the replay would then print an authoritative-looking
135
+ * table of zeroes that the gate's own header cites as its evidence. A
136
+ * measurement that can silently measure nothing cannot justify the thing it
137
+ * measures. Throwing makes the failure reach an exit code.
138
+ */
139
+ function git(args: readonly string[], cwd: string): string {
140
+ const res = spawnSync('git', [...args], { cwd, encoding: 'utf-8', maxBuffer: 64 * 1024 * 1024 });
141
+ if (res.error !== undefined || res.status !== 0) {
142
+ throw new GitReadError(args, res.stderr ?? res.error?.message ?? '');
143
+ }
144
+ return res.stdout ?? '';
145
+ }
146
+
147
+ /** One added clause, parsed once. The gate and its report read the same list. */
148
+ export interface AddedClause {
149
+ readonly file: string;
150
+ readonly command: string;
151
+ /** The clause states an oracle — `-> 0` or `-> /regex/`. */
152
+ readonly hasExpectation: boolean;
153
+ /** The clause points at a file rather than naming something to run. */
154
+ readonly pointer: boolean;
155
+ /** States an oracle, or is exempt from stating one. The gate's predicate. */
156
+ readonly satisfied: boolean;
157
+ }
158
+
159
+ /**
160
+ * A unified-diff line that OPENS a file section — `+++ b/<path>`.
161
+ *
162
+ * Matched as the whole header rather than by a `+++` prefix, because an added
163
+ * CONTENT line whose own text begins with `++` is rendered `+++…` and a prefix
164
+ * test discards it as metadata. Narrow in practice and wrong in principle: this
165
+ * reader claimed to parse a unified diff and was reading its first character.
166
+ * `/dev/null` is the delete side and names no file.
167
+ */
168
+ const FILE_HEADER_RE = /^\+\+\+ (?:b\/(.+)|\/dev\/null)$/;
169
+
170
+ /**
171
+ * Every `verify:` clause a unified patch ADDS, each with its verdict.
172
+ *
173
+ * ONE parsed pass, deliberately. The count the gate reports and the set it
174
+ * convicts on used to be derived separately — a line filter for the first, a
175
+ * parse for the second — so a patch with ten `verify:` lines of which three
176
+ * were prose reported "scanned 10" while enforcing over 7. A scan count that
177
+ * does not describe the enforced set is the false-denominator shape this
178
+ * repository's gate-coverage manifest exists to prevent.
179
+ *
180
+ * Reads `+` lines only. A context line carrying a bare clause is a clause this
181
+ * change did not write, and convicting on it would make flipping a checkbox two
182
+ * lines above an unrelated verify line fail the author's change — the exact
183
+ * collateral that turns a diff-scoped gate back into an estate-scoped one.
184
+ */
185
+ export function addedClausesIn(patch: string): AddedClause[] {
186
+ const out: AddedClause[] = [];
187
+ let file = '';
188
+ for (const raw of patch.split('\n')) {
189
+ const fm = FILE_HEADER_RE.exec(raw);
190
+ if (fm !== null) {
191
+ file = fm[1] ?? '';
192
+ continue;
193
+ }
194
+ if (!raw.startsWith('+')) continue;
195
+ const body = raw.slice(1);
196
+ if (!body.includes('verify:')) continue;
197
+ const clause = parseVerifyClause(body);
198
+ // No clause, or the prose (MANUAL) form — prose stays legal by design,
199
+ // and an unparseable line is not a clause this gate may convict on.
200
+ if (clause === null || clause.command === null) continue;
201
+ const hasExpectation = clause.expect !== null;
202
+ const pointer = isPointer(clause.command);
203
+ out.push({ file, command: clause.command, hasExpectation, pointer, satisfied: hasExpectation || pointer });
204
+ }
205
+ return out;
206
+ }
207
+
208
+ /** The subset that fails: a command, no expectation, not a pointer. */
209
+ export function bareClausesIn(patch: string): BareClause[] {
210
+ return addedClausesIn(patch)
211
+ .filter((c) => !c.satisfied)
212
+ .map((c) => ({ file: c.file, command: c.command }));
213
+ }
214
+
215
+ export interface ReplayRow {
216
+ readonly merge: string;
217
+ readonly bare: number;
218
+ }
219
+
220
+ export interface Replay {
221
+ readonly merges: number;
222
+ readonly added: number;
223
+ readonly withExpectation: number;
224
+ /** Exempted as pointers — reported separately, never folded into the above. */
225
+ readonly pointers: number;
226
+ readonly bare: readonly BareClause[];
227
+ readonly redMerges: readonly ReplayRow[];
228
+ }
229
+
230
+ /**
231
+ * Replay the proposed rule over the last `n` merges that touched the roadmaps.
232
+ *
233
+ * @throws {GitReadError} when any git read fails. Deliberate: this function's
234
+ * output is cited as the evidence for shipping the gate, and an evidence
235
+ * producer that returns zeroes when it could not read anything is worse than
236
+ * one that does not run.
237
+ */
238
+ export function replay(repoRoot: string, n: number, ref = 'origin/main'): Replay {
239
+ const list = git(
240
+ ['log', '--merges', '--first-parent', ref, `--max-count=${String(n)}`, '--format=%h', '--', `${ROADMAPS_REL}/*.md`],
241
+ repoRoot,
242
+ );
243
+ const merges = list.split('\n').filter((s) => s.trim() !== '');
244
+ const bare: BareClause[] = [];
245
+ const redMerges: ReplayRow[] = [];
246
+ let added = 0;
247
+ let withExpectation = 0;
248
+ let pointers = 0;
249
+ for (const m of merges) {
250
+ const patch = git(['diff', '--unified=0', `${m}^1`, m, '--', ROADMAPS_REL], repoRoot);
251
+ // One parsed pass feeds both halves, so the denominator describes the
252
+ // same set the verdict is drawn from.
253
+ const clauses = addedClausesIn(patch);
254
+ added += clauses.length;
255
+ withExpectation += clauses.filter((c) => c.hasExpectation).length;
256
+ pointers += clauses.filter((c) => c.pointer).length;
257
+ const hits = clauses.filter((c) => !c.satisfied).map((c) => ({ file: c.file, command: c.command }));
258
+ bare.push(...hits);
259
+ if (hits.length > 0) redMerges.push({ merge: m, bare: hits.length });
260
+ }
261
+ return { merges: merges.length, added, withExpectation, pointers, bare, redMerges };
262
+ }
263
+
264
+ function repoRootFrom(start: string): string {
265
+ let dir = path.resolve(start);
266
+ for (;;) {
267
+ if (fs.existsSync(path.join(dir, ROADMAPS_REL))) return dir;
268
+ const up = path.dirname(dir);
269
+ if (up === dir) return path.resolve(start);
270
+ dir = up;
271
+ }
272
+ }
273
+
274
+ function renderReplay(rep: Replay): string {
275
+ const out: string[] = [];
276
+ out.push(`${GATE} --replay: ${String(rep.merges)} merge(s) replayed`);
277
+ out.push(` added command-bearing clauses ${String(rep.added)}`);
278
+ out.push(` with an expectation ${String(rep.withExpectation)}`);
279
+ out.push(` exempt as a file pointer ${String(rep.pointers)}`);
280
+ out.push(` bare (this gate would fire) ${String(rep.bare.length)}`);
281
+ const share = rep.merges === 0 ? 0 : Math.round((rep.redMerges.length / rep.merges) * 100);
282
+ out.push(` merges that would go RED ${String(rep.redMerges.length)} of ${String(rep.merges)} (${String(share)}%)`);
283
+ for (const r of [...rep.redMerges].sort((a, b) => b.bare - a.bare)) {
284
+ out.push(` ${r.merge} ${String(r.bare).padStart(3)} bare clause(s)`);
285
+ }
286
+ return out.join('\n') + '\n';
287
+ }
288
+
289
+ /** Fixtures for `--self-test`: a throwaway repo with a base commit and a change. */
290
+ function fixture(opts: { base: string; added: readonly string[] }): number {
291
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'verify-delta-'));
292
+ try {
293
+ const run = (...args: string[]): void => {
294
+ const r = spawnSync('git', args, { cwd: dir, encoding: 'utf-8' });
295
+ if (r.status !== 0) throw new Error(`git ${args.join(' ')}: ${r.stderr}`);
296
+ };
297
+ const write = (rel: string, body: string): void => {
298
+ const abs = path.join(dir, rel);
299
+ fs.mkdirSync(path.dirname(abs), { recursive: true });
300
+ fs.writeFileSync(abs, body, 'utf-8');
301
+ };
302
+ run('init', '-q', '-b', 'main');
303
+ run('config', 'user.email', 'verify@test.local');
304
+ run('config', 'user.name', 'verify');
305
+ run('config', 'commit.gpgsign', 'false');
306
+ write(`${ROADMAPS_REL}/road-to-base.md`, `# Roadmap: base\n\n## Phase 1\n\n- [ ] **1.1** s\n verify: ${opts.base}\n`);
307
+ run('add', '-A');
308
+ run('commit', '-qm', 'base');
309
+ run('checkout', '-qb', 'feat/change');
310
+ opts.added.forEach((line, i) => {
311
+ write(
312
+ `${ROADMAPS_REL}/road-to-new-${String(i)}.md`,
313
+ `# Roadmap: new ${String(i)}\n\n## Phase 1\n\n- [ ] **1.1** s\n verify: ${line}\n`,
314
+ );
315
+ });
316
+ // An edit that touches a roadmap and adds no clause. Without it the
317
+ // "nothing added" case has nothing to commit and dies in git rather than
318
+ // in the gate — and that case is the one proving the base clause is not
319
+ // re-read, so it has to reach the gate to mean anything.
320
+ write(`${ROADMAPS_REL}/road-to-base.md`, `# Roadmap: base\n\n## Phase 1\n\n- [x] **1.1** s\n verify: ${opts.base}\n`);
321
+ run('add', '-A');
322
+ run('commit', '-qm', 'change');
323
+ return runGateCli(REPO_ROOT, SCRIPT_REL, ['--base', 'main'], dir);
324
+ } finally {
325
+ fs.rmSync(dir, { recursive: true, force: true });
326
+ }
327
+ }
328
+
329
+ function selfTest(): number {
330
+ const cases: SelfTestCase[] = [
331
+ {
332
+ name: 'added clause naming a command and no expectation → reject',
333
+ expect: 'reject',
334
+ run: () => fixture({ base: '`true` -> 0', added: ['`./scripts-run src/scripts/check_claims`'] }),
335
+ },
336
+ {
337
+ name: 'added clause naming a command AND an exit expectation → accept',
338
+ expect: 'accept',
339
+ run: () => fixture({ base: '`true` -> 0', added: ['`./scripts-run src/scripts/check_claims` -> 0'] }),
340
+ },
341
+ {
342
+ name: 'added clause naming a command AND a regex expectation → accept',
343
+ expect: 'accept',
344
+ run: () => fixture({ base: '`true` -> 0', added: ['`grep -c x f.md` -> /^[1-9]/'] }),
345
+ },
346
+ {
347
+ // Prose stays legal. Forbidding it would invalidate the large
348
+ // majority of clauses in the tree, which is the decision
349
+ // `verify_clause.ts` records and this gate does not reopen.
350
+ name: 'added PROSE clause → accept (the MANUAL form is legal by design)',
351
+ expect: 'accept',
352
+ run: () => fixture({ base: '`true` -> 0', added: ['a human reads the rendered page and confirms it'] }),
353
+ },
354
+ {
355
+ // The measured carve-out: 8 of 49 bare clauses over thirty merges.
356
+ name: 'added clause naming a FILE PATH → accept (a pointer is not a command)',
357
+ expect: 'accept',
358
+ run: () => fixture({ base: '`true` -> 0', added: ['`tests/scripts/dispatch_integrity.test.ts`'] }),
359
+ },
360
+ {
361
+ name: 'a pointer with a :line suffix → accept',
362
+ expect: 'accept',
363
+ run: () => fixture({ base: '`true` -> 0', added: ['`turn_end_gate_hook.test.ts:1427`'] }),
364
+ },
365
+ {
366
+ // `cat file.md` is a command whose exit decides nothing — and it is
367
+ // still asked for an oracle, because the carve-out is about SHAPE,
368
+ // not about whether the author chose a weak command.
369
+ name: 'a command that merely cats a file → reject (the carve-out is one token only)',
370
+ expect: 'reject',
371
+ run: () => fixture({ base: '`true` -> 0', added: ['`cat docs/CLAIMS.md`'] }),
372
+ },
373
+ {
374
+ name: 'two added clauses, one bare → reject',
375
+ expect: 'reject',
376
+ run: () =>
377
+ fixture({ base: '`true` -> 0', added: ['`./scripts-run src/scripts/check_claims` -> 0', '`npx vitest run x`'] }),
378
+ },
379
+ {
380
+ // The grandfathering half: an untouched bare clause at base must not
381
+ // convict a change that added nothing.
382
+ //
383
+ // WHAT IT DOES NOT COVER, corrected on a review finding that the
384
+ // earlier wording here overstated: under `--unified=0` the unchanged
385
+ // `verify:` line does not appear in the patch at all, so this case
386
+ // does not exercise context-line handling and would stay green if
387
+ // that handling broke. The unit test `reads ADDED lines only` is
388
+ // what pins it. This case pins the weaker, still real property —
389
+ // that a change adding no clause is not convicted of the base's.
390
+ name: 'a bare clause ALREADY at base, nothing added → accept',
391
+ expect: 'accept',
392
+ run: () => fixture({ base: '`cat notes.md`', added: [] }),
393
+ },
394
+ {
395
+ // An executable script is run, not opened, however it is spelled.
396
+ name: 'an added `./path/script.ts` → reject (an invocation is not a pointer)',
397
+ expect: 'reject',
398
+ run: () => fixture({ base: '`true` -> 0', added: ['`./src/scripts/check_claims.ts`'] }),
399
+ },
400
+ ];
401
+ return runSelfTest({ gate: GATE, cases, minCases: SELF_TEST_MIN_CASES, minRejectCases: SELF_TEST_MIN_REJECT });
402
+ }
403
+
404
+ export function main(argv: string[] = process.argv.slice(2)): number {
405
+ if (argv.includes('--self-test')) return selfTest();
406
+ const repoRoot = repoRootFrom(process.cwd());
407
+
408
+ const replayIdx = argv.indexOf('--replay');
409
+ if (replayIdx !== -1) {
410
+ const raw = argv[replayIdx + 1];
411
+ const n = raw === undefined ? NaN : Number(raw);
412
+ if (!Number.isInteger(n) || n <= 0) {
413
+ process.stderr.write(`usage: ${GATE} [--base <ref>] [--replay <n>] [--self-test]\n`);
414
+ return 2;
415
+ }
416
+ try {
417
+ process.stdout.write(renderReplay(replay(repoRoot, n)));
418
+ } catch (err) {
419
+ if (err instanceof GitReadError) {
420
+ process.stderr.write(
421
+ `❌ ${GATE} --replay: ${err.message}\n` +
422
+ ' No table is printed. A replay that could not read its own history would\n' +
423
+ ' otherwise print zeroes, and those zeroes are cited as this gate\'s evidence.\n',
424
+ );
425
+ return 2;
426
+ }
427
+ throw err;
428
+ }
429
+ return 0;
430
+ }
431
+
432
+ const baseIdx = argv.indexOf('--base');
433
+ let baseRef: string | undefined;
434
+ if (baseIdx !== -1) {
435
+ const next = argv[baseIdx + 1];
436
+ if (next === undefined || next.startsWith('-')) {
437
+ process.stderr.write(`usage: ${GATE} [--base <ref>] [--replay <n>] [--self-test]\n`);
438
+ return 2;
439
+ }
440
+ baseRef = next;
441
+ }
442
+ const ref = baseRef ?? resolveBaseRef(repoRoot);
443
+ if (ref === null) {
444
+ process.stderr.write(
445
+ `❌ ${GATE}: no base ref resolved (no origin/main, no merge-commit parent).\n` +
446
+ ' This gate reads the clauses a CHANGE adds, so with no base there is no change\n' +
447
+ ' to read — and a diff-scoped gate with no diff passes every possible tree.\n' +
448
+ ' Fetch the base (`git fetch origin main`) or name it: --base origin/main\n',
449
+ );
450
+ return 2;
451
+ }
452
+
453
+ let clauses: AddedClause[];
454
+ try {
455
+ clauses = addedClausesIn(git(['diff', '--unified=0', '--find-renames', `${ref}...HEAD`, '--', ROADMAPS_REL], repoRoot));
456
+ } catch (err) {
457
+ if (err instanceof GitReadError) {
458
+ process.stderr.write(`❌ ${GATE}: ${err.message}\n The change could not be read, so nothing was checked.\n`);
459
+ return 2;
460
+ }
461
+ throw err;
462
+ }
463
+
464
+ const bare = clauses.filter((c) => !c.satisfied);
465
+ // The unit is the added CLAUSE, not the file: a change adding ten clauses to
466
+ // one roadmap scanned ten things, and reporting "1 file" would understate
467
+ // what was read. It is the SAME list the verdict is drawn from, which it was
468
+ // not in the first version — a line filter counted prose and malformed lines
469
+ // the parser then dropped, so the gate reported scanning more than it judged.
470
+ // An empty diff is a real answer here (nothing was added), never a dead
471
+ // scope, so the count is allowed to be zero.
472
+ try {
473
+ reportScanned({
474
+ gate: GATE,
475
+ scanned: clauses.length,
476
+ units: 'added verify clause(s)',
477
+ roots: [ROADMAPS_REL],
478
+ allowEmpty: 'a change that adds no verify clause has nothing to check',
479
+ });
480
+ } catch (err) {
481
+ if (err instanceof DeadScopeError) {
482
+ process.stderr.write(`❌ ${GATE}: ${err.message}\n`);
483
+ return 2;
484
+ }
485
+ throw err;
486
+ }
487
+
488
+ if (bare.length === 0) {
489
+ process.stdout.write(`✅ ${GATE}: every added verify clause states what its command must produce.\n`);
490
+ return 0;
491
+ }
492
+
493
+ for (const b of bare) {
494
+ process.stderr.write(`❌ ${b.file}: verify clause names a command and no expectation.\n ${b.command.slice(0, 160)}\n`);
495
+ }
496
+ process.stderr.write(
497
+ `\n ${String(bare.length)} added verify clause(s) cannot fail. A clause that names a command and\n` +
498
+ ' no expectation is an oracle that cannot say no: the step gets flipped on a\n' +
499
+ ' command that was never able to fail. State what the command must produce:\n' +
500
+ '\n' +
501
+ ' verify: `<cmd>` -> 0 the command must exit 0\n' +
502
+ ' verify: `<cmd>` -> /regex/ its output must match\n' +
503
+ '\n' +
504
+ ' Pick the regex form when the exit status decides nothing — `grep -c`, `wc`,\n' +
505
+ ' `head` and `cat` all exit 0 on content nobody looked at, so `-> 0` there is an\n' +
506
+ ' expectation that still cannot fail. Prose clauses stay legal and are not read\n' +
507
+ ' here; so is a backticked file path, which points rather than runs. This gate\n' +
508
+ ' reads only the clauses THIS change adds — nothing already in the tree.\n',
509
+ );
510
+ return 1;
511
+ }
512
+
513
+ function isCliEntry(): boolean {
514
+ const entry = process.argv[1];
515
+ if (entry === undefined) return false;
516
+ return pathToFileURL(path.resolve(entry)).href === pathToFileURL(fileURLToPath(import.meta.url)).href;
517
+ }
518
+
519
+ if (isCliEntry()) {
520
+ process.exit(main());
521
+ }