@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,294 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The kill-switch table says what it counts — this checks that it still does.
4
+ *
5
+ * `docs/contracts/hook-architecture-v1.md` § Kill switches enumerates every
6
+ * `AGENT_CONFIG_*` identifier a file under `src/scripts/hooks/` or
7
+ * `src/scripts/_lib/` carries, and publishes the command that reproduces the
8
+ * count. An equality between a hand-written table and a grep over a growing
9
+ * tree is exactly the claim that decays without anybody touching the document:
10
+ * the table shipped at 28 == 28 and was stale within a day, because a merge
11
+ * brought in one hook carrying one new switch. Found by an independent review,
12
+ * which is a worse way to find it than a gate.
13
+ *
14
+ * WHAT IS CHECKED, and it is the equality itself rather than a proxy for it:
15
+ * the gate runs the published enumeration and compares the SET against the
16
+ * table's rows. A set comparison rather than a count, because two errors that
17
+ * cancel — one switch added, one row for a deleted switch left behind — is the
18
+ * failure a count cannot see, and it is the one that leaves a reader chasing a
19
+ * variable nothing reads.
20
+ *
21
+ * WHAT IS DELIBERATELY NOT CHECKED: the owner class, and the prose of each row.
22
+ * Whether a switch is `maintainer` or `harness` is a judgement about who is
23
+ * expected to set it, and a gate that guessed at it would either be wrong or
24
+ * would have to encode the judgement somewhere else — which is the table.
25
+ *
26
+ * THE TWO EXCLUSIONS ARE PART OF THE CONTRACT, not a convenience.
27
+ * `__AGENT_CONFIG_BUNDLE__` and `__AGENT_CONFIG_CLI_DELEGATE__` are esbuild
28
+ * `--define` identifiers (see `package.json`'s `build:*` scripts): nothing can
29
+ * set one at runtime, so neither is a switch. They are excluded on the emitted
30
+ * token, because `grep -o` strips the leading underscores and the naive
31
+ * `grep -v __AGENT_CONFIG_BUNDLE__` therefore matches nothing.
32
+ */
33
+ import * as fs from 'node:fs';
34
+ import * as path from 'node:path';
35
+ import process from 'node:process';
36
+ import { fileURLToPath, pathToFileURL } from 'node:url';
37
+
38
+ import { GateLedger } from './_lib/gate_ledger.js';
39
+ import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
40
+ import { assertScanned, reportScanned } from './_lib/scan_scope.js';
41
+
42
+ const GATE = 'check_kill_switch_table';
43
+ const CONTRACT = path.join('docs', 'contracts', 'hook-architecture-v1.md');
44
+ const SECTION = '## Kill switches';
45
+ const ROOTS = [path.join('src', 'scripts', 'hooks'), path.join('src', 'scripts', '_lib')];
46
+
47
+ /** The esbuild defines. Not environment variables, so not switches. */
48
+ const BUILD_DEFINES: ReadonlySet<string> = new Set([
49
+ 'AGENT_CONFIG_BUNDLE__',
50
+ 'AGENT_CONFIG_CLI_DELEGATE__',
51
+ ]);
52
+
53
+ const TOKEN = /AGENT_CONFIG_[A-Z_]+/g;
54
+ /** A table row: `| \`AGENT_CONFIG_X\` | owner | … |`. */
55
+ const ROW = /^\|\s*`(AGENT_CONFIG_[A-Z_]+)`\s*\|/gm;
56
+
57
+ function walk(dir: string, out: string[]): void {
58
+ let entries: fs.Dirent[];
59
+ try {
60
+ entries = fs.readdirSync(dir, { withFileTypes: true });
61
+ } catch {
62
+ return;
63
+ }
64
+ for (const e of entries) {
65
+ const full = path.join(dir, e.name);
66
+ if (e.isDirectory()) {
67
+ walk(full, out);
68
+ } else if (e.isFile()) {
69
+ out.push(full);
70
+ }
71
+ }
72
+ }
73
+
74
+ /** Every switch name the declared roots carry, minus the build defines. */
75
+ export function switchesInTree(root: string): { names: Set<string>; files: number } {
76
+ const files: string[] = [];
77
+ for (const rel of ROOTS) {
78
+ walk(path.join(root, rel), files);
79
+ }
80
+ const names = new Set<string>();
81
+ for (const f of files) {
82
+ let text: string;
83
+ try {
84
+ text = fs.readFileSync(f, 'utf-8');
85
+ } catch {
86
+ continue;
87
+ }
88
+ for (const m of text.matchAll(TOKEN)) {
89
+ const name = m[0];
90
+ if (!BUILD_DEFINES.has(name)) names.add(name);
91
+ }
92
+ }
93
+ return { names, files: files.length };
94
+ }
95
+
96
+ /** Every switch the contract's table has a row for. */
97
+ export function switchesInTable(root: string): { names: Set<string>; present: boolean } {
98
+ let text: string;
99
+ try {
100
+ text = fs.readFileSync(path.join(root, CONTRACT), 'utf-8');
101
+ } catch {
102
+ return { names: new Set(), present: false };
103
+ }
104
+ const at = text.indexOf(SECTION);
105
+ if (at === -1) return { names: new Set(), present: false };
106
+ const rest = text.slice(at + SECTION.length);
107
+ const end = rest.indexOf('\n## ');
108
+ const section = end === -1 ? rest : rest.slice(0, end);
109
+ const names = new Set<string>();
110
+ for (const m of section.matchAll(ROW)) {
111
+ const n = m[1];
112
+ if (n !== undefined) names.add(n);
113
+ }
114
+ return { names, present: true };
115
+ }
116
+
117
+ export function main(argv: readonly string[] = process.argv.slice(2)): number {
118
+ if (argv.includes('--self-test')) return selfTest();
119
+
120
+ const root = process.cwd();
121
+ const ledger = new GateLedger(GATE);
122
+ ledger.plan(['tree-enumeration', 'table-rows', 'set-equality']);
123
+
124
+ const tree = switchesInTree(root);
125
+ const scope = {
126
+ gate: GATE,
127
+ scanned: tree.files,
128
+ units: 'source file(s)',
129
+ roots: ROOTS,
130
+ };
131
+ // BEFORE the verdict, per the empty-corpus contract: a run that read no
132
+ // source file must refuse rather than report an empty tree as agreement
133
+ // with an empty table.
134
+ assertScanned(scope);
135
+ reportScanned(scope);
136
+ ledger.complete('tree-enumeration');
137
+
138
+ const table = switchesInTable(root);
139
+ if (!table.present) {
140
+ ledger.fail('table-rows', `no "${SECTION}" section in ${CONTRACT}`);
141
+ ledger.fail('set-equality', 'nothing to compare against');
142
+ ledger.report();
143
+ process.stderr.write(
144
+ `❌ ${GATE}: ${CONTRACT} carries no "${SECTION}" section. The section is the\n` +
145
+ ' contract; a tree enumeration with nothing to compare it against is not a pass.\n',
146
+ );
147
+ return 1;
148
+ }
149
+ ledger.complete('table-rows');
150
+
151
+ const missing = [...tree.names].filter((n) => !table.names.has(n)).sort();
152
+ const extra = [...table.names].filter((n) => !tree.names.has(n)).sort();
153
+
154
+ if (missing.length === 0 && extra.length === 0) {
155
+ ledger.complete('set-equality');
156
+ ledger.report();
157
+ process.stdout.write(
158
+ `✅ ${GATE}: ${String(tree.names.size)} switch(es) in ` +
159
+ `${String(tree.files)} file(s), ${String(table.names.size)} table row(s), sets equal\n`,
160
+ );
161
+ return 0;
162
+ }
163
+
164
+ ledger.fail('set-equality', `${String(missing.length + extra.length)} mismatch(es)`);
165
+ ledger.report();
166
+ process.stderr.write(`❌ ${GATE}: the table and the tree disagree.\n\n`);
167
+ for (const n of missing) {
168
+ process.stderr.write(` MISSING ROW ${n} — read by the tree, absent from the table\n`);
169
+ }
170
+ for (const n of extra) {
171
+ process.stderr.write(
172
+ ` STALE ROW ${n} — a table row for a name the tree no longer carries\n`,
173
+ );
174
+ }
175
+ process.stderr.write(
176
+ `\nAdd or remove the row in ${CONTRACT} § Kill switches. A switch with no row is\n` +
177
+ 'one an operator cannot find; a row with no switch is one they will set expecting\n' +
178
+ 'an effect. If a name is genuinely read outside the two declared roots, the row\n' +
179
+ 'stays and says so — the row still has to exist.\n',
180
+ );
181
+ return 1;
182
+ }
183
+
184
+ // ---------------------------------------------------------------------------
185
+ // Self-test — the gate proving its own rejections still fire
186
+ // ---------------------------------------------------------------------------
187
+
188
+ function fixture(body: { tree: string; table: string }): string {
189
+ const dir = fs.mkdtempSync(path.join(process.cwd(), '.kst-'));
190
+ fs.mkdirSync(path.join(dir, 'src', 'scripts', 'hooks'), { recursive: true });
191
+ fs.mkdirSync(path.join(dir, 'src', 'scripts', '_lib'), { recursive: true });
192
+ fs.mkdirSync(path.join(dir, 'docs', 'contracts'), { recursive: true });
193
+ fs.writeFileSync(path.join(dir, 'src', 'scripts', 'hooks', 'a.ts'), body.tree, 'utf-8');
194
+ fs.writeFileSync(path.join(dir, CONTRACT), body.table, 'utf-8');
195
+ return dir;
196
+ }
197
+
198
+ function table(...names: string[]): string {
199
+ const rows = names.map((n) => `| \`${n}\` | maintainer | does a thing | a.ts:1 |`).join('\n');
200
+ return `# Contract\n\n${SECTION}\n\n| Switch | Owner | What | Read at |\n|---|---|---|---|\n${rows}\n\n## Stability\n\nBeta.\n`;
201
+ }
202
+
203
+ function selfTest(): number {
204
+ const repoRoot = process.cwd();
205
+ const script = path.join('src', 'scripts', 'check_kill_switch_table.ts');
206
+ const dirs: string[] = [];
207
+ const run = (body: { tree: string; table: string }): number => {
208
+ const dir = fixture(body);
209
+ dirs.push(dir);
210
+ return runGateCli(repoRoot, script, [], dir);
211
+ };
212
+
213
+ const cases: SelfTestCase[] = [
214
+ {
215
+ name: 'equal sets pass',
216
+ expect: 'accept',
217
+ run: () =>
218
+ run({
219
+ tree: "const A = process.env['AGENT_CONFIG_ALPHA'];\n",
220
+ table: table('AGENT_CONFIG_ALPHA'),
221
+ }),
222
+ },
223
+ {
224
+ name: 'a switch with no row is rejected',
225
+ expect: 'reject',
226
+ run: () =>
227
+ run({
228
+ tree: "const A = process.env['AGENT_CONFIG_ALPHA'];\nconst B = process.env['AGENT_CONFIG_BETA'];\n",
229
+ table: table('AGENT_CONFIG_ALPHA'),
230
+ }),
231
+ },
232
+ {
233
+ name: 'a row with no switch is rejected',
234
+ expect: 'reject',
235
+ run: () =>
236
+ run({
237
+ tree: "const A = process.env['AGENT_CONFIG_ALPHA'];\n",
238
+ table: table('AGENT_CONFIG_ALPHA', 'AGENT_CONFIG_GONE'),
239
+ }),
240
+ },
241
+ {
242
+ name: 'one added and one stale do NOT cancel — the count would hide it',
243
+ expect: 'reject',
244
+ run: () =>
245
+ run({
246
+ tree: "const B = process.env['AGENT_CONFIG_BETA'];\n",
247
+ table: table('AGENT_CONFIG_ALPHA'),
248
+ }),
249
+ },
250
+ {
251
+ name: 'the esbuild defines are excluded, not counted',
252
+ expect: 'accept',
253
+ run: () =>
254
+ run({
255
+ tree:
256
+ 'declare const __AGENT_CONFIG_BUNDLE__: boolean;\n'
257
+ + 'declare const __AGENT_CONFIG_CLI_DELEGATE__: boolean;\n'
258
+ + "const A = process.env['AGENT_CONFIG_ALPHA'];\n",
259
+ table: table('AGENT_CONFIG_ALPHA'),
260
+ }),
261
+ },
262
+ {
263
+ name: 'a missing section is rejected, never read as an empty table',
264
+ expect: 'reject',
265
+ run: () =>
266
+ run({
267
+ tree: "const A = process.env['AGENT_CONFIG_ALPHA'];\n",
268
+ table: '# Contract\n\n## Stability\n\nBeta.\n',
269
+ }),
270
+ },
271
+ ];
272
+
273
+ try {
274
+ return runSelfTest({ gate: GATE, cases, minCases: 6, minRejectCases: 4 });
275
+ } finally {
276
+ for (const d of dirs) fs.rmSync(d, { recursive: true, force: true });
277
+ }
278
+ }
279
+
280
+ function isCliEntry(): boolean {
281
+ const argv1 = process.argv[1];
282
+ if (argv1 === undefined) return false;
283
+ try {
284
+ return (
285
+ fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(argv1))
286
+ );
287
+ } catch {
288
+ return pathToFileURL(argv1).href === import.meta.url;
289
+ }
290
+ }
291
+
292
+ if (isCliEntry()) {
293
+ process.exit(main());
294
+ }
@@ -607,7 +607,13 @@ function _checkAppendOnly(base: string | null, findings: Finding[]): void {
607
607
  '--no-color',
608
608
  ref,
609
609
  '--',
610
- 'agents/memory/intake/',
610
+ // The JSONL drops, not the directory. `INTAKE_GLOB`, this module's
611
+ // docstring and every fixture in the suite all scope this check to
612
+ // `*.jsonl`; asking git for the directory made it govern the tracked
613
+ // skeleton too, so editing the README that documents the append-only
614
+ // rule was reported as a violation of it. `:(glob)` is explicit rather
615
+ // than relying on the default pathspec magic.
616
+ ':(glob)agents/memory/intake/*.jsonl',
611
617
  ]);
612
618
  if (rc !== 0) {
613
619
  findings.push(new Finding(INTAKE_GLOB, 0, 'warning', `append-only: git diff failed vs ${ref}`));
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * The placeholder-drift ratchet — foreign placeholder syntaxes in prose may
4
+ * shrink, never grow.
5
+ *
6
+ * road-to-an-invocation-contract-that-reaches-the-wire 1.2.
7
+ *
8
+ * WHAT IT GATES, AND WHAT IT DELIBERATELY DOES NOT
9
+ *
10
+ * It fails on GROWTH of the foreign forms only. It never fails on the absolute
11
+ * number, and it never fails on the plurality form — so holding at the seeded
12
+ * counts is permanently green, and nothing here asks for a rewrite of a working
13
+ * body. That is the whole of Risk 2's mitigation: a committed number naming two
14
+ * syntaxes as foreign reads like a canon ruling whose obvious next move is
15
+ * rewriting those bodies, and a gate that is green at the seed removes the
16
+ * pressure to do it.
17
+ *
18
+ * THE SEED IS MEASURED, NOT COPIED
19
+ *
20
+ * The roadmap's step text says "seeded at the measured 4 and 2". The operative
21
+ * word is MEASURED: under the census's published unit — a token in PROSE,
22
+ * outside fenced blocks, indented blocks and inline code spans — the corpus
23
+ * carries different numbers, because the source figures counted tokens inside
24
+ * demonstrated code (JS template literals in `playwright-testing`, HCL in
25
+ * `terragrunt`, a table-cell marker the prose is talking ABOUT in
26
+ * `livewire-architect`). The seed below is this tree's own reading. The
27
+ * reasoning lives in `report_invocation_surface.ts`'s module header, and the
28
+ * per-file breakdown is in the census artifact, so the definition is arguable
29
+ * rather than merely asserted.
30
+ *
31
+ * A NOTE ON WHAT A ZERO SEED MEANS. `{{…}}` seeds at zero. That is not "the
32
+ * check has nothing to do" — a zero-seeded ratchet is the strictest form of
33
+ * this gate, because the first occurrence is growth. It is also the cheapest
34
+ * possible moment to hold a line: no existing body has to change for it.
35
+ *
36
+ * Exit codes: 0 within the ratchet · 1 growth · 2 the corpus could not be read.
37
+ */
38
+
39
+ import fs from 'node:fs';
40
+ import os from 'node:os';
41
+ import path from 'node:path';
42
+ import { fileURLToPath, pathToFileURL } from 'node:url';
43
+
44
+ import { GateLedger } from './_lib/gate_ledger.js';
45
+ import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
46
+ import { assertScanned, reportScanned } from './_lib/scan_scope.js';
47
+ import { SYNTAXES, type SyntaxId, census } from './report_invocation_surface.js';
48
+
49
+ const _HERE = fileURLToPath(import.meta.url);
50
+ const ROOT = path.resolve(path.dirname(_HERE), '..', '..');
51
+
52
+ export const GATE = 'check_placeholder_drift';
53
+
54
+ /** Where the seed lives, so a deliberate change is a reviewable diff. */
55
+ export const BUDGET_REL = path.join('src', 'config', 'placeholder-drift-budget.json');
56
+
57
+ export interface Budget {
58
+ readonly seeded_at: string;
59
+ readonly note: string;
60
+ readonly ceilings: Readonly<Partial<Record<SyntaxId, number>>>;
61
+ }
62
+
63
+ export function readBudget(root: string): Budget | null {
64
+ const p = path.join(root, BUDGET_REL);
65
+ if (!fs.existsSync(p)) return null;
66
+ try {
67
+ return JSON.parse(fs.readFileSync(p, 'utf8')) as Budget;
68
+ } catch {
69
+ return null;
70
+ }
71
+ }
72
+
73
+ export interface Finding {
74
+ readonly syntax: SyntaxId;
75
+ readonly ceiling: number;
76
+ readonly measured: number;
77
+ }
78
+
79
+ /** Which foreign syntaxes exceed their ceiling. Plurality forms are skipped. */
80
+ export function findings(
81
+ occurrences: Readonly<Record<SyntaxId, number>>,
82
+ budget: Budget,
83
+ ): Finding[] {
84
+ const out: Finding[] = [];
85
+ for (const s of SYNTAXES) {
86
+ if (s.canonical) continue;
87
+ const ceiling = budget.ceilings[s.id];
88
+ if (ceiling === undefined) continue;
89
+ const measured = occurrences[s.id] ?? 0;
90
+ if (measured > ceiling) out.push({ syntax: s.id, ceiling, measured });
91
+ }
92
+ return out;
93
+ }
94
+
95
+ export function main(argv: readonly string[]): number {
96
+ if (argv.includes('--self-test')) return selfTest();
97
+ const rootIdx = argv.indexOf('--root');
98
+ const root = rootIdx === -1 ? ROOT : (argv[rootIdx + 1] ?? ROOT);
99
+
100
+ const budget = readBudget(root);
101
+ if (budget === null) {
102
+ process.stderr.write(
103
+ `❌ ${GATE}: ${BUDGET_REL} is missing or unreadable. A ratchet that cannot read ` +
104
+ 'its own seed must not pass — it would be a green nobody earned.\n',
105
+ );
106
+ return 2;
107
+ }
108
+
109
+ const c = census(root);
110
+ const foreign = SYNTAXES.filter((s) => !s.canonical);
111
+ const ledger = new GateLedger(GATE);
112
+ ledger.plan(foreign.map((s) => s.id));
113
+
114
+ const found = findings(c.occurrences, budget);
115
+ for (const s of foreign) {
116
+ const f = found.find((x) => x.syntax === s.id);
117
+ if (f === undefined) ledger.complete(s.id);
118
+ else ledger.fail(s.id, `${String(f.measured)} occurrence(s) against a ceiling of ${String(f.ceiling)}`);
119
+ }
120
+
121
+ // A gate that read nothing has not passed. This fires BEFORE the verdict,
122
+ // because certifying against an empty corpus is the false green the coverage
123
+ // manifest exists to refuse — named by the provider-diverse ratification
124
+ // review as one condition that would have flipped its verdict.
125
+ assertScanned({ gate: GATE, scanned: c.rows.length, units: 'artifact(s)', roots: [BUDGET_REL, 'dist/agent-src/commands', 'src/skills'] });
126
+
127
+ reportScanned({
128
+ gate: GATE,
129
+ scanned: c.rows.length,
130
+ units: 'artifact(s)',
131
+ roots: [BUDGET_REL],
132
+ });
133
+ ledger.report();
134
+
135
+ if (found.length > 0) {
136
+ for (const f of found) {
137
+ const label = SYNTAXES.find((s) => s.id === f.syntax)?.label ?? f.syntax;
138
+ process.stdout.write(
139
+ `❌ ${GATE}: \`${label}\` grew to ${String(f.measured)} prose occurrence(s), ceiling ${String(f.ceiling)}.\n`,
140
+ );
141
+ }
142
+ process.stdout.write(
143
+ '\nThe ratchet walks DOWN only. Use the plurality form instead, or — if the new ' +
144
+ `occurrence is genuinely right — lower nothing and raise the ceiling in ` +
145
+ `\`${BUDGET_REL}\` in the same change, with the reason in the diff.\n` +
146
+ 'Counting unit and the per-file breakdown: ' +
147
+ '`./scripts-run src/scripts/report_invocation_surface --write`.\n',
148
+ );
149
+ return 1;
150
+ }
151
+
152
+ process.stdout.write(
153
+ `✅ ${GATE}: foreign placeholder syntaxes within their ratchet ` +
154
+ `(${foreign.map((s) => `${s.label} ${String(c.occurrences[s.id])}/${String(budget.ceilings[s.id] ?? 0)}`).join(' · ')}).\n`,
155
+ );
156
+ return 0;
157
+ }
158
+
159
+ /**
160
+ * A ratchet that cannot be shown to move is a number, not a gate. Each rejecting
161
+ * case is one occurrence over a ceiling; the accepting cases are the seed itself
162
+ * and a shrink, because a suite that only proves failures proves a gate that is
163
+ * merely loud.
164
+ */
165
+ function selfTest(): number {
166
+ const plant = (name: string, bodies: readonly string[], ceilings: Record<string, number>): string => {
167
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), `drift-${name}-`));
168
+ fs.mkdirSync(path.join(dir, 'src', 'config'), { recursive: true });
169
+ fs.writeFileSync(
170
+ path.join(dir, 'src', 'config', 'placeholder-drift-budget.json'),
171
+ JSON.stringify({ seeded_at: '2026-09-29', note: 'fixture', ceilings }, null, 2),
172
+ 'utf-8',
173
+ );
174
+ bodies.forEach((body, i) => {
175
+ const d = path.join(dir, 'src', 'skills', `probe-${String(i)}`);
176
+ fs.mkdirSync(d, { recursive: true });
177
+ fs.writeFileSync(path.join(d, 'SKILL.md'), `---\nname: probe-${String(i)}\n---\n\n${body}\n`, 'utf-8');
178
+ });
179
+ return dir;
180
+ };
181
+ const run = (root: string): number =>
182
+ runGateCli(ROOT, path.join('src', 'scripts', 'check_placeholder_drift.ts'), ['--root', root], ROOT);
183
+
184
+ return runSelfTest({
185
+ gate: GATE,
186
+ minCases: 5,
187
+ minRejectCases: 3,
188
+ cases: [
189
+ {
190
+ name: 'at the seed it is green',
191
+ expect: 'accept',
192
+ run: () => run(plant('seed', ['Uses {{a}} once.'], { 'double-brace': 1, 'angle-upper': 0 })),
193
+ },
194
+ {
195
+ name: 'below the seed it stays green — it never fails on the absolute number',
196
+ expect: 'accept',
197
+ run: () => run(plant('shrink', ['no placeholders'], { 'double-brace': 1, 'angle-upper': 0 })),
198
+ },
199
+ {
200
+ name: 'one occurrence over the ceiling fails',
201
+ expect: 'reject',
202
+ run: () => run(plant('grow', ['Uses {{a}} and {{b}}.'], { 'double-brace': 1, 'angle-upper': 0 })),
203
+ },
204
+ {
205
+ name: 'a zero ceiling makes the first occurrence growth',
206
+ expect: 'reject',
207
+ run: () => run(plant('zero', ['Uses <NAME> here.'], { 'double-brace': 0, 'angle-upper': 0 })),
208
+ },
209
+ {
210
+ name: 'an unreadable budget refuses rather than certifying a green',
211
+ expect: 'reject',
212
+ run: () => runGateCli(ROOT, path.join('src', 'scripts', 'check_placeholder_drift.ts'),
213
+ ['--root', fs.mkdtempSync(path.join(os.tmpdir(), 'drift-nobudget-'))], ROOT),
214
+ },
215
+ ],
216
+ });
217
+ }
218
+
219
+ if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
220
+ process.exit(main(process.argv.slice(2)));
221
+ }