@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
@@ -31,7 +31,7 @@ import * as path from 'node:path';
31
31
  import process from 'node:process';
32
32
  import { fileURLToPath, pathToFileURL } from 'node:url';
33
33
 
34
- import { thin_entry } from './project_thin_rules.js';
34
+ import { has_body_pointer, is_thin_entry, thin_entry } from './project_thin_rules.js';
35
35
 
36
36
  const _HERE = fileURLToPath(import.meta.url);
37
37
  const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
@@ -42,8 +42,6 @@ const CANARY = path.join(
42
42
  const CANARY_ID = 'host-compliance-canary';
43
43
  const SENTINEL = 'CANARY_BODY_SENTINEL_DO_NOT_INLINE';
44
44
  const KEYWORD = 'xyzzy-canary-probe';
45
- const POINTER_MARKER = 'Routed rule — load the body on trigger-match';
46
-
47
45
  // The supported hosts whose live thin-compliance must be falsified.
48
46
  const HOSTS = ['claude-code', 'cursor', 'augment'];
49
47
 
@@ -60,10 +58,40 @@ export function evaluate_demotion(
60
58
  thinned: string,
61
59
  opts: { sentinel: string; keyword: string } = { sentinel: SENTINEL, keyword: KEYWORD },
62
60
  ): DemotionResult {
63
- const pointer_present = thinned.includes(POINTER_MARKER);
61
+ // ONE SPELLING, ASKED OF THE WRITER — step 2.1 of
62
+ // `road-to-a-thinned-layer-measured-in-one-unit`. This file carried its own
63
+ // substring of the marker, without the blockquote prefix and the full stop,
64
+ // so the writer could be shortened and this detector would keep matching the
65
+ // old sentence — silently, and in the direction that matters: a stub a
66
+ // detector fails to recognise reads as a complete rule body.
67
+ const pointer_present = is_thin_entry(thinned);
64
68
  const body_removed = !thinned.includes(opts.sentinel);
65
69
  const trigger_hint_preserved = thinned.includes(opts.keyword);
66
- const link_present = /Body: \[`[^`]+`\]\(/.test(thinned);
70
+ // THE PATTERN COMES FROM THE WRITER — step 2.3. This was its own regex for
71
+ // the markdown-link form, so when the pointer became a bare path the gate
72
+ // would have reported every correct stub as missing its link.
73
+ const link_present = has_body_pointer(thinned);
74
+ // HONEST LIMIT OF THIS FUNCTION'S MECHANICAL HALF, stated rather than
75
+ // papered over. `pointer_present` and `link_present` are now computed from
76
+ // the writer's own exports, and this probe's only caller feeds them
77
+ // `thin_entry` output produced in the same process — so against writer output
78
+ // those two cannot return false, whatever the writer emits. They still
79
+ // falsify a stub from any OTHER source, which is what the live host half
80
+ // reads, but the mechanical half's real falsifying power is `body_removed`
81
+ // and `trigger_hint_preserved`.
82
+ //
83
+ // A structural check was tried here and removed: `/\S+\.md\s*$/m` adds
84
+ // nothing AGAINST WRITER OUTPUT, which is the only input this half ever sees.
85
+ // It is not implied by `link_present` in general — `Body: .md`, a two-space
86
+ // stem, matches the pointer pattern and fails `\S+` — but the writer composes
87
+ // the pointer from a non-empty prefix and a rule id, so that string is not
88
+ // reachable from `thin_entry` and the conjunct could never flip `ok` here. A
89
+ // conjunct that cannot fail is worse than an absent one: it reads as coverage.
90
+ //
91
+ // Restoring independence needs a second spelling of the marker, which is the
92
+ // drift step 2.1 removed. The suite keeps the detectors honest instead:
93
+ // `thin_marker_single_spelling` runs a non-stub past all three in the false
94
+ // direction, which is the direction this cannot check.
67
95
  return {
68
96
  ok: pointer_present && body_removed && trigger_hint_preserved && link_present,
69
97
  pointer_present,
@@ -19,6 +19,7 @@
19
19
  * - API calls per real user request (F1)
20
20
  * - mean tool-call batch size (F1 — measured 1.00, i.e. fully serial)
21
21
  * - the >60 s blocking tail and its share of tool time (F2)
22
+ * - that tail split by cause, `unknown` always printed (road-to-blocking-time-by-cause)
22
23
  * - the first-call context floor (F3 cross-check)
23
24
  *
24
25
  * A MEASUREMENT, NOT A GATE — by default. `--against-baseline` compares against
@@ -53,6 +54,142 @@ export const BLOCKING_SECONDS = 60;
53
54
 
54
55
  type Entry = Record<string, unknown>;
55
56
 
57
+ /**
58
+ * What a blocking call waited on. A CLOSED set, and `unknown` is a row of its
59
+ * own rather than a fallback folded into a named cause: a share hidden inside
60
+ * `ci-wait` would confirm whatever hypothesis it was folded into.
61
+ */
62
+ export const BLOCKING_CAUSES = [
63
+ 'ci-wait',
64
+ 'subagent-wait',
65
+ 'test',
66
+ 'build',
67
+ 'network',
68
+ 'sleep-poll',
69
+ 'mcp',
70
+ // Added by 2.2: the first reading's unknown share was mostly a question
71
+ // waiting on the human, which no agent-side mitigation can shorten.
72
+ 'user-wait',
73
+ 'unknown',
74
+ ] as const;
75
+ export type BlockingCause = (typeof BLOCKING_CAUSES)[number];
76
+
77
+ /** Non-shell tools, by exact name. A shell call is classified by its command. */
78
+ const TOOL_CAUSE: Readonly<Record<string, BlockingCause>> = {
79
+ Agent: 'subagent-wait',
80
+ Task: 'subagent-wait',
81
+ TaskOutput: 'subagent-wait',
82
+ Monitor: 'sleep-poll',
83
+ WebFetch: 'network',
84
+ WebSearch: 'network',
85
+ AskUserQuestion: 'user-wait',
86
+ ExitPlanMode: 'user-wait',
87
+ };
88
+
89
+ /**
90
+ * Shell rules, matched against each command SEGMENT's leading words in order.
91
+ * The first segment any rule matches decides; a segment no rule matches is
92
+ * skipped, so `cd ../lane; ./scripts-run …/ci_settle 12` reads as the settle it
93
+ * is and not as the `cd` in front of it.
94
+ */
95
+ const SHELL_RULES: ReadonlyArray<readonly [RegExp, BlockingCause]> = [
96
+ [/^(\S*\/)?scripts-run \S*ci_settle\b/, 'ci-wait'],
97
+ [/^gh (run watch|pr checks)\b/, 'ci-wait'],
98
+ [/^(sleep|until|while|watch)\b/, 'sleep-poll'],
99
+ [/^((npx |\S*node_modules\/\.bin\/)?(vitest|jest|pytest|phpunit)\b|npm (run )?test\b|task (ci|test)\b)/, 'test'],
100
+ [/^(task (sync|generate-tools|build)\b|npm (ci|install|run build)\b|(npx )?tsc\b|make\b|esbuild\b)/, 'build'],
101
+ [/^(git (push|fetch|pull|clone)\b|curl\b|wget\b|gh (pr (merge|create)|api)\b)/, 'network'],
102
+ [/^(\S*\/)?scripts-run \S*council_cli run\b/, 'network'],
103
+ ];
104
+
105
+ /** A segment that only changes directory or sets a variable waited on nothing. */
106
+ const NOISE_SEGMENT = /^(cd\b|export\b|set\b|[A-Za-z_][A-Za-z0-9_]*=\S*$)/;
107
+
108
+ /** A loop keyword in front of a body: `for …; do sleep 60` reads as the sleep. */
109
+ const LOOP_KEYWORD = /^(do|then|else)\s+/;
110
+
111
+ /**
112
+ * Split a shell command at `;`, `&&`, `||`, `|` and newlines that sit OUTSIDE
113
+ * quotes. A separator inside `"…"` or `'…'`, or escaped with a backslash, is
114
+ * part of an argument — splitting there would read a commit message as a
115
+ * command. Not a shell parser: subshells, `$(…)` and heredocs are not modelled.
116
+ */
117
+ function shellSegments(cmd: string): string[] {
118
+ const out: string[] = [];
119
+ let cur = '';
120
+ let quote: '' | '"' | "'" = '';
121
+ for (let i = 0; i < cmd.length; i++) {
122
+ const ch = cmd[i] as string;
123
+ if (quote === '' && ch === '\\' && i + 1 < cmd.length) {
124
+ cur += ch + (cmd[i + 1] as string);
125
+ i++;
126
+ continue;
127
+ }
128
+ if (quote !== '') {
129
+ if (ch === quote) quote = '';
130
+ cur += ch;
131
+ continue;
132
+ }
133
+ if (ch === '"' || ch === "'") {
134
+ quote = ch;
135
+ cur += ch;
136
+ continue;
137
+ }
138
+ const two = cmd.slice(i, i + 2);
139
+ if (two === '&&' || two === '||') {
140
+ out.push(cur);
141
+ cur = '';
142
+ i++;
143
+ continue;
144
+ }
145
+ if (ch === ';' || ch === '|' || ch === '\n') {
146
+ out.push(cur);
147
+ cur = '';
148
+ continue;
149
+ }
150
+ cur += ch;
151
+ }
152
+ out.push(cur);
153
+ return out;
154
+ }
155
+
156
+ /**
157
+ * Exactly one cause per call; `unknown` when no rule matches. A compound
158
+ * command takes the cause of its FIRST matching segment, so `git commit && git
159
+ * push` reads as the push — the whole call's time lands on that one cause.
160
+ */
161
+ export function classifyBlockingCall(tool: string, input: unknown): BlockingCause {
162
+ if (tool.startsWith('mcp__')) return 'mcp';
163
+ const byName = TOOL_CAUSE[tool];
164
+ if (byName !== undefined) return byName;
165
+ if (tool !== 'Bash' || !isObj(input) || typeof input['command'] !== 'string') return 'unknown';
166
+ for (const raw of shellSegments(input['command'])) {
167
+ const seg = raw.trim().replace(LOOP_KEYWORD, '');
168
+ if (seg === '' || NOISE_SEGMENT.test(seg)) continue;
169
+ for (const [re, cause] of SHELL_RULES) if (re.test(seg)) return cause;
170
+ }
171
+ return 'unknown';
172
+ }
173
+
174
+ /**
175
+ * The in-memory record of one blocking call. `summary` is bounded and never
176
+ * printed or serialised by `main`: command text names local paths and hosts,
177
+ * and the published reading carries counts and minutes only.
178
+ */
179
+ export interface BlockingCall {
180
+ tool: string;
181
+ summary: string;
182
+ cause: BlockingCause;
183
+ seconds: number;
184
+ }
185
+
186
+ const SUMMARY_CHARS = 120;
187
+
188
+ function summarise(tool: string, input: unknown): string {
189
+ const body = isObj(input) && typeof input['command'] === 'string' ? input['command'] : JSON.stringify(input ?? {});
190
+ return `${tool}: ${body}`.slice(0, SUMMARY_CHARS);
191
+ }
192
+
56
193
  function isObj(v: unknown): v is Record<string, unknown> {
57
194
  return typeof v === 'object' && v !== null && !Array.isArray(v);
58
195
  }
@@ -72,6 +209,12 @@ export interface Turnaround {
72
209
  blockingShare: number;
73
210
  contextFloorMin: number;
74
211
  contextFloorMax: number;
212
+ /** Blocking calls and seconds per cause; every cause present, `unknown` included. */
213
+ blockingByCause: Record<BlockingCause, { calls: number; seconds: number }>;
214
+ }
215
+
216
+ function emptyByCause(): Turnaround['blockingByCause'] {
217
+ return Object.fromEntries(BLOCKING_CAUSES.map((c) => [c, { calls: 0, seconds: 0 }])) as Turnaround['blockingByCause'];
75
218
  }
76
219
 
77
220
  const ZERO: Turnaround = {
@@ -88,6 +231,7 @@ const ZERO: Turnaround = {
88
231
  blockingShare: 0,
89
232
  contextFloorMin: 0,
90
233
  contextFloorMax: 0,
234
+ blockingByCause: emptyByCause(),
91
235
  };
92
236
 
93
237
  function ms(iso: unknown): number | null {
@@ -133,12 +277,20 @@ export function recentSessions(store: string, limit: number, includeCurrent = fa
133
277
  }
134
278
 
135
279
  export function measure(files: readonly string[]): Turnaround {
280
+ return measureDetailed(files).turnaround;
281
+ }
282
+
283
+ /** `measure`, plus the per-call blocking records the cause table is built from. */
284
+ export function measureDetailed(files: readonly string[]): { turnaround: Turnaround; blocking: BlockingCall[] } {
136
285
  const requestIds = new Set<string>();
137
286
  /** requestId → tool_use blocks in it. */
138
287
  const batch = new Map<string, number>();
139
288
  /** tool_use id → the timestamp the assistant emitted it. */
140
289
  const emittedAt = new Map<string, number>();
290
+ /** tool_use id → what was called, kept only until its result arrives. */
291
+ const calledWith = new Map<string, { tool: string; input: unknown }>();
141
292
  const durations: number[] = [];
293
+ const blockingCalls: BlockingCall[] = [];
142
294
  const contextFloors: number[] = [];
143
295
  let userRequests = 0;
144
296
  let sessions = 0;
@@ -172,8 +324,20 @@ export function measure(files: readonly string[]): Turnaround {
172
324
  const id = String(b['tool_use_id'] ?? '');
173
325
  const started = emittedAt.get(id);
174
326
  if (started === undefined || at === null) continue;
175
- durations.push((at - started) / 1000);
327
+ const seconds = (at - started) / 1000;
328
+ durations.push(seconds);
176
329
  emittedAt.delete(id);
330
+ const call = calledWith.get(id);
331
+ calledWith.delete(id);
332
+ if (seconds > BLOCKING_SECONDS) {
333
+ const tool = call?.tool ?? '';
334
+ blockingCalls.push({
335
+ tool,
336
+ summary: summarise(tool, call?.input),
337
+ cause: classifyBlockingCall(tool, call?.input),
338
+ seconds,
339
+ });
340
+ }
177
341
  }
178
342
  }
179
343
  continue;
@@ -202,7 +366,10 @@ export function measure(files: readonly string[]): Turnaround {
202
366
  if (!isObj(b) || b['type'] !== 'tool_use') continue;
203
367
  n += 1;
204
368
  const id = String(b['id'] ?? '');
205
- if (id !== '' && at !== null) emittedAt.set(id, at);
369
+ if (id !== '' && at !== null) {
370
+ emittedAt.set(id, at);
371
+ calledWith.set(id, { tool: String(b['name'] ?? ''), input: b['input'] });
372
+ }
206
373
  }
207
374
  if (n > 0 && typeof rid === 'string' && rid !== '') {
208
375
  batch.set(rid, (batch.get(rid) ?? 0) + n);
@@ -216,8 +383,14 @@ export function measure(files: readonly string[]): Turnaround {
216
383
  const blocking = durations.filter((d) => d > BLOCKING_SECONDS);
217
384
  const blockingSeconds = blocking.reduce((a, b) => a + b, 0);
218
385
  const round = (x: number, p = 2): number => Math.round(x * 10 ** p) / 10 ** p;
386
+ const byCause = emptyByCause();
387
+ for (const c of blockingCalls) {
388
+ byCause[c.cause].calls += 1;
389
+ byCause[c.cause].seconds += c.seconds;
390
+ }
391
+ for (const c of BLOCKING_CAUSES) byCause[c].seconds = round(byCause[c].seconds, 1);
219
392
 
220
- return {
393
+ const turnaround: Turnaround = {
221
394
  sessions,
222
395
  userRequests,
223
396
  apiCalls: requestIds.size,
@@ -231,7 +404,9 @@ export function measure(files: readonly string[]): Turnaround {
231
404
  blockingShare: toolSeconds === 0 ? 0 : round(blockingSeconds / toolSeconds, 4),
232
405
  contextFloorMin: contextFloors.length === 0 ? 0 : Math.min(...contextFloors),
233
406
  contextFloorMax: contextFloors.length === 0 ? 0 : Math.max(...contextFloors),
407
+ blockingByCause: byCause,
234
408
  };
409
+ return { turnaround, blocking: blockingCalls };
235
410
  }
236
411
 
237
412
  export interface Budget {
@@ -297,6 +472,11 @@ function render(t: Turnaround, store: string): string {
297
472
  ` mean tool-call batch size ${String(t.meanBatchSize)} (${String(t.toolCalls)} tool calls / ${String(t.toolUsingRequests)} tool-using requests)`,
298
473
  ` blocking tail (>${String(BLOCKING_SECONDS)}s) ${String(t.blockingCalls)} call(s), ${String(Math.round(t.blockingSeconds / 60))} min = ${pct(t.blockingShare)} of ${String(Math.round(t.toolSeconds / 60))} min tool time`,
299
474
  ` first-call context floor ${String(t.contextFloorMin)}–${String(t.contextFloorMax)} tokens`,
475
+ ` blocking tail by cause`,
476
+ ...BLOCKING_CAUSES.map((c) => {
477
+ const row = t.blockingByCause[c];
478
+ return ` ${c.padEnd(14)}${String(row.calls)} call(s), ${String(Math.round(row.seconds / 60))} min`;
479
+ }),
300
480
  '',
301
481
  ].join('\n');
302
482
  }
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * ratification_header — print a ratification artifact's `providers:`,
4
+ * `verdict:` and `seats:` frontmatter lines, derived from per-seat final
5
+ * verdicts.
6
+ *
7
+ * The two header fields used to be typed by the author, and three findings in
8
+ * one release were the header saying more than the seats had: `ratified` over a
9
+ * non-convergent seat, two providers over one closing seat. This is the writer
10
+ * side of the fix; `readRatification` refuses the same shapes on the reader
11
+ * side whenever `seats:` is recorded.
12
+ *
13
+ * Usage: ratification_header --seat <provider>=<final-verdict> [--seat …]
14
+ * final-verdict: ratified | confirmed-non-expanding | refused | non-convergent
15
+ * | no-final-verdict (the seat closed or was absent at the end)
16
+ *
17
+ * Exit codes: 0 = header printed · 2 = usage error.
18
+ */
19
+
20
+ import * as fs from 'node:fs';
21
+ import * as path from 'node:path';
22
+ import { fileURLToPath, pathToFileURL } from 'node:url';
23
+
24
+ import {
25
+ SEAT_PROVIDER_RE,
26
+ SEAT_VERDICTS,
27
+ renderRatificationHeader,
28
+ type SeatVerdict,
29
+ } from './_lib/ratification_artifact.js';
30
+
31
+ export function main(argv: readonly string[] = process.argv.slice(2)): number {
32
+ const seats = new Map<string, SeatVerdict>();
33
+ for (let i = 0; i < argv.length; i += 1) {
34
+ if (argv[i] !== '--seat') {
35
+ process.stderr.write(`error: unknown argument ${String(argv[i])}\n`);
36
+ return 2;
37
+ }
38
+ const raw = argv[i + 1] ?? '';
39
+ i += 1;
40
+ const eq = raw.indexOf('=');
41
+ const provider = raw.slice(0, eq);
42
+ const verdict = raw.slice(eq + 1);
43
+ if (eq <= 0 || !SEAT_PROVIDER_RE.test(provider) || !SEAT_VERDICTS.includes(verdict)) {
44
+ process.stderr.write(
45
+ `error: --seat needs <provider id ${String(SEAT_PROVIDER_RE)}>=<one of ` +
46
+ `${SEAT_VERDICTS.join('|')}>, got \`${raw}\`\n`,
47
+ );
48
+ return 2;
49
+ }
50
+ if (seats.has(provider)) {
51
+ process.stderr.write(`error: seat \`${provider}\` given twice\n`);
52
+ return 2;
53
+ }
54
+ seats.set(provider, verdict as SeatVerdict);
55
+ }
56
+ if (seats.size === 0) {
57
+ process.stderr.write('error: at least one --seat is required\n');
58
+ return 2;
59
+ }
60
+ process.stdout.write(`${renderRatificationHeader(seats)}\n`);
61
+ return 0;
62
+ }
63
+
64
+ function _isCliEntry(): boolean {
65
+ if (process.argv[1] === undefined) return false;
66
+ const here = fileURLToPath(import.meta.url);
67
+ if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
68
+ try {
69
+ return fs.realpathSync(here) === fs.realpathSync(path.resolve(process.argv[1]));
70
+ } catch {
71
+ return false;
72
+ }
73
+ }
74
+
75
+ if (_isCliEntry()) {
76
+ process.exit(main());
77
+ }
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * refusal_envelope — the hand-off an agent writes when a HOST classifier
4
+ * refuses a step of an owner-directed task (ADR-282 § Part B).
5
+ *
6
+ * The repository cannot change the host classifier, and an agent must never
7
+ * route around a refused action. With the owner present it asks once for an
8
+ * explicit in-session authorization and re-runs the same step once; this
9
+ * envelope is the fallback when that is refused too or no owner is present.
10
+ * Write one ready-to-paste continuation prompt and name its path in one line,
11
+ * so the owner never has to ask for it.
12
+ *
13
+ * The envelope lands at `agents/tmp/<round-hex>/prompt.md`. The directory name
14
+ * is an opaque round id because `block-speaking-inbox-dir` refuses any other
15
+ * shape under `agents/tmp/`; the id is random, so an earlier envelope is never
16
+ * overwritten.
17
+ *
18
+ * Subagent lanes report refusals in the fixed `classifier_refusals` field;
19
+ * `batchLaneRefusals` folds every lane's field into ONE list so a drain ends in
20
+ * one envelope instead of N reports the owner collects by hand. A lane report
21
+ * WITHOUT the field is malformed — "no field" and "no refusals" must not read
22
+ * the same, or a lane that forgot to report looks like a lane that was clean.
23
+ *
24
+ * Usage:
25
+ * refusal_envelope --input <file.json> [--root DIR]
26
+ * The JSON is an `EnvelopeInput`. Prints the written path as the last line.
27
+ */
28
+
29
+ import { randomBytes } from 'node:crypto';
30
+ import * as fs from 'node:fs';
31
+ import * as path from 'node:path';
32
+ import { pathToFileURL } from 'node:url';
33
+
34
+ export interface Refusal {
35
+ action: string;
36
+ reason: string;
37
+ lane?: string;
38
+ }
39
+
40
+ export interface EnvelopeInput {
41
+ task: string;
42
+ done: string[];
43
+ refusals: Refusal[];
44
+ remaining: string[];
45
+ /** Path of the owner-directive record that authorized the task, if any. */
46
+ ownerDirective?: string;
47
+ }
48
+
49
+ export interface LaneReport {
50
+ lane: string;
51
+ classifier_refusals: Array<{ action: string; reason: string }>;
52
+ }
53
+
54
+ const bullets = (items: readonly string[]): string => (items.length > 0 ? items.map((i) => `- ${i}`).join('\n') : '- none');
55
+
56
+ export function renderEnvelope(input: EnvelopeInput): string {
57
+ if (input.refusals.length === 0) {
58
+ throw new Error('an envelope needs at least one refusal — without one there is nothing to hand off');
59
+ }
60
+ const refused = input.refusals
61
+ .map((r) => `- ${r.lane !== undefined ? `[${r.lane}] ` : ''}${r.action} — refused: ${r.reason}`)
62
+ .join('\n');
63
+ const auth =
64
+ input.ownerDirective !== undefined
65
+ ? `The repository owner directly ordered this task; the order is recorded verbatim in \`${input.ownerDirective}\`. I am the owner and I authorize the remaining steps below in this message.`
66
+ : 'I am the owner of this repository and I authorize the remaining steps below in this message.';
67
+ return [
68
+ '# Continuation prompt — paste into a fresh session',
69
+ '',
70
+ '## Task',
71
+ '',
72
+ input.task,
73
+ '',
74
+ '## Done',
75
+ '',
76
+ bullets(input.done),
77
+ '',
78
+ '## Refused by the host classifier',
79
+ '',
80
+ refused,
81
+ '',
82
+ 'Do not retry or route around these refusals. If one recurs, stop and say so.',
83
+ '',
84
+ '## Remaining steps',
85
+ '',
86
+ input.remaining.map((s, i) => `${i + 1}. ${s}`).join('\n'),
87
+ '',
88
+ '## Owner authorization',
89
+ '',
90
+ auth,
91
+ '',
92
+ ].join('\n');
93
+ }
94
+
95
+ export function writeEnvelope(root: string, input: EnvelopeInput): string {
96
+ const body = renderEnvelope(input);
97
+ const dir = path.join(root, 'agents', 'tmp', `round-${randomBytes(4).toString('hex')}`);
98
+ fs.mkdirSync(dir, { recursive: true });
99
+ const file = path.join(dir, 'prompt.md');
100
+ fs.writeFileSync(file, body, { flag: 'wx' });
101
+ return file;
102
+ }
103
+
104
+ export function batchLaneRefusals(reports: readonly LaneReport[]): Refusal[] {
105
+ const out: Refusal[] = [];
106
+ for (const r of reports) {
107
+ if (!Array.isArray(r.classifier_refusals)) {
108
+ throw new Error(`lane ${r.lane} report is missing the classifier_refusals field`);
109
+ }
110
+ for (const x of r.classifier_refusals) {
111
+ out.push({ lane: r.lane, action: x.action, reason: x.reason });
112
+ }
113
+ }
114
+ return out;
115
+ }
116
+
117
+ export function main(argv: readonly string[] = process.argv.slice(2)): number {
118
+ let root = process.cwd();
119
+ let input: string | undefined;
120
+ for (let i = 0; i < argv.length; i++) {
121
+ if (argv[i] === '--root') {
122
+ root = argv[++i] ?? root;
123
+ } else if (argv[i] === '--input') {
124
+ input = argv[++i];
125
+ }
126
+ }
127
+ if (input === undefined) {
128
+ process.stderr.write('usage: refusal_envelope --input <file.json> [--root DIR]\n');
129
+ return 2;
130
+ }
131
+ const file = writeEnvelope(root, JSON.parse(fs.readFileSync(input, 'utf8')) as EnvelopeInput);
132
+ process.stdout.write(`${path.relative(root, file)}\n`);
133
+ return 0;
134
+ }
135
+
136
+ if (import.meta.url === pathToFileURL(process.argv[1] ?? '').href) {
137
+ process.exit(main());
138
+ }
@@ -466,20 +466,37 @@ export function local_release_gate_argv(): string[] {
466
466
  * Returns `null` on any measurement failure — a shallow clone or a missing tag
467
467
  * is an environment fact, and a release must not stop over one. `null` means
468
468
  * the line is simply not rendered.
469
+ *
470
+ * Both ends are resolved to SHAs BEFORE measuring, and the rendered level
471
+ * carries them. The 16.3.0 line read `23 vs 1` while the measurer re-run on
472
+ * `16.2.0..16.3.0` reads `83 vs 3`: `HEAD` at write time was not the commit the
473
+ * tag later named, and the line recorded neither end, so nobody could say which
474
+ * range it had read. With both SHAs in the line, `measure_release_mix --from
475
+ * <from> --to <to>` reproduces it.
469
476
  */
470
477
  export function measure_mix_obligation(
471
478
  version: string,
472
479
  fromRef?: string | null,
480
+ opts: { toRef?: string; cwd?: string } = {},
473
481
  ): MixObligation | null {
482
+ const cwd = opts.cwd ?? REPO_ROOT;
483
+ const toRef = opts.toRef ?? 'HEAD';
474
484
  try {
475
- const from = fromRef ?? previous_release_tag('HEAD', REPO_ROOT);
485
+ const from = fromRef ?? previous_release_tag(toRef, cwd);
476
486
  if (!from) return null;
477
- const reading = measureRange(from, 'HEAD', loadTaxonomy(), version, REPO_ROOT);
487
+ const from_sha = _resolve_commit(from, cwd);
488
+ const to_sha = _resolve_commit(toRef, cwd);
489
+ const reading = measureRange(from_sha, to_sha, loadTaxonomy(), version, cwd);
478
490
  const o = reading.response_obligation;
479
491
  return {
480
492
  level:
481
493
  `governance-only ${String(o.governance_only)} vs consumer-only ` +
482
- `${String(o.consumer_only)} (taxonomy ${reading.taxonomy_version})`,
494
+ `${String(o.consumer_only)} (taxonomy ${reading.taxonomy_version}; ` +
495
+ `range ${from_sha.slice(0, 12)}..${to_sha.slice(0, 12)})`,
496
+ from_sha,
497
+ to_sha,
498
+ governance_only: o.governance_only,
499
+ consumer_only: o.consumer_only,
483
500
  };
484
501
  } catch (err) {
485
502
  // Printed rather than swallowed. Nothing refuses over the reading any
@@ -494,6 +511,15 @@ export function measure_mix_obligation(
494
511
  }
495
512
  }
496
513
 
514
+ function _resolve_commit(ref: string, cwd: string): string {
515
+ const r = spawnSync('git', ['rev-parse', '--verify', `${ref}^{commit}`], { encoding: 'utf-8', cwd });
516
+ const sha = (r.stdout ?? '').trim();
517
+ if (r.status !== 0 || !/^[0-9a-f]{40}$/u.test(sha)) {
518
+ throw new Error(`cannot resolve \`${ref}\` to a commit`);
519
+ }
520
+ return sha;
521
+ }
522
+
497
523
  /**
498
524
  * Refuse the FIRST remote state of a release whose section is not publishable.
499
525
  *
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Print the static import closure of the hook dispatcher, one module per line
4
+ * with its class — `verdict`, `payload`, `neither` or `concern`.
5
+ *
6
+ * The reading behind `check_kernel_edit_ratified`'s derived watched set: the
7
+ * `verdict` rows are what the gate adds to its hand-written plumbing pattern.
8
+ * Named `report_` because it publishes a reading and gates nothing.
9
+ *
10
+ * Inputs:
11
+ * --root DIR tree to read (default: this script's repository)
12
+ * --markdown emit a Markdown table instead of plain lines
13
+ *
14
+ * Exit 0 always, unless the dispatcher is absent under `--root` (exit 1): an
15
+ * empty closure from a tree with no dispatcher is not a reading.
16
+ */
17
+
18
+ import * as fs from 'node:fs';
19
+ import * as path from 'node:path';
20
+ import { fileURLToPath, pathToFileURL } from 'node:url';
21
+
22
+ import {
23
+ DISPATCHER_PATH,
24
+ dispatchImportClosure,
25
+ type ClosureEntry,
26
+ type ModuleClass,
27
+ } from './_lib/dispatch_import_closure.js';
28
+
29
+ const _HERE = fileURLToPath(import.meta.url);
30
+ const REPO = path.resolve(path.dirname(_HERE), '..', '..');
31
+
32
+ const ORDER: readonly ModuleClass[] = ['verdict', 'payload', 'neither', 'concern'];
33
+
34
+ export function render(entries: readonly ClosureEntry[], markdown: boolean): string[] {
35
+ const sorted = [...entries].sort(
36
+ (a, b) => ORDER.indexOf(a.class) - ORDER.indexOf(b.class) || a.path.localeCompare(b.path),
37
+ );
38
+ const counts = ORDER.map((c) => `${c} ${entries.filter((e) => e.class === c).length}`).join(' · ');
39
+ const lines: string[] = [];
40
+ if (markdown) {
41
+ lines.push('| Class | Module |', '|---|---|');
42
+ for (const e of sorted) {
43
+ lines.push(`| ${e.class} | \`${e.path}\` |`);
44
+ }
45
+ lines.push('', `Totals: ${counts}.`);
46
+ return lines;
47
+ }
48
+ for (const e of sorted) {
49
+ lines.push(`${e.class.padEnd(8)} ${e.path}`);
50
+ }
51
+ lines.push(`totals: ${counts}`);
52
+ return lines;
53
+ }
54
+
55
+ export function main(argv: readonly string[] = process.argv.slice(2)): number {
56
+ let root = REPO;
57
+ let markdown = false;
58
+ for (let i = 0; i < argv.length; i += 1) {
59
+ if (argv[i] === '--root') {
60
+ root = path.resolve(argv[i + 1] ?? root);
61
+ i += 1;
62
+ } else if (argv[i] === '--markdown') {
63
+ markdown = true;
64
+ }
65
+ }
66
+ if (!fs.existsSync(path.join(root, DISPATCHER_PATH))) {
67
+ process.stderr.write(`report_dispatch_import_closure: no ${DISPATCHER_PATH} under ${root}\n`);
68
+ return 1;
69
+ }
70
+ process.stdout.write(`${render(dispatchImportClosure(root), markdown).join('\n')}\n`);
71
+ return 0;
72
+ }
73
+
74
+ if (process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href) {
75
+ process.exit(main());
76
+ }