@event4u/agent-config 16.3.0 → 16.4.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 (486) 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 +251 -0
  5. package/README.md +2 -2
  6. package/agents/templates/.ai-council.yml.example +26 -8
  7. package/dist/agent-src/commands/analyze/inbox.md +10 -7
  8. package/dist/agent-src/commands/bug/investigate.md +1 -1
  9. package/dist/agent-src/commands/commit/in-chunks.md +40 -31
  10. package/dist/agent-src/commands/commit.md +72 -33
  11. package/dist/agent-src/commands/condense.md +2 -8
  12. package/dist/agent-src/commands/council/debate.md +11 -7
  13. package/dist/agent-src/commands/council/default.md +10 -9
  14. package/dist/agent-src/commands/council.md +1 -1
  15. package/dist/agent-src/commands/estimate-ticket.md +1 -1
  16. package/dist/agent-src/commands/feature/explore.md +3 -3
  17. package/dist/agent-src/commands/feature/plan.md +1 -1
  18. package/dist/agent-src/commands/fix/ci.md +17 -3
  19. package/dist/agent-src/commands/fix/commit-messages.md +48 -23
  20. package/dist/agent-src/commands/fix/pr-comments.md +3 -6
  21. package/dist/agent-src/commands/implement-ticket.md +3 -3
  22. package/dist/agent-src/commands/memory/add.md +4 -16
  23. package/dist/agent-src/commands/memory/load.md +5 -6
  24. package/dist/agent-src/commands/memory/promote.md +3 -16
  25. package/dist/agent-src/commands/mission/upgrade.md +3 -2
  26. package/dist/agent-src/commands/optimize/agents-dir.md +2 -2
  27. package/dist/agent-src/commands/optimize/deep.md +4 -2
  28. package/dist/agent-src/commands/optimize/rtk.md +4 -26
  29. package/dist/agent-src/commands/pr/create/description-only.md +18 -15
  30. package/dist/agent-src/commands/pr/create.md +42 -34
  31. package/dist/agent-src/commands/pr/merge.md +136 -9
  32. package/dist/agent-src/commands/prepare-for-review.md +13 -11
  33. package/dist/agent-src/commands/project/analyze.md +7 -35
  34. package/dist/agent-src/commands/refine-ticket.md +1 -1
  35. package/dist/agent-src/commands/review/changes.md +14 -19
  36. package/dist/agent-src/commands/roadmap/next.md +10 -1
  37. package/dist/agent-src/commands/roadmap/process-full.md +52 -38
  38. package/dist/agent-src/commands/roadmap/resolve-blockers.md +64 -14
  39. package/dist/agent-src/commands/worktree/create.md +7 -3
  40. package/dist/agent-src/commands/worktree/verify.md +2 -1
  41. package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +5 -3
  42. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +7 -9
  43. package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +8 -6
  44. package/dist/agent-src/contexts/contracts/frugality-charter.md +8 -5
  45. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +1 -1
  46. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +0 -1
  47. package/dist/agent-src/contexts/execution/evidence-discipline.md +2 -2
  48. package/dist/agent-src/contexts/execution/non-interactive-contract.md +5 -8
  49. package/dist/agent-src/contexts/execution/rdp-gate.md +4 -4
  50. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +9 -8
  51. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +67 -52
  52. package/dist/agent-src/contexts/execution/subagent-routing.md +8 -8
  53. package/dist/agent-src/contexts/execution/subagent-steering.md +6 -4
  54. package/dist/agent-src/contexts/execution/terminal-states.md +2 -2
  55. package/dist/agent-src/contexts/execution/toolchain-resolver.md +4 -10
  56. package/dist/agent-src/contexts/subagent-configuration.md +1 -1
  57. package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
  58. package/dist/agent-src/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
  59. package/dist/agent-src/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
  60. package/dist/agent-src/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
  61. package/dist/agent-src/guidelines/agent-infra/layered-settings.md +13 -1
  62. package/dist/agent-src/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  63. package/dist/agent-src/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
  64. package/dist/agent-src/guidelines/agent-infra/size-and-scope.md +36 -0
  65. package/dist/agent-src/guidelines/php/git.md +15 -2
  66. package/dist/agent-src/rules/active-remediation.md +0 -1
  67. package/dist/agent-src/rules/analysis-skill-routing.md +0 -1
  68. package/dist/agent-src/rules/architecture.md +0 -1
  69. package/dist/agent-src/rules/artifact-drafting-protocol.md +0 -1
  70. package/dist/agent-src/rules/artifact-engagement-recording.md +0 -1
  71. package/dist/agent-src/rules/augment-edit-discipline.md +0 -1
  72. package/dist/agent-src/rules/autonomous-execution.md +0 -1
  73. package/dist/agent-src/rules/brand-consistency.md +0 -1
  74. package/dist/agent-src/rules/brand-source-of-truth.md +0 -1
  75. package/dist/agent-src/rules/broken-access-control.md +0 -1
  76. package/dist/agent-src/rules/cli-output-handling.md +0 -1
  77. package/dist/agent-src/rules/code-comment-discipline.md +0 -1
  78. package/dist/agent-src/rules/code-provenance.md +0 -1
  79. package/dist/agent-src/rules/command-suggestion-policy.md +0 -1
  80. package/dist/agent-src/rules/commit-conventions.md +1 -2
  81. package/dist/agent-src/rules/communication-through-line.md +1 -2
  82. package/dist/agent-src/rules/content-quoting-floor.md +1 -2
  83. package/dist/agent-src/rules/context-hygiene.md +5 -5
  84. package/dist/agent-src/rules/copilot-routing.md +1 -2
  85. package/dist/agent-src/rules/council-availability.md +4 -4
  86. package/dist/agent-src/rules/cross-source-consistency.md +4 -6
  87. package/dist/agent-src/rules/decision-revisit-gate.md +2 -3
  88. package/dist/agent-src/rules/delegation-policy.md +2 -3
  89. package/dist/agent-src/rules/design-fidelity.md +0 -1
  90. package/dist/agent-src/rules/design-review-after-ui-write.md +3 -3
  91. package/dist/agent-src/rules/devcontainer-routing.md +1 -2
  92. package/dist/agent-src/rules/doc-screenshot-hygiene.md +0 -1
  93. package/dist/agent-src/rules/docker-commands.md +0 -1
  94. package/dist/agent-src/rules/domain-adoption-policy.md +0 -1
  95. package/dist/agent-src/rules/domain-safety-disclaimer.md +0 -1
  96. package/dist/agent-src/rules/domain-safety-pii.md +0 -1
  97. package/dist/agent-src/rules/domain-safety-retention.md +0 -1
  98. package/dist/agent-src/rules/downstream-changes.md +0 -1
  99. package/dist/agent-src/rules/engineering-safety-floor.md +0 -1
  100. package/dist/agent-src/rules/external-code-graph-interop.md +0 -1
  101. package/dist/agent-src/rules/external-reference-deep-dive.md +0 -1
  102. package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -2
  103. package/dist/agent-src/rules/finance-safety-floor.md +0 -1
  104. package/dist/agent-src/rules/fix-what-you-see.md +6 -32
  105. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +0 -1
  106. package/dist/agent-src/rules/git-history-discipline.md +1 -2
  107. package/dist/agent-src/rules/guidelines.md +0 -1
  108. package/dist/agent-src/rules/history-discipline.md +0 -1
  109. package/dist/agent-src/rules/icon-consistency.md +0 -1
  110. package/dist/agent-src/rules/image-likeness-and-rights.md +0 -1
  111. package/dist/agent-src/rules/improve-before-implement.md +0 -1
  112. package/dist/agent-src/rules/invite-challenge.md +0 -1
  113. package/dist/agent-src/rules/laravel-routing.md +1 -2
  114. package/dist/agent-src/rules/laravel-translations.md +0 -1
  115. package/dist/agent-src/rules/legal-safety-floor.md +0 -1
  116. package/dist/agent-src/rules/lethal-trifecta-guard.md +0 -1
  117. package/dist/agent-src/rules/linked-projects-onboarding-gate.md +0 -1
  118. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +0 -1
  119. package/dist/agent-src/rules/markdown-safe-codeblocks.md +0 -1
  120. package/dist/agent-src/rules/media-governance-routing.md +1 -2
  121. package/dist/agent-src/rules/media-sync-ground-truth.md +0 -1
  122. package/dist/agent-src/rules/minimal-safe-diff.md +0 -1
  123. package/dist/agent-src/rules/missing-skill-recovery.md +0 -1
  124. package/dist/agent-src/rules/missing-tool-handling.md +0 -1
  125. package/dist/agent-src/rules/model-recommendation.md +0 -1
  126. package/dist/agent-src/rules/neighbour-precedence.md +64 -0
  127. package/dist/agent-src/rules/no-attribution-footers.md +0 -1
  128. package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +0 -1
  129. package/dist/agent-src/rules/no-pr-progress-comments.md +0 -1
  130. package/dist/agent-src/rules/no-roadmap-references.md +0 -1
  131. package/dist/agent-src/rules/notes-first-reasoning.md +0 -1
  132. package/dist/agent-src/rules/onboarding-gate.md +0 -1
  133. package/dist/agent-src/rules/output-discipline.md +0 -1
  134. package/dist/agent-src/rules/package-ci-checks.md +0 -1
  135. package/dist/agent-src/rules/persona-governance.md +2 -3
  136. package/dist/agent-src/rules/php-coding.md +0 -1
  137. package/dist/agent-src/rules/prefer-enums-over-literals.md +0 -1
  138. package/dist/agent-src/rules/preservation-guard.md +0 -1
  139. package/dist/agent-src/rules/provider-lifecycle-discipline.md +2 -3
  140. package/dist/agent-src/rules/question-not-instruction.md +0 -1
  141. package/dist/agent-src/rules/reviewer-awareness.md +0 -1
  142. package/dist/agent-src/rules/roadmap-ci-steps-policy.md +0 -1
  143. package/dist/agent-src/rules/roadmap-progress-sync.md +3 -6
  144. package/dist/agent-src/rules/role-mode-adherence.md +0 -1
  145. package/dist/agent-src/rules/rule-type-governance.md +0 -1
  146. package/dist/agent-src/rules/runtime-safety.md +0 -1
  147. package/dist/agent-src/rules/scale-discipline.md +0 -1
  148. package/dist/agent-src/rules/secret-vcs-guard.md +0 -1
  149. package/dist/agent-src/rules/security-sensitive-stop.md +0 -1
  150. package/dist/agent-src/rules/self-repair-loop.md +0 -1
  151. package/dist/agent-src/rules/senior-engineering-discipline.md +0 -1
  152. package/dist/agent-src/rules/session-canary.md +0 -1
  153. package/dist/agent-src/rules/settings-ask-protocol.md +5 -6
  154. package/dist/agent-src/rules/size-enforcement.md +0 -1
  155. package/dist/agent-src/rules/skill-improvement-trigger.md +2 -3
  156. package/dist/agent-src/rules/skill-quality.md +0 -1
  157. package/dist/agent-src/rules/slash-command-routing-policy.md +0 -1
  158. package/dist/agent-src/rules/source-confidentiality.md +0 -1
  159. package/dist/agent-src/rules/source-discovery-gate.md +0 -1
  160. package/dist/agent-src/rules/source-of-truth.md +0 -1
  161. package/dist/agent-src/rules/spreadsheet-source-quality.md +1 -2
  162. package/dist/agent-src/rules/strategy-safety-floor.md +0 -1
  163. package/dist/agent-src/rules/symfony-routing.md +1 -2
  164. package/dist/agent-src/rules/think-before-action.md +0 -1
  165. package/dist/agent-src/rules/token-budget-discipline.md +12 -46
  166. package/dist/agent-src/rules/token-efficiency.md +0 -1
  167. package/dist/agent-src/rules/token-optimizer-maintenance.md +0 -1
  168. package/dist/agent-src/rules/tool-safety.md +0 -1
  169. package/dist/agent-src/rules/ui-audit-gate.md +1 -2
  170. package/dist/agent-src/rules/untrusted-input-defense.md +0 -1
  171. package/dist/agent-src/rules/upstream-proposal.md +0 -1
  172. package/dist/agent-src/rules/user-interaction.md +0 -1
  173. package/dist/agent-src/rules/user-interrupt-priority.md +0 -1
  174. package/dist/agent-src/scripts/gate_budget.ts +47 -23
  175. package/dist/agent-src/scripts/gate_execute.ts +12 -4
  176. package/dist/agent-src/skills/ai-council/SKILL.md +7 -4
  177. package/dist/agent-src/skills/ai-council/references/cost-and-redaction.md +21 -11
  178. package/dist/agent-src/skills/ai-council/references/procedure.md +12 -6
  179. package/dist/agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -1
  180. package/dist/agent-src/skills/bug-analyzer/SKILL.md +1 -1
  181. package/dist/agent-src/skills/command-routing/SKILL.md +3 -4
  182. package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +127 -139
  183. package/dist/agent-src/skills/corpus-grounding/ATTRIBUTION.md +39 -0
  184. package/dist/agent-src/skills/corpus-grounding/SKILL.md +8 -2
  185. package/dist/agent-src/skills/database/data/manifest.json +2 -2
  186. package/dist/agent-src/skills/database/data/query-tuning.csv +13 -13
  187. package/dist/agent-src/skills/design-system-capture/SKILL.md +0 -3
  188. package/dist/agent-src/skills/estimate-ticket/SKILL.md +1 -1
  189. package/dist/agent-src/skills/feature-planning/SKILL.md +1 -1
  190. package/dist/agent-src/skills/git-workflow/SKILL.md +44 -44
  191. package/dist/agent-src/skills/git-workflow/references/branch-update.md +312 -0
  192. package/dist/agent-src/skills/git-workflow/references/commit-subject.md +205 -0
  193. package/dist/agent-src/skills/jira-integration/SKILL.md +3 -3
  194. package/dist/agent-src/skills/merge-conflicts/SKILL.md +10 -4
  195. package/dist/agent-src/skills/po-discovery/SKILL.md +1 -1
  196. package/dist/agent-src/skills/refine-ticket/SKILL.md +4 -4
  197. package/dist/agent-src/skills/roadmap-writing/SKILL.md +2 -2
  198. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +4 -2
  199. package/dist/agent-src/skills/source-discovery/SKILL.md +1 -1
  200. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +3 -1
  201. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
  202. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +1 -1
  203. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +2 -2
  204. package/dist/agent-src/templates/AGENTS.md +1 -1
  205. package/dist/agent-src/templates/agent-settings.md +46 -129
  206. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +3 -3
  207. package/dist/agent-src/templates/command.md +2 -2
  208. package/dist/agent-src/templates/roadmaps.md +6 -1
  209. package/dist/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
  210. package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
  211. package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
  212. package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
  213. package/dist/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
  214. package/dist/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
  215. package/dist/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
  216. package/dist/agent-src/templates/skill.md +1 -1
  217. package/dist/cli/registry.js +1 -0
  218. package/dist/cli-delegate/check_update_banner.js +195 -119
  219. package/dist/cli-delegate/{chunk-TRI6DQZ6.js → chunk-5GPULQBE.js} +60 -42
  220. package/dist/cli-delegate/{chunk-JQVYKIZA.js → chunk-6SRJTYJS.js} +33 -177
  221. package/dist/cli-delegate/chunk-6V5FMA3P.js +186 -0
  222. package/dist/cli-delegate/chunk-6YQC2HLF.js +415 -0
  223. package/dist/cli-delegate/{chunk-E4XIZDIB.js → chunk-7HKRE54K.js} +1 -64
  224. package/dist/cli-delegate/{chunk-NQ7WT43P.js → chunk-AED2VQGM.js} +65 -11
  225. package/dist/cli-delegate/{chunk-7HQ52DHU.js → chunk-AL3RZ22D.js} +1 -1
  226. package/dist/cli-delegate/{chunk-DBH4AHDK.js → chunk-ED7KCMLB.js} +9 -11
  227. package/dist/cli-delegate/{chunk-NXEILF2K.js → chunk-F3QDG2GT.js} +481 -72
  228. package/dist/cli-delegate/{chunk-CQWX336L.js → chunk-G5VVIZRC.js} +3 -3
  229. package/dist/cli-delegate/{chunk-JY2I2DXV.js → chunk-H76PHZBI.js} +137 -60
  230. package/dist/cli-delegate/chunk-IAYTIIQW.js +67 -0
  231. package/dist/cli-delegate/{chunk-LIYTLH6O.js → chunk-KXXWJTDO.js} +5 -10
  232. package/dist/cli-delegate/{chunk-T7L2QK3K.js → chunk-LQOCRFWT.js} +1 -1
  233. package/dist/cli-delegate/{chunk-S4YWNRKO.js → chunk-MDPPKQCQ.js} +34 -1
  234. package/dist/cli-delegate/{chunk-S4UMZNES.js → chunk-MSUL5NYP.js} +5 -5
  235. package/dist/cli-delegate/chunk-OAFSJBHH.js +272 -0
  236. package/dist/cli-delegate/{chunk-GKE7ZVFA.js → chunk-PWX7CKMD.js} +1 -1
  237. package/dist/cli-delegate/{chunk-NDJLNC6Q.js → chunk-T6BP34WI.js} +1 -0
  238. package/dist/cli-delegate/{chunk-RQNNW7IF.js → chunk-T7XSJSUQ.js} +433 -632
  239. package/dist/cli-delegate/{chunk-EEHDXSYD.js → chunk-WQWXGIWB.js} +12 -273
  240. package/dist/cli-delegate/{chunk-QLDHIPWR.js → chunk-XQTPXKFA.js} +1 -1
  241. package/dist/cli-delegate/cmd_analyze_session.js +223 -43
  242. package/dist/cli-delegate/cmd_brand_status.js +3 -2
  243. package/dist/cli-delegate/cmd_conformance.js +105 -35
  244. package/dist/cli-delegate/cmd_converge.js +3 -3
  245. package/dist/cli-delegate/cmd_doctor.js +15 -12
  246. package/dist/cli-delegate/cmd_doctor_neighbours.js +11 -4
  247. package/dist/cli-delegate/cmd_explain.js +43 -19
  248. package/dist/cli-delegate/cmd_export.js +10 -10
  249. package/dist/cli-delegate/cmd_git_convention.js +1851 -0
  250. package/dist/cli-delegate/cmd_handoff.js +40 -21
  251. package/dist/cli-delegate/cmd_mcp_available.js +3 -2
  252. package/dist/cli-delegate/cmd_migrate.js +3 -3
  253. package/dist/cli-delegate/cmd_packs_active.js +4 -3
  254. package/dist/cli-delegate/cmd_prune.js +10 -10
  255. package/dist/cli-delegate/cmd_route_audit.js +7 -7
  256. package/dist/cli-delegate/cmd_route_explain.js +5 -5
  257. package/dist/cli-delegate/cmd_session_recycle.js +9 -7
  258. package/dist/cli-delegate/cmd_settings_check.js +54 -7
  259. package/dist/cli-delegate/cmd_settings_get.js +18 -8
  260. package/dist/cli-delegate/cmd_settings_migrate.js +10 -10
  261. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  262. package/dist/cli-delegate/cmd_sync.js +10 -10
  263. package/dist/cli-delegate/cmd_uninstall.js +10 -10
  264. package/dist/cli-delegate/cmd_update.js +7 -7
  265. package/dist/cli-delegate/cmd_upgrade.js +7 -7
  266. package/dist/cli-delegate/cmd_validate.js +10 -10
  267. package/dist/cli-delegate/cmd_versions.js +5 -5
  268. package/dist/cli-delegate/gate_budget.js +1 -1
  269. package/dist/cli-delegate/gate_execute.js +2 -2
  270. package/dist/cli-delegate/roadmap_gates.js +2 -2
  271. package/dist/discovery/deprecation-report.md +1 -1
  272. package/dist/discovery/discovery-manifest.json +129 -90
  273. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  274. package/dist/discovery/discovery-manifest.summary.md +3 -3
  275. package/dist/discovery/dormancy-report.md +1 -1
  276. package/dist/discovery/orphan-report.md +1 -1
  277. package/dist/discovery/packs.json +24 -9
  278. package/dist/discovery/trust-report.md +3 -3
  279. package/dist/discovery/workspaces.json +5 -4
  280. package/dist/hooks/dispatch.js +2151 -1820
  281. package/dist/hooks/dispatch.sha256 +1 -1
  282. package/dist/install/install.mjs +462 -431
  283. package/dist/install/installThinLayer.js +40 -12
  284. package/dist/install/installedRuleLinks.js +105 -19
  285. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  286. package/dist/mcp/mcp-cloudflare-catalogue.json +2 -2
  287. package/dist/mcp/registry-manifest.json +5 -5
  288. package/dist/mcp/server.json +2 -2
  289. package/dist/mcp/server.mjs +2702 -1995
  290. package/dist/router.json +1 -1
  291. package/dist/scripts/_lib/agent_settings.js +15 -120
  292. package/dist/scripts/_lib/compile_time_toggles.js +12 -21
  293. package/dist/scripts/_lib/git_convention.js +232 -0
  294. package/dist/scripts/_lib/global_deploy_inventory.js +730 -0
  295. package/dist/scripts/_lib/installed_layer.js +344 -18
  296. package/dist/scripts/_lib/package_root.js +68 -0
  297. package/dist/scripts/_lib/rule_law_section.js +1 -1
  298. package/dist/scripts/_lib/settings_removed_keys.js +168 -0
  299. package/dist/scripts/_lib/thin_rules.js +80 -3
  300. package/dist/server/app.js +2 -1
  301. package/dist/server/gitKeysGate.js +105 -0
  302. package/dist/server/routes/settings.js +67 -8
  303. package/dist/server/routes/wizard.js +4 -0
  304. package/dist/server/schemas/settings.js +23 -81
  305. package/dist/shared/skillRanking.js +30 -4
  306. package/dist/ui/assets/{index-Cwq4d0hX.js → index-C3djEJah.js} +2 -2
  307. package/dist/ui/index.html +1 -1
  308. package/docs/MIGRATION.md +72 -1
  309. package/docs/contracts/settings-classes.md +35 -65
  310. package/docs/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
  311. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
  312. package/docs/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
  313. package/docs/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
  314. package/docs/guidelines/agent-infra/layered-settings.md +13 -1
  315. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  316. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
  317. package/docs/guidelines/agent-infra/size-and-scope.md +36 -0
  318. package/docs/guidelines/php/git.md +15 -2
  319. package/package.json +1 -1
  320. package/src/agent-src/scripts/gate_budget.ts +47 -23
  321. package/src/agent-src/scripts/gate_execute.ts +12 -4
  322. package/src/agent-src/templates/AGENTS.md +1 -1
  323. package/src/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
  324. package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
  325. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
  326. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
  327. package/src/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
  328. package/src/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
  329. package/src/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
  330. package/src/config/agent-settings.template.yml +79 -312
  331. package/src/config/agents-paths.yml +16 -0
  332. package/src/config/assurance-capability-registry.json +7 -3
  333. package/src/config/ci-local-parity.yml +3 -0
  334. package/src/config/continuity-surface.json +3 -3
  335. package/src/config/discovery/packs.yml +17 -1
  336. package/src/config/evaluator-budgets.json +19 -6
  337. package/src/config/gate-coverage.yml +65 -23
  338. package/src/config/gate-violation-baselines.json +53 -13
  339. package/src/config/gitignore-block.txt +19 -0
  340. package/src/config/hook-bundle-budget.json +1 -1
  341. package/src/config/release-gate-locality.yml +2 -1
  342. package/src/config/routing-coverage-seed.json +48 -6
  343. package/src/config/rule-law-ceilings.json +12 -6
  344. package/src/config/rule-obligations.json +833 -0
  345. package/src/install/installThinLayer.ts +76 -10
  346. package/src/install/installedRuleLinks.ts +105 -17
  347. package/src/scripts/_cli/cmd_analyze_session.ts +9 -15
  348. package/src/scripts/_cli/cmd_conformance.ts +13 -2
  349. package/src/scripts/_cli/cmd_doctor.ts +10 -10
  350. package/src/scripts/_cli/cmd_doctor_neighbours.ts +133 -0
  351. package/src/scripts/_cli/cmd_explain.ts +72 -14
  352. package/src/scripts/_cli/cmd_git_convention.ts +637 -0
  353. package/src/scripts/_cli/cmd_settings_check.ts +66 -8
  354. package/src/scripts/_cli/cmd_settings_get.ts +18 -3
  355. package/src/scripts/_cli/doctor_execution.ts +72 -1
  356. package/src/scripts/_dispatch.bash +37 -2
  357. package/src/scripts/_lib/agent_settings.ts +15 -124
  358. package/src/scripts/_lib/blocked_by_marker.ts +1 -1
  359. package/src/scripts/_lib/compile_time_toggles.ts +12 -21
  360. package/src/scripts/_lib/dispatch_import_closure.ts +163 -0
  361. package/src/scripts/_lib/git_base_ref.ts +92 -0
  362. package/src/scripts/_lib/git_convention.ts +291 -0
  363. package/src/scripts/_lib/git_convention_carrier.ts +389 -0
  364. package/src/scripts/_lib/git_convention_grammar.ts +246 -0
  365. package/src/scripts/_lib/git_convention_measure.ts +344 -0
  366. package/src/scripts/_lib/global_deploy_inventory.ts +74 -0
  367. package/src/scripts/_lib/graph_feeder_record.ts +236 -13
  368. package/src/scripts/_lib/installed_layer.ts +448 -23
  369. package/src/scripts/_lib/knowledge_global.ts +14 -1
  370. package/src/scripts/_lib/module_reach.ts +456 -0
  371. package/src/scripts/_lib/neighbour_contradictions.ts +236 -0
  372. package/src/scripts/_lib/neighbour_tool_use.ts +8 -10
  373. package/src/scripts/_lib/ratification_artifact.ts +220 -1
  374. package/src/scripts/_lib/ratification_subject.ts +92 -0
  375. package/src/scripts/_lib/release_findings_ingest.ts +15 -7
  376. package/src/scripts/_lib/release_highlights.ts +5 -0
  377. package/src/scripts/_lib/rule_law_section.ts +1 -1
  378. package/src/scripts/_lib/rule_obligations.ts +205 -0
  379. package/src/scripts/_lib/self_repair.ts +1 -1
  380. package/src/scripts/_lib/settings_removed_keys.ts +173 -0
  381. package/src/scripts/_lib/test_red_state.ts +5 -0
  382. package/src/scripts/_lib/thin_rules.ts +83 -3
  383. package/src/scripts/_lib/touched_file_quality.ts +142 -6
  384. package/src/scripts/_lib/worker_budget.ts +1 -1
  385. package/src/scripts/adr/regenerate_index.ts +16 -1
  386. package/src/scripts/ai_council/config.ts +7 -7
  387. package/src/scripts/ai_council/modification_review.ts +100 -0
  388. package/src/scripts/ai_council/modification_review_questions.ts +90 -0
  389. package/src/scripts/ai_council/orchestrator.ts +5 -5
  390. package/src/scripts/ai_council/spend_gate.ts +18 -7
  391. package/src/scripts/ai_team/config.ts +11 -16
  392. package/src/scripts/audit_user_type_axis.ts +20 -8
  393. package/src/scripts/bench_ab_clone.ts +1 -2
  394. package/src/scripts/bench_concern_spawn_path.ts +129 -0
  395. package/src/scripts/bench_graph_feeder_latency.ts +584 -0
  396. package/src/scripts/check_agent_artifact_location.ts +36 -0
  397. package/src/scripts/check_branch_freshness.ts +147 -24
  398. package/src/scripts/check_enforcement_coverage.ts +130 -0
  399. package/src/scripts/check_evaluator_budgets.ts +4 -0
  400. package/src/scripts/check_finding_dispositions.ts +88 -25
  401. package/src/scripts/check_gate_coverage.ts +4 -3
  402. package/src/scripts/check_gate_reachability.ts +48 -1
  403. package/src/scripts/check_generator_sync.ts +48 -0
  404. package/src/scripts/check_hook_bundle_composition.ts +107 -0
  405. package/src/scripts/check_kernel_edit_ratified.ts +86 -6
  406. package/src/scripts/check_pack_size.ts +1 -1
  407. package/src/scripts/check_release_manifest_content.ts +189 -0
  408. package/src/scripts/check_standing_rule_delivery.ts +96 -0
  409. package/src/scripts/check_suppression_hygiene.ts +2 -5
  410. package/src/scripts/ci_settle.ts +42 -5
  411. package/src/scripts/classify_merge_risk.ts +320 -0
  412. package/src/scripts/closure_scan.ts +91 -1
  413. package/src/scripts/command_suggester/settings.ts +8 -108
  414. package/src/scripts/command_suggester/types.ts +4 -5
  415. package/src/scripts/consumer_matrix.ts +102 -0
  416. package/src/scripts/context_hygiene_hook.ts +13 -23
  417. package/src/scripts/cost/preflight.mjs +12 -1
  418. package/src/scripts/council_cli.ts +7 -7
  419. package/src/scripts/dispatch_r2_reviewer.ts +24 -11
  420. package/src/scripts/explain_run.ts +8 -13
  421. package/src/scripts/generate_git_convention_grammar.ts +127 -0
  422. package/src/scripts/generate_host_cost_table.ts +20 -3
  423. package/src/scripts/handoff_context_hook.ts +86 -37
  424. package/src/scripts/hook_manifest.json +1 -1
  425. package/src/scripts/hook_manifest.yaml +25 -6
  426. package/src/scripts/hooks/block_config_weakening.ts +48 -5
  427. package/src/scripts/hooks/block_plumbing_writes.ts +8 -4
  428. package/src/scripts/hooks/concern_registry.ts +2 -0
  429. package/src/scripts/hooks/delegation_nudge_hook.ts +2 -3
  430. package/src/scripts/hooks/evidence_independence.ts +12 -4
  431. package/src/scripts/hooks/mcp_usage_observation_hook.ts +121 -0
  432. package/src/scripts/hooks/push_settle_hook.ts +4 -3
  433. package/src/scripts/hooks/rule_inject_hook.ts +44 -3
  434. package/src/scripts/hooks/state_io.ts +8 -4
  435. package/src/scripts/hooks/telemetry_usage_hook.ts +7 -46
  436. package/src/scripts/hooks/turn_end_gate_hook.ts +1 -0
  437. package/src/scripts/install-hooks.sh +42 -14
  438. package/src/scripts/install.ts +7 -31
  439. package/src/scripts/lint_blocker_citations.ts +198 -0
  440. package/src/scripts/lint_evidence_artifacts.ts +9 -0
  441. package/src/scripts/lint_hook_concern_budget.ts +10 -21
  442. package/src/scripts/lint_pack_boundaries.ts +406 -28
  443. package/src/scripts/lint_roadmap_blockers.ts +282 -29
  444. package/src/scripts/lint_roadmap_complexity.ts +4 -2
  445. package/src/scripts/lint_rule_law_section.ts +151 -21
  446. package/src/scripts/lint_rule_skill_pack_reach.ts +17 -0
  447. package/src/scripts/lint_settings_classes.ts +1 -1
  448. package/src/scripts/lint_ticked_unmet_criteria.ts +165 -0
  449. package/src/scripts/lint_workflow_security.ts +12 -1
  450. package/src/scripts/measure_skill_ranker_baseline.ts +5 -0
  451. package/src/scripts/model_rule_injection.ts +3 -3
  452. package/src/scripts/onboarding_gate_hook.ts +7 -6
  453. package/src/scripts/print_required_checks.ts +15 -3
  454. package/src/scripts/probe_host_compliance.ts +33 -5
  455. package/src/scripts/probe_turnaround.ts +183 -3
  456. package/src/scripts/ratification_header.ts +77 -0
  457. package/src/scripts/refusal_envelope.ts +138 -0
  458. package/src/scripts/release_publication.ts +29 -3
  459. package/src/scripts/report_dispatch_import_closure.ts +76 -0
  460. package/src/scripts/report_installed_rule_links.ts +118 -1
  461. package/src/scripts/report_module_reach.ts +212 -0
  462. package/src/scripts/report_obligation_mechanism.ts +16 -18
  463. package/src/scripts/report_parked_blockers.ts +222 -0
  464. package/src/scripts/report_required_checks_drift.ts +196 -0
  465. package/src/scripts/report_skill_ranker_confusion.ts +103 -2
  466. package/src/scripts/report_standing_payload_by_host.ts +1 -1
  467. package/src/scripts/routing_doctor.ts +2 -2
  468. package/src/scripts/schemas/agent-settings.schema.json +17 -31
  469. package/src/scripts/schemas/command.schema.json +1 -1
  470. package/src/scripts/schemas/skill.schema.json +1 -1
  471. package/src/scripts/self_review_gate.ts +39 -2
  472. package/src/scripts/skill_tools/score_skill_relevance.ts +28 -19
  473. package/src/scripts/sync_pr_branch.ts +403 -132
  474. package/src/scripts/trigger_eval_grandfather.json +0 -16
  475. package/src/server/schemas/settings.ts +33 -177
  476. package/src/shared/skillRanking.ts +53 -4
  477. package/dist/cli-delegate/chunk-NYX3L2PZ.js +0 -99
  478. package/src/scripts/_lib/config_chain.ts +0 -477
  479. package/src/scripts/_lib/conformance_report.ts +0 -403
  480. package/src/scripts/_lib/eval_discrimination.ts +0 -95
  481. package/src/scripts/_lib/evaluator_promotion.ts +0 -225
  482. package/src/scripts/_lib/file_slicer.ts +0 -117
  483. package/src/scripts/_lib/legacy_boundary_map.ts +0 -228
  484. package/src/scripts/_lib/minimality_tiebreak.ts +0 -168
  485. package/src/scripts/_lib/overbuild_lens_contract.ts +0 -196
  486. package/src/scripts/_lib/role_split.ts +0 -338
@@ -126,12 +126,13 @@ const _PATH_KEYS: readonly string[] = ['file_path', 'path', 'target_file', 'file
126
126
  export type ConfigKind = 'allowlist' | 'advisory' | 'class-c' | null;
127
127
 
128
128
  /**
129
- * Project settings files whose keys this guard fences. User-global files are
129
+ * Project settings files, and the committed git-convention carrier (ADR-283),
130
+ * whose keys this guard fences. User-global files are
130
131
  * never in reach — the hook only sees a path a tool call named, and the writes
131
132
  * that reach `~/.event4u/` go through `settings:set`, which applies its own
132
133
  * per-key refusal.
133
134
  */
134
- const CLASS_C_BASENAMES: readonly string[] = ['.agent-settings.yml', '.agent-settings.yaml', 'settings.json'];
135
+ const CLASS_C_BASENAMES: readonly string[] = ['.agent-settings.yml', '.agent-settings.yaml', '.git-convention.yml', 'settings.json'];
135
136
 
136
137
  /** Where the class contract lives, relative to the package root. */
137
138
  export const SETTINGS_CLASSES_RELATIVE = 'docs/contracts/settings-classes.md';
@@ -382,10 +383,25 @@ export interface Decision {
382
383
  * unreadable for the length of one tool call, which is a bypass with no
383
384
  * authorisation step in it.
384
385
  *
386
+ * The edit forms it models: `Write` (`content`), `Edit` (`old_string` /
387
+ * `new_string`, with `replace_all`) and `MultiEdit` (an `edits` list of those
388
+ * pairs, applied in order).
389
+ *
385
390
  * WHAT IT CANNOT SEE: an edit applied through a shell redirect rather than an
386
391
  * edit tool — `EDIT_TOOLS` is the corpus, and the shell shapes are
387
392
  * `block_plumbing_writes`' subject, not this one.
388
393
  */
394
+ /** The host writes `new_string` verbatim; `String.replace` would expand `$&`-style tokens. */
395
+ function _replaceFirstLiteral(text: string, from: string, to: string): string {
396
+ const at = text.indexOf(from);
397
+ return text.slice(0, at) + to + text.slice(at + from.length);
398
+ }
399
+
400
+ /** An empty `old_string` is the host's create form, which `split('')` does not model. */
401
+ function _applyEdit(text: string, from: string, to: string, all: unknown): string {
402
+ return all === true && from !== '' ? text.split(from).join(to) : _replaceFirstLiteral(text, from, to);
403
+ }
404
+
389
405
  export function classCVerdict(
390
406
  ti: JsonObject,
391
407
  on_disk: string | null,
@@ -397,11 +413,22 @@ export function classCVerdict(
397
413
  const content = ti['content'];
398
414
  const oldStr = ti['old_string'];
399
415
  const newStr = ti['new_string'];
416
+ const forms = [content !== undefined, oldStr !== undefined || newStr !== undefined, ti['edits'] !== undefined];
417
+ if (forms.filter(Boolean).length > 1) {
418
+ return (
419
+ `${rel_path}: this edit carries more than one edit form (content, old_string/new_string, edits), ` +
420
+ 'so the guard cannot tell which one the host will run and no key can be cleared. ' +
421
+ 'Re-send it as one form, or write the change through `agent-config settings:set`.'
422
+ );
423
+ }
424
+ // A file that does not exist yet is created by an edit with an empty
425
+ // `old_string`, so it is modelled as empty text rather than left unchecked.
426
+ const current = on_disk ?? '';
400
427
  let afterText: string | null = null;
401
428
  if (typeof content === 'string') {
402
429
  afterText = content;
403
- } else if (typeof oldStr === 'string' && typeof newStr === 'string' && on_disk !== null) {
404
- if (!on_disk.includes(oldStr)) return null; // the edit will not apply
430
+ } else if (typeof oldStr === 'string' && typeof newStr === 'string') {
431
+ if (!current.includes(oldStr)) return null; // the edit will not apply
405
432
  // `replace_all` is the host's own flag and it changes WHICH text the
406
433
  // edit produces. Modelling only the first occurrence let a
407
434
  // `replace_all` edit whose SECOND occurrence is the Class C one pass
@@ -417,7 +444,23 @@ export function classCVerdict(
417
444
  '`agent-config settings:set`.'
418
445
  );
419
446
  }
420
- afterText = all === true ? on_disk.split(oldStr).join(newStr) : on_disk.replace(oldStr, newStr);
447
+ afterText = _applyEdit(current, oldStr, newStr, all);
448
+ } else if (ti['edits'] !== undefined && !Array.isArray(ti['edits'])) {
449
+ return `${rel_path}: this MultiEdit carries an edit the guard cannot interpret, so the text it would produce is unknown and no key can be cleared. Re-send it as plain edits, or write the change through \`agent-config settings:set\`.`;
450
+ } else if (Array.isArray(ti['edits'])) {
451
+ // MultiEdit applies its pairs in order and applies none when one misses.
452
+ let text = current;
453
+ for (const e of ti['edits']) {
454
+ const o = _isObject(e) ? e['old_string'] : undefined;
455
+ const n = _isObject(e) ? e['new_string'] : undefined;
456
+ const a = _isObject(e) ? e['replace_all'] : undefined;
457
+ if (typeof o !== 'string' || typeof n !== 'string' || (a !== undefined && typeof a !== 'boolean')) {
458
+ return `${rel_path}: this MultiEdit carries an edit the guard cannot interpret, so the text it would produce is unknown and no key can be cleared. Re-send it as plain edits, or write the change through \`agent-config settings:set\`.`;
459
+ }
460
+ if (!text.includes(o)) return null;
461
+ text = _applyEdit(text, o, n, a);
462
+ }
463
+ afterText = text;
421
464
  }
422
465
  if (afterText === null) return null;
423
466
 
@@ -5,10 +5,14 @@
5
5
  * road-to-a-kernel-that-guards-its-plumbing 1.2 — the other half of a
6
6
  * deliberate split, and the split is the whole design:
7
7
  *
8
- * · plumbing SOURCES (`hook_manifest.yaml`, `host_lowering.yaml`, the
9
- * `*-dispatcher.sh` trampolines, both hook budget files) are edited
10
- * legitimately all the time. They carry a RECORD — the ADR-268 § 4
11
- * ratification gate, path set extended by step 1.1 — not a deny.
8
+ * · plumbing SOURCES are edited legitimately all the time. They carry a
9
+ * RECORD — the ADR-268 § 4 ratification gate — not a deny. Which files
10
+ * count is NOT listed here: it is `check_kernel_edit_ratified`'s
11
+ * `PLUMBING_SOURCE_RE` plus the verdict-deciding modules of the
12
+ * dispatcher's import closure (`derivedPlumbing`), computed at run time.
13
+ * A copy of that list here drifted once already — it named the pattern
14
+ * and missed the policy module a refactor moved out of the dispatcher —
15
+ * so this header points at the set instead of restating it.
12
16
  * · plumbing BUILD OUTPUTS have no legitimate hand edit at all. They carry a
13
17
  * DENY, which is this file.
14
18
  *
@@ -65,6 +65,7 @@ import { main as suggestionCaptureMain } from './suggestion_capture_hook.js';
65
65
  import { main as uiRouteNudgeMain } from './ui_route_nudge_hook.js';
66
66
  import { main as orchestrationRecordMain } from './orchestration_record_hook.js';
67
67
  import { main as telemetryUsageMain } from './telemetry_usage_hook.js';
68
+ import { main as mcpUsageObservationMain } from './mcp_usage_observation_hook.js';
68
69
  import { main as telemetryFlushMain } from './telemetry_flush_hook.js';
69
70
  import { main as delegationNudgeMain } from './delegation_nudge_hook.js';
70
71
  import { main as skillRouteMain } from './skill_route_hook.js';
@@ -132,6 +133,7 @@ export const CONCERN_REGISTRY: Readonly<Record<string, ConcernMain>> = {
132
133
  'src/scripts/hooks/ui_route_nudge_hook.ts': uiRouteNudgeMain as ConcernMain,
133
134
  'src/scripts/hooks/orchestration_record_hook.ts': orchestrationRecordMain as ConcernMain,
134
135
  'src/scripts/hooks/telemetry_usage_hook.ts': telemetryUsageMain as ConcernMain,
136
+ 'src/scripts/hooks/mcp_usage_observation_hook.ts': mcpUsageObservationMain as ConcernMain,
135
137
  'src/scripts/hooks/telemetry_flush_hook.ts': telemetryFlushMain as ConcernMain,
136
138
  'src/scripts/hooks/delegation_nudge_hook.ts': delegationNudgeMain as ConcernMain,
137
139
  'src/scripts/hooks/skill_route_hook.ts': skillRouteMain as ConcernMain,
@@ -320,11 +320,10 @@ export function resolveActivation(
320
320
  const emergency = (settings["emergency"] ?? {}) as Record<string, unknown>;
321
321
  const halted = emergency["orchestration_halt"] === true;
322
322
  const host_manifest = probeHostCapabilities(hostId);
323
- const sub = (settings["subagents"] ?? {}) as Record<string, unknown>;
324
- const downshift = sub["downshift"] !== false;
325
323
  return {
326
324
  activation: { halted, subagent_spawn: host_manifest.subagent_spawn },
327
- downshift,
325
+ // Fixed on: the `subagents.downshift` key was retired with this default.
326
+ downshift: true,
328
327
  separate_quota_pool: host_manifest.separate_quota_pool,
329
328
  agentTeams: host_manifest.agent_teams,
330
329
  };
@@ -53,6 +53,7 @@ import { atomic_write_json } from "./state_io.js";
53
53
  import { readHookStdin } from "./hook_stdin.js";
54
54
  import { isCodePath, isTestPath } from "../_lib/test_delta.js";
55
55
  import { EXIT_ALLOW, EXIT_BLOCK } from './exit_codes.js';
56
+ import { ledgerFileFor } from "../git_authorization_hook.js";
56
57
 
57
58
  // MUST equal dispatch_hook.EXIT_BLOCK. The dispatcher's internal ladder is
58
59
  // 0 allow / 1 block / 2 warn — NOT the 2-means-block shape a PreToolUse guard
@@ -198,11 +199,18 @@ interface DispatchState extends JsonObject {
198
199
  evaluations: JsonValue[];
199
200
  }
200
201
 
201
- /** The current user turn's stamp, or "" when no ledger exists yet. */
202
- function _ledgerStamp(consumer_root: string): string {
202
+ /**
203
+ * The current user turn's stamp, or "" when no ledger exists yet.
204
+ *
205
+ * Reads the ledger through the writer's own `ledgerFileFor(session_id)`
206
+ * rather than the legacy session-less path: with a session id the writer
207
+ * never touches that path, so reading it unconditionally found an empty or
208
+ * stale file and the stamp never changed per turn.
209
+ */
210
+ function _ledgerStamp(consumer_root: string, session_id: string): string {
203
211
  try {
204
212
  const raw = fs.readFileSync(
205
- path.join(consumer_root, "agents", "state", "git-authorization.json"),
213
+ path.join(consumer_root, ledgerFileFor(session_id)),
206
214
  "utf8",
207
215
  );
208
216
  const d = JSON.parse(raw) as Record<string, unknown>;
@@ -421,7 +429,7 @@ export function run(stdin_text: string, options: { consumer_root: string }): num
421
429
  // in a session blocked every later one. The only per-user-turn stamp that
422
430
  // actually exists is `detected_at` in the authorization ledger, which
423
431
  // `git_authorization_hook` rewrites on every `user_prompt_submit`.
424
- const turnMarker = `${session_id}:${_ledgerStamp(options.consumer_root)}`;
432
+ const turnMarker = `${session_id}:${_ledgerStamp(options.consumer_root, session_id)}`;
425
433
  if (state.session_id !== turnMarker) {
426
434
  state.session_id = turnMarker;
427
435
  state.turn_started_at = new Date().toISOString();
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Foreign MCP tool names, observed on `post_tool_use`
4
+ * (road-to-neighbours-that-pull-their-weight step 3.3, decision D12).
5
+ *
6
+ * DEFAULT-ON LOCAL OBSERVATION, AND IT BYPASSES THE TELEMETRY OPT-IN. Stated
7
+ * here first because it is the one property a reader must not have to infer.
8
+ * This concern writes on every install, whether or not the org telemetry switch
9
+ * was ever enabled, because the file it writes feeds `doctor neighbours` — a
10
+ * report the consumer runs on their own tree — and gating it on an org switch
11
+ * would publish `0` on every install that never enabled one. Nothing here is
12
+ * telemetry: no transport reads the file, it is never spooled, and it lives
13
+ * under gitignored `agents/runtime/` (decision D9).
14
+ *
15
+ * WHAT IS RECORDED: the tool NAME, `mcp__<server>__<tool>`, and the UTC day it
16
+ * was last seen. Nothing else — no arguments, no response, no session id, no
17
+ * host. The dispatcher serves this concern a REDUCED payload: its manifest
18
+ * entry declares no `needs_payload_bodies`, so `tool_input` and `tool_response`
19
+ * arrive as size-only stubs and cannot be recorded even by mistake.
20
+ *
21
+ * RETENTION. A map keyed by tool name, rewritten in place at most once per day
22
+ * per name — bounded by the neighbour's tool surface, so it needs no TTL job.
23
+ * The reader applies a 30-day window; older entries stop counting. Deleting
24
+ * `agents/runtime/neighbour-tool-use.json` erases all of it.
25
+ *
26
+ * Why a concern of its own rather than a branch of `telemetry-usage`: that
27
+ * concern's dispatcher filter is `tools: [Skill]` and matches exactly, so a
28
+ * branch there was never called for an MCP tool; and a concern named for
29
+ * opt-in telemetry should not also carry default-on local collection. Both
30
+ * were the AI council's findings (2026-10-02); the owner chose this shape.
31
+ *
32
+ * No `tools:` filter on the manifest entry, deliberately: MCP tool names are
33
+ * not enumerable and matching is exact. The prefix test below is the filter.
34
+ *
35
+ * Exit code is ALWAYS 0 and nothing is printed — it observes, never gates.
36
+ */
37
+ import * as path from 'node:path';
38
+ import { fileURLToPath, pathToFileURL } from 'node:url';
39
+ import * as fs from 'node:fs';
40
+
41
+ import { FOREIGN_TOOL_USE_REL, MCP_TOOL_PREFIX, resolveStoreRoot, usageDay } from '../_lib/neighbour_tool_use.js';
42
+ import { update_json_under_lock } from './state_io.js';
43
+ import { readHookStdin } from './hook_stdin.js';
44
+ import { EXIT_ALLOW } from './exit_codes.js';
45
+
46
+ type JsonObject = { [k: string]: unknown };
47
+
48
+ function isObject(v: unknown): v is JsonObject {
49
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
50
+ }
51
+
52
+ /** The MCP tool name off the envelope, or null for anything else. */
53
+ export function mcpToolName(envelope: unknown): string | null {
54
+ if (!isObject(envelope)) return null;
55
+ const payload = isObject(envelope['payload']) ? envelope['payload'] : envelope;
56
+ const v = payload['tool_name'] ?? payload['toolName'] ?? payload['tool'];
57
+ return typeof v === 'string' && v.startsWith(MCP_TOOL_PREFIX) && v.length > MCP_TOOL_PREFIX.length ? v : null;
58
+ }
59
+
60
+ function record(envelope: unknown, consumer_root: string): number {
61
+ try {
62
+ const tool = mcpToolName(envelope);
63
+ if (tool === null) return EXIT_ALLOW;
64
+ const day = usageDay(new Date());
65
+ update_json_under_lock<Record<string, string>>(
66
+ path.join(resolveStoreRoot(consumer_root), FOREIGN_TOOL_USE_REL),
67
+ (seen) => (seen[tool] === day ? null : ({ ...seen, [tool]: day } as Record<string, string>)),
68
+ { blocking: false },
69
+ );
70
+ } catch {
71
+ return EXIT_ALLOW;
72
+ }
73
+ return EXIT_ALLOW;
74
+ }
75
+
76
+ export function run(stdin_text: string, options: { consumer_root: string }): number {
77
+ let envelope: unknown;
78
+ try {
79
+ const raw = stdin_text.trim();
80
+ if (!raw) return EXIT_ALLOW;
81
+ envelope = JSON.parse(raw);
82
+ } catch {
83
+ return EXIT_ALLOW;
84
+ }
85
+ return record(envelope, options.consumer_root);
86
+ }
87
+
88
+ function _root(envelope: unknown): string {
89
+ if (isObject(envelope)) {
90
+ const v = envelope['cwd'] ?? envelope['workspace_root'] ?? envelope['project_root'];
91
+ if (typeof v === 'string' && v) return v;
92
+ }
93
+ return process.cwd();
94
+ }
95
+
96
+ export function main(): number {
97
+ const raw = readHookStdin();
98
+ let envelope: unknown = {};
99
+ try {
100
+ envelope = raw.trim() ? JSON.parse(raw) : {};
101
+ } catch {
102
+ return EXIT_ALLOW;
103
+ }
104
+ return record(envelope, _root(envelope));
105
+ }
106
+
107
+ // Bundle-safety: guarded at the call site so esbuild drops the whole entry
108
+ // check inside the shared hook bundle (see telemetry_usage_hook.ts, D11).
109
+ declare const __AGENT_CONFIG_BUNDLE__: boolean | undefined;
110
+ function _isCliEntry(): boolean {
111
+ if (process.argv[1] === undefined) return false;
112
+ if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
113
+ try {
114
+ return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(process.argv[1]));
115
+ } catch {
116
+ return false;
117
+ }
118
+ }
119
+ if (typeof __AGENT_CONFIG_BUNDLE__ === 'undefined' || !__AGENT_CONFIG_BUNDLE__) {
120
+ if (_isCliEntry()) process.exit(main());
121
+ }
@@ -195,9 +195,10 @@ export function buildReminder(branch: string, pr: number | null): { reason: stri
195
195
  ` 2. Red? Read only the failing part:\n` +
196
196
  ` gh run view --job <id> --log-failed | grep -E '×|FAIL|Error'\n` +
197
197
  ` then fix it and push again (fix-what-you-see: the author is irrelevant).\n` +
198
- ` 3. Still red after 3 attempts on the same target, or blocked on something ` +
199
- `only the user can decide — stop and say so, with the three attempts named ` +
200
- `(autonomous-execution N=3).\n\n` +
198
+ ` 3. 3 attempts on the same target triggers autonomous-execution's ` +
199
+ `execution.fix_loop_max strategy shift — change approach, never stop. ` +
200
+ `Blocked on something only the user can decide is the one branch that halts: ` +
201
+ `say so, with what was tried named.\n\n` +
201
202
  `Handing the user a red PR with its cause named and unfixed is not a delivery ` +
202
203
  `either. If you are deliberately leaving this WIP, say that in the reply — ` +
203
204
  `silence is what this hook exists to stop.`;
@@ -147,7 +147,11 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
147
147
 
148
148
  import { hookSectionEnabled } from '../_lib/hook_settings.js';
149
149
  import * as user_global_paths from '../_lib/user_global_paths.js';
150
- import { deliversBodies, resolveLeanProjection } from '../_lib/lean_projection_mode.js';
150
+ import {
151
+ deliversBodies,
152
+ installerThinsHost,
153
+ resolveLeanProjection,
154
+ } from '../_lib/lean_projection_mode.js';
151
155
  import { enforcement_class_from_frontmatter } from '../_lib/obligation_frequency.js';
152
156
  import {
153
157
  appendDelivered,
@@ -168,7 +172,8 @@ import {
168
172
  } from '../_lib/rule_injection.js';
169
173
  import { readConsequenceClass, stubLawIds } from '../_lib/rule_consequence_class.js';
170
174
  import { lawText, ruleBody } from '../_lib/rule_law_section.js';
171
- import { hostRuleLayerIds } from '../_lib/rule_layer_overlap.js';
175
+ import { hostRuleLayerDirs, hostRuleLayerIds } from '../_lib/rule_layer_overlap.js';
176
+ import { is_thin_entry } from '../_lib/thin_rules.js';
172
177
  import { readHookStdin } from './hook_stdin.js';
173
178
  import { EXIT_ALLOW, EXIT_WARN } from './exit_codes.js';
174
179
 
@@ -853,6 +858,9 @@ export function buildInjection(
853
858
  openFiles: string[] | null,
854
859
  command: string | null,
855
860
  seen: Set<string>,
861
+ // `false` only for an offline measurement of WHAT the concern delivers,
862
+ // which must not read the measuring machine's installed rule files.
863
+ servedOnce = true,
856
864
  ): Injection | null {
857
865
  let router;
858
866
  try {
@@ -878,14 +886,47 @@ export function buildInjection(
878
886
  // `hostRuleLayerIds`. No filter then, because scoping to an empty set would
879
887
  // re-create the silence step 1.1 repaired.
880
888
  const scope = hostRuleLayerIds(root);
881
- const matches = matchTierRules(router, prompt, openFiles, command).filter(
889
+ let matches = matchTierRules(router, prompt, openFiles, command).filter(
882
890
  (m) => !seen.has(m.id) && (scope === null || scope.has(m.id)),
883
891
  );
884
892
  if (matches.length === 0) return null;
893
+ // ONE COPY (`road-to-a-default-install-served-once` 1.1). The gate opens on
894
+ // the template's `delivery`, but the installer thins only on an explicit
895
+ // user-global choice, so a default install carries every routed body in
896
+ // its rule files already. A rule whose installed copy is a full body gets
897
+ // nothing; a stub still gets its body. Asked only off the consent path, so
898
+ // an opted-in install's delivery is unchanged byte for byte.
899
+ if (servedOnce && scope !== null && !installerThinsHost(DELIVERY_HOST, { packageRoot: ruleSources(root).pkg })) {
900
+ const full = installedFullIds(root, matches.map((m) => m.id));
901
+ matches = matches.filter((m) => !full.has(m.id));
902
+ if (matches.length === 0) return null;
903
+ }
885
904
  const sel = selectForInjection(root, matches, CAP_BYTES);
886
905
  return compose(root, sel, highConsequenceIds(root));
887
906
  }
888
907
 
908
+ /**
909
+ * Ids among `ids` whose copy in EITHER host rule layer is a full body rather
910
+ * than a stub. Either, because the host loads both: one full copy is enough
911
+ * for the body to be standing in context already. Reads only matched ids,
912
+ * never the whole layer, because this runs on the per-prompt path.
913
+ */
914
+ export function installedFullIds(root: string, ids: readonly string[]): Set<string> {
915
+ const out = new Set<string>();
916
+ for (const dir of hostRuleLayerDirs(root)) {
917
+ for (const id of ids) {
918
+ let text: string;
919
+ try {
920
+ text = fs.readFileSync(path.join(dir, `${id}.md`), 'utf-8');
921
+ } catch {
922
+ continue;
923
+ }
924
+ if (!is_thin_entry(text)) out.add(id);
925
+ }
926
+ }
927
+ return out;
928
+ }
929
+
889
930
  // ── main ─────────────────────────────────────────────────────────────────
890
931
 
891
932
  /**
@@ -6,10 +6,14 @@
6
6
  * Python module exactly (snake_case kept deliberately — fidelity over
7
7
  * TS idiom).
8
8
  *
9
- * Per `docs/contracts/hook-architecture-v1.md` § Concurrency, every concern
10
- * that writes under `agents/runtime/state/` MUST:
11
- *
12
- * 1. Acquire an exclusive lock on `agents/runtime/state/.dispatcher.lock`.
9
+ * Per `docs/contracts/hook-architecture-v1.md`, Concurrency, every concern
10
+ * that writes a state file under `agents/` MUST:
11
+ *
12
+ * 1. Acquire an exclusive lock on `<state_dir>/.dispatcher.lock` — the SAME
13
+ * directory the target file lives in, derived from the target's own
14
+ * path (`path.dirname`), never a single fixed location: one concern's
15
+ * target under `agents/runtime/state/` locks there, another's target
16
+ * under `agents/state/` locks there instead.
13
17
  * 2. Write to a sibling `<dest>.tmp.<pid>` file in the same directory.
14
18
  * 3. Rename(2) (atomic on the same filesystem) tmp → dest.
15
19
  * 4. Release the lock.
@@ -29,23 +29,11 @@
29
29
  * settings file is how it learns it is off, the same as the artefact-
30
30
  * engagement surface it mirrors.)
31
31
  *
32
- * THAT SENTENCE USED TO READ "no directory creation", UNQUALIFIED, AND IS
33
- * NARROWED RATHER THAN QUIETLY LEFT STANDING. The foreign-MCP recorder below
34
- * writes `agents/runtime/neighbour-tool-use.json` on an install that never
35
- * enabled telemetry, and creates that directory and a lock sentinel beside it.
36
- * That is deliberate — the store is a local census input, not telemetry, and
37
- * gating it on the org switch would print `0` everywhere (roadmap decision D9)
38
- * — but it IS a file operation, so the guarantee now says which operations it
39
- * covers. An unqualified claim this file's own code contradicts is worse than
40
- * the narrower one it is replaced by.
41
- *
42
- * NOT REACHED YET, AND SAYING SO HERE BECAUSE THIS IS WHERE A READER LOOKS.
43
- * The manifest entry for this concern carries `tools: [Skill]`, which the
44
- * dispatcher matches exactly, so it is not invoked for an MCP call at all and
45
- * the branch below is dead in production. Held as the
46
- * `mcp-recorder-unreachable-behind-the-tools-filter` blocker on
47
- * road-to-neighbours-that-pull-their-weight: the manifest is a gated
48
- * governance surface and the council split on the edit rather than converging.
32
+ * The foreign-MCP tool-name recorder that once branched here lives in its own
33
+ * concern, `mcp-usage-observation` (road-to-neighbours-that-pull-their-weight
34
+ * D12): this concern's `tools: [Skill]` filter meant the dispatcher never
35
+ * called that branch, and default-on local collection does not belong under an
36
+ * opt-in telemetry name.
49
37
  *
50
38
  * NO OUTBOUND CALL EXISTS HERE, DELIBERATELY. Transport is Phase 2 and is
51
39
  * blocked on `sink-choice`; org-wide enablement is Phase 3 and is blocked on
@@ -74,12 +62,7 @@ import {
74
62
  FLUSH_SESSION_END,
75
63
  spool_path_for,
76
64
  } from '../../agent-src/templates/scripts/telemetry/transport.js';
77
- import {
78
- FOREIGN_TOOL_USE_REL,
79
- MCP_TOOL_PREFIX,
80
- usageDay,
81
- } from '../_lib/neighbour_tool_use.js';
82
- import { is_replay_mode, update_json_under_lock } from './state_io.js';
65
+ import { is_replay_mode } from './state_io.js';
83
66
  import { readHookStdin } from './hook_stdin.js';
84
67
  import { EXIT_ALLOW } from './exit_codes.js';
85
68
 
@@ -272,29 +255,7 @@ function processEnvelope(envelope: JsonValue, consumer_root: string): number {
272
255
 
273
256
  const payload = unwrapPayload(envelope);
274
257
  const tool = extractToolName(payload);
275
- if (tool !== SKILL_TOOL_NAME) {
276
- // The other half of this slot's observation, and the only half a
277
- // `post_tool_use` envelope can supply: the tool's NAME. The MCP
278
- // fingerprint store wants a tool DEFINITION, which this envelope
279
- // never carries (roadmap decision D2), so what is recorded here is
280
- // what was actually seen. Rooted at the settings directory, not at
281
- // the session cwd, for the same reason the Class-A log below is.
282
- if (tool !== null && tool.startsWith(MCP_TOOL_PREFIX)) {
283
- // The mutator's cast is safe at the only place that matters:
284
- // the reader in `neighbour_tool_use` drops any value that is
285
- // not a string, so a hand-edited store cannot widen this.
286
- // Kept OUT of the argument list below — esbuild preserves a
287
- // comment in that position and it would cost the shared
288
- // bundle ~190 bytes of prose nothing executes.
289
- const day = usageDay(new Date());
290
- update_json_under_lock<Record<string, string>>(
291
- path.join(readSettingsFor(consumer_root).root, FOREIGN_TOOL_USE_REL),
292
- (seen) => (seen[tool] === day ? null : ({ ...seen, [tool]: day } as Record<string, string>)),
293
- { blocking: false },
294
- );
295
- }
296
- return EXIT_ALLOW;
297
- }
258
+ if (tool !== SKILL_TOOL_NAME) return EXIT_ALLOW;
298
259
 
299
260
  const { settings, text, root } = readSettingsFor(consumer_root);
300
261
  if (!settings.active) return EXIT_ALLOW;
@@ -1333,6 +1333,7 @@ function recordGraphFeeder(
1333
1333
  inputs.workspaceRoot,
1334
1334
  inputs.sessionKey,
1335
1335
  buildFeederRow({
1336
+ root: inputs.workspaceRoot,
1336
1337
  turn: inputs.turnOrdinal,
1337
1338
  layer,
1338
1339
  state,
@@ -70,9 +70,13 @@ cat > "$HOOKS_DIR/pre-push" << 'EOF'
70
70
  # belongs here; resolution belongs to a step run with the result in front of
71
71
  # you. When this hook refuses for staleness, the thing that fixes it is
72
72
  #
73
- # task push-ready # fetch -> integrate the base SET -> regenerate
74
- # # -> verify -> re-check freshness -> push
75
- # task push-ready DRY=1 # the same six steps, read-only
73
+ # task push-ready BASE=<base> # fetch -> integrate the base SET -> regenerate
74
+ # # -> verify -> re-check freshness -> push
75
+ # task push-ready DRY=1 BASE=<base> # the same six steps, read-only
76
+ #
77
+ # `<base>` is the base the refusal names. Without BASE the base comes from the
78
+ # open pull request (gh pr view), and is the default branch only when there is
79
+ # no open pull request or no gh.
76
80
  #
77
81
  # The base is a SET: a branch targeting a release line or a stacked parent may
78
82
  # also have to integrate the default branch, per the branch-convergence policy
@@ -141,23 +145,47 @@ fail=0
141
145
  # no useful second finding to collect from a tree that is about to move.
142
146
  #
143
147
  # It never merges. `check_branch_freshness` asks the REMOTE (one `ls-remote`,
144
- # measured 4.5s) and returns 1 only on a VERIFIED behind state; offline, in CI,
145
- # on a detached HEAD, or standing on the base itself it returns 0 and says so.
146
- # So an unreachable network cannot block a push, and a stale local tracking ref
147
- # cannot fake a green.
148
+ # measured 4.5s) and returns 1 on a VERIFIED behind state, or when the remote
149
+ # answered without the base at all (a misspelled or deleted base); offline, in
150
+ # CI, on a detached HEAD, or standing on the base itself it returns 0 and says
151
+ # so. So an unreachable network cannot block a push, and a stale local tracking
152
+ # ref cannot fake a green. The refusal below names which of the two it was, read
153
+ # from the gate's own lines, so a typo is never reported as staleness.
148
154
  echo "🔍 Base freshness — is this branch behind the base it will merge into?"
149
155
  if [ "${AGENT_CONFIG_SKIP_PREPUSH_FRESHNESS:-}" = "1" ]; then
150
156
  echo "⏭️ skipped via AGENT_CONFIG_SKIP_PREPUSH_FRESHNESS=1"
151
157
  elif [ ! -x ./scripts-run ]; then
152
158
  echo "⚠️ ./scripts-run not found — skipping the freshness check for this push."
153
- elif ! ./scripts-run src/scripts/check_branch_freshness --quiet; then
154
- echo ""
155
- echo " Push blocked — the branch is behind its base, and the gates you just"
156
- echo " passed were answered against a base that no longer exists."
159
+ else
160
+ fresh_rc=0
161
+ fresh_out=$(./scripts-run src/scripts/check_branch_freshness --quiet 2>&1) || fresh_rc=$?
162
+ [ -z "$fresh_out" ] || printf '%s\n' "$fresh_out"
163
+ fi
164
+ if [ "${fresh_rc:-0}" -ne 0 ]; then
165
+ # The gate prints the base in the spelling `task push-ready` accepts.
166
+ base=$(printf '%s\n' "$fresh_out" | sed -n 's/^ *task push-ready BASE=\([^ ]*\).*/\1/p' | head -n 1)
167
+ absent=$(printf '%s\n' "$fresh_out" | sed -n 's/.*base `\([^`]*\)` does not exist on \([^ ]*\) .*/\2\/\1/p' | head -n 1)
157
168
  echo ""
158
- echo " task push-ready # fetch → integrate the base SET → regenerate"
159
- echo " # → verify → re-check freshness, then push"
160
- echo " task push-ready DRY=1 # the same steps, read-only"
169
+ if [ -n "$base" ]; then
170
+ echo " Push blocked — the branch is behind its base, and the gates you just"
171
+ echo " passed were answered against a base that no longer exists."
172
+ echo ""
173
+ echo " task push-ready BASE=$base # fetch → integrate the base SET"
174
+ echo " # → regenerate → verify → re-check"
175
+ echo " task push-ready DRY=1 BASE=$base # the same steps, read-only"
176
+ elif printf '%s\n' "$fresh_out" | grep -q 'branch is BEHIND'; then
177
+ # A strategy that does not merge gets no push-ready line; its remedy
178
+ # is printed by the gate itself.
179
+ echo " Push blocked — the branch is behind its base. The remedy for this"
180
+ echo " project's update strategy is printed above."
181
+ elif [ -n "$absent" ]; then
182
+ echo " Push blocked — the base $absent does not exist on the remote: a"
183
+ echo " misspelled or deleted base, not a stale branch. Name a branch the"
184
+ echo " remote has (--base main and --base origin/main are the same branch)."
185
+ else
186
+ echo " Push blocked — the freshness gate refused without a verdict line;"
187
+ echo " its output is above."
188
+ fi
161
189
  echo ""
162
190
  echo " This hook refuses; it never merges. Bypass a genuine WIP push with"
163
191
  echo " AGENT_CONFIG_SKIP_PREPUSH_FRESHNESS=1."