@event4u/agent-config 16.3.0 → 16.5.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 (532) 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 +178 -78
  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/design.md +1 -1
  16. package/dist/agent-src/commands/estimate-ticket.md +1 -1
  17. package/dist/agent-src/commands/feature/explore.md +3 -3
  18. package/dist/agent-src/commands/feature/plan.md +1 -1
  19. package/dist/agent-src/commands/fix/ci.md +17 -3
  20. package/dist/agent-src/commands/fix/commit-messages.md +48 -23
  21. package/dist/agent-src/commands/fix/pr-comments.md +3 -6
  22. package/dist/agent-src/commands/implement-ticket.md +3 -3
  23. package/dist/agent-src/commands/memory/add.md +4 -16
  24. package/dist/agent-src/commands/memory/load.md +5 -6
  25. package/dist/agent-src/commands/memory/promote.md +3 -16
  26. package/dist/agent-src/commands/mission/upgrade.md +3 -2
  27. package/dist/agent-src/commands/optimize/agents-dir.md +2 -2
  28. package/dist/agent-src/commands/optimize/deep.md +4 -2
  29. package/dist/agent-src/commands/optimize/rtk.md +4 -26
  30. package/dist/agent-src/commands/pr/create/description-only.md +18 -15
  31. package/dist/agent-src/commands/pr/create.md +42 -34
  32. package/dist/agent-src/commands/pr/merge.md +136 -9
  33. package/dist/agent-src/commands/prepare-for-review.md +13 -11
  34. package/dist/agent-src/commands/project/analyze.md +7 -35
  35. package/dist/agent-src/commands/refine-ticket.md +1 -1
  36. package/dist/agent-src/commands/review/changes.md +14 -19
  37. package/dist/agent-src/commands/roadmap/next.md +10 -1
  38. package/dist/agent-src/commands/roadmap/process-full.md +52 -38
  39. package/dist/agent-src/commands/roadmap/resolve-blockers.md +64 -14
  40. package/dist/agent-src/commands/worktree/create.md +7 -3
  41. package/dist/agent-src/commands/worktree/verify.md +2 -1
  42. package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +5 -3
  43. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +7 -9
  44. package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +8 -6
  45. package/dist/agent-src/contexts/contracts/frugality-charter.md +8 -5
  46. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +1 -1
  47. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +0 -1
  48. package/dist/agent-src/contexts/execution/evidence-discipline.md +2 -2
  49. package/dist/agent-src/contexts/execution/non-interactive-contract.md +5 -8
  50. package/dist/agent-src/contexts/execution/rdp-gate.md +4 -4
  51. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +9 -8
  52. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +67 -52
  53. package/dist/agent-src/contexts/execution/subagent-routing.md +8 -8
  54. package/dist/agent-src/contexts/execution/subagent-steering.md +6 -4
  55. package/dist/agent-src/contexts/execution/terminal-states.md +2 -2
  56. package/dist/agent-src/contexts/execution/toolchain-resolver.md +4 -10
  57. package/dist/agent-src/contexts/subagent-configuration.md +1 -1
  58. package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
  59. package/dist/agent-src/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
  60. package/dist/agent-src/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
  61. package/dist/agent-src/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
  62. package/dist/agent-src/guidelines/agent-infra/layered-settings.md +13 -1
  63. package/dist/agent-src/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  64. package/dist/agent-src/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
  65. package/dist/agent-src/guidelines/agent-infra/size-and-scope.md +36 -0
  66. package/dist/agent-src/guidelines/design-antipatterns.md +1 -1
  67. package/dist/agent-src/guidelines/php/git.md +15 -2
  68. package/dist/agent-src/rules/active-remediation.md +0 -1
  69. package/dist/agent-src/rules/analysis-skill-routing.md +0 -1
  70. package/dist/agent-src/rules/architecture.md +0 -1
  71. package/dist/agent-src/rules/artifact-drafting-protocol.md +0 -1
  72. package/dist/agent-src/rules/artifact-engagement-recording.md +0 -1
  73. package/dist/agent-src/rules/augment-edit-discipline.md +0 -1
  74. package/dist/agent-src/rules/autonomous-execution.md +0 -1
  75. package/dist/agent-src/rules/brand-consistency.md +0 -1
  76. package/dist/agent-src/rules/brand-source-of-truth.md +0 -1
  77. package/dist/agent-src/rules/broken-access-control.md +0 -1
  78. package/dist/agent-src/rules/cli-output-handling.md +0 -1
  79. package/dist/agent-src/rules/code-comment-discipline.md +0 -1
  80. package/dist/agent-src/rules/code-provenance.md +0 -1
  81. package/dist/agent-src/rules/command-suggestion-policy.md +0 -1
  82. package/dist/agent-src/rules/commit-conventions.md +1 -2
  83. package/dist/agent-src/rules/communication-through-line.md +1 -2
  84. package/dist/agent-src/rules/content-quoting-floor.md +1 -2
  85. package/dist/agent-src/rules/context-hygiene.md +5 -5
  86. package/dist/agent-src/rules/copilot-routing.md +1 -2
  87. package/dist/agent-src/rules/council-availability.md +4 -4
  88. package/dist/agent-src/rules/cross-source-consistency.md +4 -6
  89. package/dist/agent-src/rules/decision-revisit-gate.md +2 -3
  90. package/dist/agent-src/rules/delegation-policy.md +2 -3
  91. package/dist/agent-src/rules/design-fidelity.md +0 -1
  92. package/dist/agent-src/rules/design-review-after-ui-write.md +3 -3
  93. package/dist/agent-src/rules/devcontainer-routing.md +1 -2
  94. package/dist/agent-src/rules/doc-screenshot-hygiene.md +0 -1
  95. package/dist/agent-src/rules/docker-commands.md +0 -1
  96. package/dist/agent-src/rules/domain-adoption-policy.md +0 -1
  97. package/dist/agent-src/rules/domain-safety-disclaimer.md +0 -1
  98. package/dist/agent-src/rules/domain-safety-pii.md +0 -1
  99. package/dist/agent-src/rules/domain-safety-retention.md +0 -1
  100. package/dist/agent-src/rules/downstream-changes.md +0 -1
  101. package/dist/agent-src/rules/engineering-safety-floor.md +0 -1
  102. package/dist/agent-src/rules/external-code-graph-interop.md +0 -1
  103. package/dist/agent-src/rules/external-reference-deep-dive.md +0 -1
  104. package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -2
  105. package/dist/agent-src/rules/finance-safety-floor.md +0 -1
  106. package/dist/agent-src/rules/fix-what-you-see.md +6 -32
  107. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +0 -1
  108. package/dist/agent-src/rules/git-history-discipline.md +1 -2
  109. package/dist/agent-src/rules/guidelines.md +0 -1
  110. package/dist/agent-src/rules/history-discipline.md +0 -1
  111. package/dist/agent-src/rules/icon-consistency.md +0 -1
  112. package/dist/agent-src/rules/image-likeness-and-rights.md +0 -1
  113. package/dist/agent-src/rules/improve-before-implement.md +0 -1
  114. package/dist/agent-src/rules/invite-challenge.md +0 -1
  115. package/dist/agent-src/rules/laravel-routing.md +1 -2
  116. package/dist/agent-src/rules/laravel-translations.md +0 -1
  117. package/dist/agent-src/rules/legal-safety-floor.md +0 -1
  118. package/dist/agent-src/rules/lethal-trifecta-guard.md +0 -1
  119. package/dist/agent-src/rules/linked-projects-onboarding-gate.md +0 -1
  120. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +0 -1
  121. package/dist/agent-src/rules/markdown-safe-codeblocks.md +0 -1
  122. package/dist/agent-src/rules/media-governance-routing.md +1 -2
  123. package/dist/agent-src/rules/media-sync-ground-truth.md +0 -1
  124. package/dist/agent-src/rules/minimal-safe-diff.md +0 -1
  125. package/dist/agent-src/rules/missing-skill-recovery.md +0 -1
  126. package/dist/agent-src/rules/missing-tool-handling.md +0 -1
  127. package/dist/agent-src/rules/model-recommendation.md +0 -1
  128. package/dist/agent-src/rules/neighbour-precedence.md +64 -0
  129. package/dist/agent-src/rules/no-attribution-footers.md +0 -1
  130. package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +0 -1
  131. package/dist/agent-src/rules/no-pr-progress-comments.md +0 -1
  132. package/dist/agent-src/rules/no-roadmap-references.md +0 -1
  133. package/dist/agent-src/rules/notes-first-reasoning.md +0 -1
  134. package/dist/agent-src/rules/onboarding-gate.md +0 -1
  135. package/dist/agent-src/rules/output-discipline.md +0 -1
  136. package/dist/agent-src/rules/package-ci-checks.md +0 -1
  137. package/dist/agent-src/rules/persona-governance.md +2 -3
  138. package/dist/agent-src/rules/php-coding.md +0 -1
  139. package/dist/agent-src/rules/prefer-enums-over-literals.md +0 -1
  140. package/dist/agent-src/rules/preservation-guard.md +0 -1
  141. package/dist/agent-src/rules/provider-lifecycle-discipline.md +2 -3
  142. package/dist/agent-src/rules/question-not-instruction.md +0 -1
  143. package/dist/agent-src/rules/reviewer-awareness.md +0 -1
  144. package/dist/agent-src/rules/roadmap-ci-steps-policy.md +0 -1
  145. package/dist/agent-src/rules/roadmap-progress-sync.md +3 -6
  146. package/dist/agent-src/rules/role-mode-adherence.md +0 -1
  147. package/dist/agent-src/rules/rule-type-governance.md +0 -1
  148. package/dist/agent-src/rules/runtime-safety.md +0 -1
  149. package/dist/agent-src/rules/scale-discipline.md +0 -1
  150. package/dist/agent-src/rules/secret-vcs-guard.md +0 -1
  151. package/dist/agent-src/rules/security-sensitive-stop.md +0 -1
  152. package/dist/agent-src/rules/self-repair-loop.md +0 -1
  153. package/dist/agent-src/rules/senior-engineering-discipline.md +0 -1
  154. package/dist/agent-src/rules/session-canary.md +0 -1
  155. package/dist/agent-src/rules/settings-ask-protocol.md +5 -6
  156. package/dist/agent-src/rules/size-enforcement.md +0 -1
  157. package/dist/agent-src/rules/skill-improvement-trigger.md +2 -3
  158. package/dist/agent-src/rules/skill-quality.md +0 -1
  159. package/dist/agent-src/rules/slash-command-routing-policy.md +0 -1
  160. package/dist/agent-src/rules/source-confidentiality.md +0 -1
  161. package/dist/agent-src/rules/source-discovery-gate.md +0 -1
  162. package/dist/agent-src/rules/source-of-truth.md +0 -1
  163. package/dist/agent-src/rules/spreadsheet-source-quality.md +1 -2
  164. package/dist/agent-src/rules/strategy-safety-floor.md +0 -1
  165. package/dist/agent-src/rules/symfony-routing.md +1 -2
  166. package/dist/agent-src/rules/think-before-action.md +0 -1
  167. package/dist/agent-src/rules/token-budget-discipline.md +14 -48
  168. package/dist/agent-src/rules/token-efficiency.md +0 -1
  169. package/dist/agent-src/rules/token-optimizer-maintenance.md +0 -1
  170. package/dist/agent-src/rules/tool-safety.md +0 -1
  171. package/dist/agent-src/rules/ui-audit-gate.md +1 -2
  172. package/dist/agent-src/rules/untrusted-input-defense.md +0 -1
  173. package/dist/agent-src/rules/upstream-proposal.md +0 -1
  174. package/dist/agent-src/rules/user-interaction.md +0 -1
  175. package/dist/agent-src/rules/user-interrupt-priority.md +0 -1
  176. package/dist/agent-src/scripts/gate_budget.ts +47 -23
  177. package/dist/agent-src/scripts/gate_execute.ts +12 -4
  178. package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +2 -0
  179. package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
  180. package/dist/agent-src/skills/ai-council/SKILL.md +7 -4
  181. package/dist/agent-src/skills/ai-council/references/cost-and-redaction.md +21 -11
  182. package/dist/agent-src/skills/ai-council/references/procedure.md +12 -6
  183. package/dist/agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -1
  184. package/dist/agent-src/skills/bug-analyzer/SKILL.md +1 -1
  185. package/dist/agent-src/skills/canvas-design/SKILL.md +4 -2
  186. package/dist/agent-src/skills/command-routing/SKILL.md +3 -4
  187. package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +127 -139
  188. package/dist/agent-src/skills/corpus-grounding/ATTRIBUTION.md +39 -0
  189. package/dist/agent-src/skills/corpus-grounding/SKILL.md +8 -2
  190. package/dist/agent-src/skills/database/data/manifest.json +2 -2
  191. package/dist/agent-src/skills/database/data/query-tuning.csv +13 -13
  192. package/dist/agent-src/skills/design-intelligence/references/integration-mapping.md +13 -10
  193. package/dist/agent-src/skills/design-system-capture/SKILL.md +0 -3
  194. package/dist/agent-src/skills/estimate-ticket/SKILL.md +1 -1
  195. package/dist/agent-src/skills/fe-design/references/design-patterns.md +49 -2
  196. package/dist/agent-src/skills/feature-planning/SKILL.md +1 -1
  197. package/dist/agent-src/skills/frontend-render-security/SKILL.md +9 -0
  198. package/dist/agent-src/skills/git-workflow/SKILL.md +44 -44
  199. package/dist/agent-src/skills/git-workflow/references/branch-update.md +312 -0
  200. package/dist/agent-src/skills/git-workflow/references/commit-subject.md +205 -0
  201. package/dist/agent-src/skills/iconography/SKILL.md +4 -2
  202. package/dist/agent-src/skills/image-provider-routing/SKILL.md +16 -5
  203. package/dist/agent-src/skills/jira-integration/SKILL.md +3 -3
  204. package/dist/agent-src/skills/logo-generation/SKILL.md +12 -8
  205. package/dist/agent-src/skills/merge-conflicts/SKILL.md +10 -4
  206. package/dist/agent-src/skills/po-discovery/SKILL.md +1 -1
  207. package/dist/agent-src/skills/refine-ticket/SKILL.md +4 -4
  208. package/dist/agent-src/skills/roadmap-writing/SKILL.md +2 -2
  209. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +4 -2
  210. package/dist/agent-src/skills/source-discovery/SKILL.md +1 -1
  211. package/dist/agent-src/skills/svg-authoring/SKILL.md +318 -0
  212. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +3 -1
  213. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
  214. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +1 -1
  215. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +2 -2
  216. package/dist/agent-src/skills/wireframe/SKILL.md +5 -2
  217. package/dist/agent-src/templates/AGENTS.md +1 -1
  218. package/dist/agent-src/templates/agent-settings.md +46 -129
  219. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +3 -3
  220. package/dist/agent-src/templates/command.md +2 -2
  221. package/dist/agent-src/templates/roadmaps.md +6 -1
  222. package/dist/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
  223. package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
  224. package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
  225. package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
  226. package/dist/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
  227. package/dist/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
  228. package/dist/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
  229. package/dist/agent-src/templates/skill.md +1 -1
  230. package/dist/cli/commands/uiRender.js +201 -4
  231. package/dist/cli/commands/uiRenderAsset.js +1308 -0
  232. package/dist/cli/commands/uiRenderAssetCompare.js +752 -0
  233. package/dist/cli/commands/uiRenderAssetGrid.js +265 -0
  234. package/dist/cli/commands/uiRenderAssetGrounds.js +323 -0
  235. package/dist/cli/commands/uiRenderAssetIsolation.js +85 -0
  236. package/dist/cli/commands/uiRenderAssetTypes.js +145 -0
  237. package/dist/cli/main.js +47 -1
  238. package/dist/cli/registry.js +2 -1
  239. package/dist/cli-delegate/check_update_banner.js +195 -119
  240. package/dist/cli-delegate/{chunk-S4UMZNES.js → chunk-4DBG5K7M.js} +5 -5
  241. package/dist/cli-delegate/{chunk-TRI6DQZ6.js → chunk-5GPULQBE.js} +60 -42
  242. package/dist/cli-delegate/{chunk-JQVYKIZA.js → chunk-6SRJTYJS.js} +33 -177
  243. package/dist/cli-delegate/chunk-6V5FMA3P.js +186 -0
  244. package/dist/cli-delegate/chunk-6YQC2HLF.js +415 -0
  245. package/dist/cli-delegate/{chunk-E4XIZDIB.js → chunk-7HKRE54K.js} +1 -64
  246. package/dist/cli-delegate/{chunk-7HQ52DHU.js → chunk-AL3RZ22D.js} +1 -1
  247. package/dist/cli-delegate/{chunk-DBH4AHDK.js → chunk-ED7KCMLB.js} +9 -11
  248. package/dist/cli-delegate/{chunk-NXEILF2K.js → chunk-F3QDG2GT.js} +481 -72
  249. package/dist/cli-delegate/{chunk-CQWX336L.js → chunk-G5VVIZRC.js} +3 -3
  250. package/dist/cli-delegate/{chunk-JY2I2DXV.js → chunk-H76PHZBI.js} +137 -60
  251. package/dist/cli-delegate/chunk-IAYTIIQW.js +67 -0
  252. package/dist/cli-delegate/{chunk-LIYTLH6O.js → chunk-KXXWJTDO.js} +5 -10
  253. package/dist/cli-delegate/{chunk-T7L2QK3K.js → chunk-LQOCRFWT.js} +1 -1
  254. package/dist/cli-delegate/{chunk-S4YWNRKO.js → chunk-MDPPKQCQ.js} +34 -1
  255. package/dist/cli-delegate/chunk-OAFSJBHH.js +272 -0
  256. package/dist/cli-delegate/{chunk-GKE7ZVFA.js → chunk-PWX7CKMD.js} +1 -1
  257. package/dist/cli-delegate/{chunk-NDJLNC6Q.js → chunk-T6BP34WI.js} +1 -0
  258. package/dist/cli-delegate/{chunk-RQNNW7IF.js → chunk-T7XSJSUQ.js} +433 -632
  259. package/dist/cli-delegate/{chunk-NQ7WT43P.js → chunk-TMWYUOK4.js} +75 -12
  260. package/dist/cli-delegate/{chunk-EEHDXSYD.js → chunk-WQWXGIWB.js} +12 -273
  261. package/dist/cli-delegate/{chunk-QLDHIPWR.js → chunk-XQTPXKFA.js} +1 -1
  262. package/dist/cli-delegate/cmd_analyze_session.js +223 -43
  263. package/dist/cli-delegate/cmd_brand_status.js +3 -2
  264. package/dist/cli-delegate/cmd_conformance.js +489 -238
  265. package/dist/cli-delegate/cmd_converge.js +3 -3
  266. package/dist/cli-delegate/cmd_doctor.js +15 -12
  267. package/dist/cli-delegate/cmd_doctor_neighbours.js +11 -4
  268. package/dist/cli-delegate/cmd_explain.js +43 -19
  269. package/dist/cli-delegate/cmd_export.js +10 -10
  270. package/dist/cli-delegate/cmd_git_convention.js +1851 -0
  271. package/dist/cli-delegate/cmd_handoff.js +40 -21
  272. package/dist/cli-delegate/cmd_mcp_available.js +3 -2
  273. package/dist/cli-delegate/cmd_migrate.js +3 -3
  274. package/dist/cli-delegate/cmd_packs_active.js +4 -3
  275. package/dist/cli-delegate/cmd_prune.js +10 -10
  276. package/dist/cli-delegate/cmd_route_audit.js +7 -7
  277. package/dist/cli-delegate/cmd_route_explain.js +5 -5
  278. package/dist/cli-delegate/cmd_session_recycle.js +9 -7
  279. package/dist/cli-delegate/cmd_settings_check.js +54 -7
  280. package/dist/cli-delegate/cmd_settings_get.js +18 -8
  281. package/dist/cli-delegate/cmd_settings_migrate.js +10 -10
  282. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  283. package/dist/cli-delegate/cmd_sync.js +10 -10
  284. package/dist/cli-delegate/cmd_uninstall.js +10 -10
  285. package/dist/cli-delegate/cmd_update.js +7 -7
  286. package/dist/cli-delegate/cmd_upgrade.js +7 -7
  287. package/dist/cli-delegate/cmd_validate.js +10 -10
  288. package/dist/cli-delegate/cmd_versions.js +5 -5
  289. package/dist/cli-delegate/gate_budget.js +1 -1
  290. package/dist/cli-delegate/gate_execute.js +2 -2
  291. package/dist/cli-delegate/roadmap_gates.js +2 -2
  292. package/dist/discovery/deprecation-report.md +1 -1
  293. package/dist/discovery/discovery-manifest.json +171 -107
  294. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  295. package/dist/discovery/discovery-manifest.summary.md +7 -7
  296. package/dist/discovery/dormancy-report.md +1 -1
  297. package/dist/discovery/orphan-report.md +1 -1
  298. package/dist/discovery/packs.json +41 -22
  299. package/dist/discovery/trust-report.md +3 -3
  300. package/dist/discovery/workspaces.json +16 -11
  301. package/dist/hooks/dispatch.js +2520 -1924
  302. package/dist/hooks/dispatch.sha256 +1 -1
  303. package/dist/hooks/svg_rules.chunk.cjs +1626 -0
  304. package/dist/hooks/svg_rules.chunk.cjs.sha256 +1 -0
  305. package/dist/install/install.mjs +462 -431
  306. package/dist/install/installThinLayer.js +40 -12
  307. package/dist/install/installedRuleLinks.js +105 -19
  308. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  309. package/dist/mcp/mcp-cloudflare-catalogue.json +2 -2
  310. package/dist/mcp/registry-manifest.json +5 -5
  311. package/dist/mcp/server.json +2 -2
  312. package/dist/mcp/server.mjs +3063 -2160
  313. package/dist/router.json +1 -1
  314. package/dist/scripts/_lib/agent_settings.js +15 -120
  315. package/dist/scripts/_lib/compile_time_toggles.js +12 -21
  316. package/dist/scripts/_lib/git_convention.js +232 -0
  317. package/dist/scripts/_lib/global_deploy_inventory.js +730 -0
  318. package/dist/scripts/_lib/installed_layer.js +344 -18
  319. package/dist/scripts/_lib/package_root.js +68 -0
  320. package/dist/scripts/_lib/rule_law_section.js +1 -1
  321. package/dist/scripts/_lib/scan_scope.js +105 -0
  322. package/dist/scripts/_lib/settings_removed_keys.js +168 -0
  323. package/dist/scripts/_lib/svg_dom.js +284 -0
  324. package/dist/scripts/_lib/svg_geometry.js +477 -0
  325. package/dist/scripts/_lib/svg_motion.js +179 -0
  326. package/dist/scripts/_lib/svg_rules.js +1337 -0
  327. package/dist/scripts/_lib/svg_urls.js +67 -0
  328. package/dist/scripts/_lib/thin_rules.js +80 -3
  329. package/dist/scripts/lint_svg_asset.js +324 -0
  330. package/dist/server/app.js +2 -1
  331. package/dist/server/gitKeysGate.js +105 -0
  332. package/dist/server/routes/settings.js +67 -8
  333. package/dist/server/routes/wizard.js +4 -0
  334. package/dist/server/schemas/settings.js +23 -81
  335. package/dist/shared/skillRanking.js +30 -4
  336. package/dist/ui/assets/{index-Cwq4d0hX.js → index-C3djEJah.js} +2 -2
  337. package/dist/ui/index.html +1 -1
  338. package/docs/MIGRATION.md +72 -1
  339. package/docs/contracts/settings-classes.md +35 -65
  340. package/docs/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
  341. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
  342. package/docs/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
  343. package/docs/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
  344. package/docs/guidelines/agent-infra/layered-settings.md +13 -1
  345. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  346. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
  347. package/docs/guidelines/agent-infra/size-and-scope.md +36 -0
  348. package/docs/guidelines/design-antipatterns.md +1 -1
  349. package/docs/guidelines/php/git.md +15 -2
  350. package/package.json +4 -3
  351. package/src/agent-src/scripts/gate_budget.ts +47 -23
  352. package/src/agent-src/scripts/gate_execute.ts +12 -4
  353. package/src/agent-src/templates/AGENTS.md +1 -1
  354. package/src/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
  355. package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
  356. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
  357. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
  358. package/src/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
  359. package/src/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
  360. package/src/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
  361. package/src/config/agent-settings.template.yml +79 -312
  362. package/src/config/agents-paths.yml +16 -0
  363. package/src/config/assurance-capability-registry.json +7 -3
  364. package/src/config/ci-local-parity.yml +3 -0
  365. package/src/config/continuity-surface.json +3 -3
  366. package/src/config/discovery/packs.yml +17 -1
  367. package/src/config/evaluator-budgets.json +19 -6
  368. package/src/config/gate-coverage.yml +65 -23
  369. package/src/config/gate-violation-baselines.json +56 -16
  370. package/src/config/gitignore-block.txt +19 -0
  371. package/src/config/hook-bundle-budget.json +1 -1
  372. package/src/config/release-gate-locality.yml +2 -1
  373. package/src/config/routing-coverage-seed.json +55 -6
  374. package/src/config/rule-law-ceilings.json +12 -6
  375. package/src/config/rule-obligations.json +833 -0
  376. package/src/install/installThinLayer.ts +76 -10
  377. package/src/install/installedRuleLinks.ts +105 -17
  378. package/src/scripts/_cli/cmd_analyze_session.ts +9 -15
  379. package/src/scripts/_cli/cmd_conformance.ts +13 -2
  380. package/src/scripts/_cli/cmd_doctor.ts +10 -10
  381. package/src/scripts/_cli/cmd_doctor_neighbours.ts +133 -0
  382. package/src/scripts/_cli/cmd_explain.ts +72 -14
  383. package/src/scripts/_cli/cmd_git_convention.ts +637 -0
  384. package/src/scripts/_cli/cmd_settings_check.ts +66 -8
  385. package/src/scripts/_cli/cmd_settings_get.ts +18 -3
  386. package/src/scripts/_cli/doctor_execution.ts +72 -1
  387. package/src/scripts/_dispatch.bash +37 -2
  388. package/src/scripts/_lib/agent_settings.ts +15 -124
  389. package/src/scripts/_lib/blocked_by_marker.ts +1 -1
  390. package/src/scripts/_lib/compile_time_toggles.ts +12 -21
  391. package/src/scripts/_lib/dispatch_import_closure.ts +163 -0
  392. package/src/scripts/_lib/git_base_ref.ts +92 -0
  393. package/src/scripts/_lib/git_convention.ts +291 -0
  394. package/src/scripts/_lib/git_convention_carrier.ts +389 -0
  395. package/src/scripts/_lib/git_convention_grammar.ts +246 -0
  396. package/src/scripts/_lib/git_convention_measure.ts +344 -0
  397. package/src/scripts/_lib/global_deploy_inventory.ts +74 -0
  398. package/src/scripts/_lib/graph_feeder_record.ts +236 -13
  399. package/src/scripts/_lib/installed_layer.ts +448 -23
  400. package/src/scripts/_lib/knowledge_global.ts +14 -1
  401. package/src/scripts/_lib/module_reach.ts +456 -0
  402. package/src/scripts/_lib/neighbour_contradictions.ts +236 -0
  403. package/src/scripts/_lib/neighbour_tool_use.ts +8 -10
  404. package/src/scripts/_lib/ratification_artifact.ts +220 -1
  405. package/src/scripts/_lib/ratification_subject.ts +92 -0
  406. package/src/scripts/_lib/release_findings_ingest.ts +15 -7
  407. package/src/scripts/_lib/release_highlights.ts +5 -0
  408. package/src/scripts/_lib/rule_law_section.ts +1 -1
  409. package/src/scripts/_lib/rule_obligations.ts +205 -0
  410. package/src/scripts/_lib/self_repair.ts +1 -1
  411. package/src/scripts/_lib/settings_removed_keys.ts +173 -0
  412. package/src/scripts/_lib/svg_dom.ts +318 -0
  413. package/src/scripts/_lib/svg_geometry.ts +480 -0
  414. package/src/scripts/_lib/svg_motion.ts +208 -0
  415. package/src/scripts/_lib/svg_rules.ts +1453 -0
  416. package/src/scripts/_lib/svg_urls.ts +72 -0
  417. package/src/scripts/_lib/test_red_state.ts +5 -0
  418. package/src/scripts/_lib/thin_rules.ts +83 -3
  419. package/src/scripts/_lib/touched_file_quality.ts +142 -6
  420. package/src/scripts/_lib/verification_command.ts +59 -0
  421. package/src/scripts/_lib/verify_clause.ts +27 -17
  422. package/src/scripts/_lib/worker_budget.ts +1 -1
  423. package/src/scripts/adr/regenerate_index.ts +16 -1
  424. package/src/scripts/ai_council/config.ts +7 -7
  425. package/src/scripts/ai_council/modification_review.ts +100 -0
  426. package/src/scripts/ai_council/modification_review_questions.ts +90 -0
  427. package/src/scripts/ai_council/orchestrator.ts +5 -5
  428. package/src/scripts/ai_council/spend_gate.ts +18 -7
  429. package/src/scripts/ai_team/config.ts +11 -16
  430. package/src/scripts/audit_user_type_axis.ts +20 -8
  431. package/src/scripts/bench_ab_clone.ts +1 -2
  432. package/src/scripts/bench_concern_spawn_path.ts +129 -0
  433. package/src/scripts/bench_graph_feeder_latency.ts +584 -0
  434. package/src/scripts/check_agent_artifact_location.ts +36 -0
  435. package/src/scripts/check_branch_freshness.ts +147 -24
  436. package/src/scripts/check_enforcement_coverage.ts +130 -0
  437. package/src/scripts/check_evaluator_budgets.ts +4 -0
  438. package/src/scripts/check_finding_dispositions.ts +88 -25
  439. package/src/scripts/check_gate_coverage.ts +4 -3
  440. package/src/scripts/check_gate_reachability.ts +48 -1
  441. package/src/scripts/check_generator_sync.ts +48 -0
  442. package/src/scripts/check_hook_bundle_composition.ts +107 -0
  443. package/src/scripts/check_kernel_edit_ratified.ts +86 -6
  444. package/src/scripts/check_pack_size.ts +1 -1
  445. package/src/scripts/check_release_manifest_content.ts +189 -0
  446. package/src/scripts/check_standing_rule_delivery.ts +96 -0
  447. package/src/scripts/check_suppression_hygiene.ts +2 -5
  448. package/src/scripts/ci_settle.ts +42 -5
  449. package/src/scripts/classify_merge_risk.ts +320 -0
  450. package/src/scripts/closure_scan.ts +91 -1
  451. package/src/scripts/command_suggester/settings.ts +8 -108
  452. package/src/scripts/command_suggester/types.ts +4 -5
  453. package/src/scripts/consumer_matrix.ts +102 -0
  454. package/src/scripts/context_hygiene_hook.ts +13 -23
  455. package/src/scripts/cost/preflight.mjs +12 -1
  456. package/src/scripts/council_cli.ts +7 -7
  457. package/src/scripts/dispatch_r2_reviewer.ts +24 -11
  458. package/src/scripts/explain_run.ts +8 -13
  459. package/src/scripts/generate_git_convention_grammar.ts +127 -0
  460. package/src/scripts/generate_host_cost_table.ts +20 -3
  461. package/src/scripts/handoff_context_hook.ts +86 -37
  462. package/src/scripts/hook_manifest.json +1 -1
  463. package/src/scripts/hook_manifest.yaml +25 -6
  464. package/src/scripts/hooks/block_config_weakening.ts +48 -5
  465. package/src/scripts/hooks/block_plumbing_writes.ts +8 -4
  466. package/src/scripts/hooks/block_speaking_inbox_dir.ts +16 -1
  467. package/src/scripts/hooks/concern_registry.ts +2 -0
  468. package/src/scripts/hooks/delegation_nudge_hook.ts +2 -3
  469. package/src/scripts/hooks/design_pass_hook.ts +157 -3
  470. package/src/scripts/hooks/evidence_independence.ts +12 -4
  471. package/src/scripts/hooks/mcp_usage_observation_hook.ts +121 -0
  472. package/src/scripts/hooks/push_settle_hook.ts +4 -3
  473. package/src/scripts/hooks/rule_inject_hook.ts +44 -3
  474. package/src/scripts/hooks/state_io.ts +8 -4
  475. package/src/scripts/hooks/svg_obligation.ts +497 -0
  476. package/src/scripts/hooks/svg_rules_loader.ts +133 -0
  477. package/src/scripts/hooks/telemetry_usage_hook.ts +7 -46
  478. package/src/scripts/hooks/turn_end_gate_hook.ts +6 -3
  479. package/src/scripts/install-hooks.sh +42 -14
  480. package/src/scripts/install.ts +7 -31
  481. package/src/scripts/lint_blocker_citations.ts +198 -0
  482. package/src/scripts/lint_consolidation_lineage.ts +6 -3
  483. package/src/scripts/lint_design_quality.ts +60 -12
  484. package/src/scripts/lint_evidence_artifacts.ts +9 -0
  485. package/src/scripts/lint_hook_concern_budget.ts +10 -21
  486. package/src/scripts/lint_motion_authority_drift.ts +27 -0
  487. package/src/scripts/lint_pack_boundaries.ts +406 -28
  488. package/src/scripts/lint_roadmap_blockers.ts +282 -29
  489. package/src/scripts/lint_roadmap_complexity.ts +4 -2
  490. package/src/scripts/lint_rule_law_section.ts +151 -21
  491. package/src/scripts/lint_rule_skill_pack_reach.ts +17 -0
  492. package/src/scripts/lint_settings_classes.ts +1 -1
  493. package/src/scripts/lint_svg_asset.ts +365 -0
  494. package/src/scripts/lint_ticked_unmet_criteria.ts +165 -0
  495. package/src/scripts/lint_workflow_security.ts +12 -1
  496. package/src/scripts/measure_skill_ranker_baseline.ts +5 -0
  497. package/src/scripts/model_rule_injection.ts +3 -3
  498. package/src/scripts/onboarding_gate_hook.ts +7 -6
  499. package/src/scripts/print_required_checks.ts +15 -3
  500. package/src/scripts/probe_host_compliance.ts +33 -5
  501. package/src/scripts/probe_turnaround.ts +183 -3
  502. package/src/scripts/ratification_header.ts +77 -0
  503. package/src/scripts/refusal_envelope.ts +138 -0
  504. package/src/scripts/release_publication.ts +29 -3
  505. package/src/scripts/report_dispatch_import_closure.ts +76 -0
  506. package/src/scripts/report_installed_rule_links.ts +118 -1
  507. package/src/scripts/report_module_reach.ts +212 -0
  508. package/src/scripts/report_obligation_mechanism.ts +16 -18
  509. package/src/scripts/report_parked_blockers.ts +222 -0
  510. package/src/scripts/report_required_checks_drift.ts +196 -0
  511. package/src/scripts/report_skill_ranker_confusion.ts +103 -2
  512. package/src/scripts/report_standing_payload_by_host.ts +1 -1
  513. package/src/scripts/routing_doctor.ts +2 -2
  514. package/src/scripts/schemas/agent-settings.schema.json +17 -31
  515. package/src/scripts/schemas/command.schema.json +1 -1
  516. package/src/scripts/schemas/skill.schema.json +1 -1
  517. package/src/scripts/self_review_gate.ts +39 -2
  518. package/src/scripts/skill_tools/score_skill_relevance.ts +28 -19
  519. package/src/scripts/sync_pr_branch.ts +403 -132
  520. package/src/scripts/trigger_eval_grandfather.json +0 -16
  521. package/src/server/schemas/settings.ts +33 -177
  522. package/src/shared/skillRanking.ts +53 -4
  523. package/dist/cli-delegate/chunk-NYX3L2PZ.js +0 -99
  524. package/src/scripts/_lib/config_chain.ts +0 -477
  525. package/src/scripts/_lib/conformance_report.ts +0 -403
  526. package/src/scripts/_lib/eval_discrimination.ts +0 -95
  527. package/src/scripts/_lib/evaluator_promotion.ts +0 -225
  528. package/src/scripts/_lib/file_slicer.ts +0 -117
  529. package/src/scripts/_lib/legacy_boundary_map.ts +0 -228
  530. package/src/scripts/_lib/minimality_tiebreak.ts +0 -168
  531. package/src/scripts/_lib/overbuild_lens_contract.ts +0 -196
  532. package/src/scripts/_lib/role_split.ts +0 -338
@@ -30,7 +30,8 @@
30
30
  * definition. It runs the same contract as the review-side canary in
31
31
  * `docs/contracts/adversarial-review-protocol.md` § 6 (rotating class, sealed
32
32
  * record, NEVER SHIPS) and is deliberately kept OFF the default CI path: it
33
- * mutates the tree, so it is an operator-invoked biannual experiment, not a
33
+ * mutates the tree, so it is a scheduled experiment (`.github/workflows/gate-canary.yml`,
34
+ * monthly, ledger uploaded as a run artifact) or an operator run, never a
34
35
  * per-PR gate. Every plant is reverted in a `finally`.
35
36
  *
36
37
  * CLI:
@@ -415,8 +416,8 @@ function report_negative_control_inventory(specs: readonly GateSpec[]): void {
415
416
  // The arithmetic is the guard against skimming: two numbers that reconcile
416
417
  // against the enforced total cannot be read as "all of them checked".
417
418
  process.stdout.write(
418
- ` ⚠️ declared, not run — the mutating --canary path is operator-invoked and off the per-PR workflow, ` +
419
- `so no negative control ran here.\n`,
419
+ ` ⚠️ declared, not run — the mutating --canary path is off the per-PR workflow (it runs monthly ` +
420
+ `in .github/workflows/gate-canary.yml), so no negative control ran here.\n`,
420
421
  );
421
422
  for (const s of without) {
422
423
  process.stdout.write(` · ${s.id}: ${s.no_canary_reason ?? '(no reason recorded)'}\n`);
@@ -42,6 +42,7 @@ import {
42
42
  resetSourceCache,
43
43
  type InventoryVerdict,
44
44
  } from './_lib/loop_surfaces.js';
45
+ import { analyseModuleReach, groupCounts } from './_lib/module_reach.js';
45
46
 
46
47
  const REPO_ROOT = process.cwd();
47
48
  const TASKFILES_DIR = 'taskfiles';
@@ -312,6 +313,10 @@ function runGate(root: string): number {
312
313
  units: 'exemption row(s) + unreachable target(s) + declared loop instrument(s)',
313
314
  roots: [EXEMPTIONS_REL, INVENTORY_REL, ROOT_TASKFILE, TASKFILES_DIR],
314
315
  });
316
+ // Phase 3.1 of road-to-modules-that-something-calls.md: five numbers beside
317
+ // this gate's existing verdicts, printed whether the gate passes or fails —
318
+ // reported, enforcing nothing, the way the estate gate prints its draft count.
319
+ process.stdout.write(moduleReachLine(moduleReachSummary(root)));
315
320
  const inventoryClean = inv.shape.length === 0 && inv.reach.length === 0;
316
321
  if (v.unreasoned.length === 0 && v.stale.length === 0 && inventoryClean) {
317
322
  process.stdout.write(
@@ -506,13 +511,54 @@ function selfTest(): number {
506
511
  }
507
512
  }
508
513
 
514
+ export interface ModuleReachSummary {
515
+ /** The four group counts — the roadmap's "four group counts", over the unreferenced-by-name set only. */
516
+ groups: Record<'contract-test' | 'open-or-deferred-step' | 'named-outside-open-step' | 'named-in-none', number>;
517
+ /** "the total of modules reached by nothing" (import edges + run-by-path) — the fifth number. */
518
+ reachedByNothing: number;
519
+ /**
520
+ * Not one of the five — the size of the unreferenced-by-name set the four
521
+ * groups partition. Kept on the summary because it is a free cross-check
522
+ * (it must equal the sum of `groups`); never printed as a sixth number.
523
+ */
524
+ unreferencedTotal: number;
525
+ }
526
+
527
+ /**
528
+ * The five module-reach numbers (road-to-modules-that-something-calls.md
529
+ * Phase 3.1) — reported beside this gate's own verdicts, the way the estate
530
+ * gate prints its draft-roadmap count: a number that moves in a change's own
531
+ * gate output, enforcing nothing.
532
+ */
533
+ export function moduleReachSummary(root: string): ModuleReachSummary {
534
+ const { modules } = analyseModuleReach(root);
535
+ const unreferenced = modules.filter((m) => !m.namedByProduction);
536
+ return {
537
+ groups: groupCounts(unreferenced),
538
+ reachedByNothing: modules.filter((m) => !m.reachedByImportOrPath).length,
539
+ unreferencedTotal: unreferenced.length,
540
+ };
541
+ }
542
+
543
+ export function moduleReachLine(s: ModuleReachSummary): string {
544
+ return (
545
+ `module reach (reported, not gated), src/scripts/_lib: ` +
546
+ `contract-test ${String(s.groups['contract-test'])} · ` +
547
+ `open-or-deferred-step ${String(s.groups['open-or-deferred-step'])} · ` +
548
+ `named-outside-open-step ${String(s.groups['named-outside-open-step'])} · ` +
549
+ `named-in-none ${String(s.groups['named-in-none'])} · ` +
550
+ `REACHED-BY-NOTHING total ${String(s.reachedByNothing)}\n`
551
+ );
552
+ }
553
+
509
554
  export function main(argv: string[] = process.argv.slice(2), root = REPO_ROOT): number {
510
555
  if (argv.includes('--self-test')) return selfTest();
511
556
  if (argv.includes('--gate')) return runGate(root);
512
557
  const r = analyse(root);
513
558
  const inv = inventoryVerdict(root);
559
+ const moduleReach = moduleReachSummary(root);
514
560
  if (argv.includes('--json')) {
515
- process.stdout.write(`${JSON.stringify({ ...r, inventory: inv }, null, 2)}\n`);
561
+ process.stdout.write(`${JSON.stringify({ ...r, inventory: inv, moduleReach }, null, 2)}\n`);
516
562
  return 0;
517
563
  }
518
564
  // Emitted on the DEFAULT invocation too, not only under `--gate`: the
@@ -538,6 +584,7 @@ export function main(argv: string[] = process.argv.slice(2), root = REPO_ROOT):
538
584
  `prose-bound surfaces ${String(inv.proseBound.length)}\n`,
539
585
  );
540
586
  for (const f of inv.reach) process.stdout.write(` · ${f.id} — ${f.detail}\n`);
587
+ process.stdout.write(moduleReachLine(moduleReach));
541
588
  return 0;
542
589
  }
543
590
 
@@ -546,11 +546,59 @@ const HOST_LOWERING_TRIPLE: Triple = {
546
546
  },
547
547
  };
548
548
 
549
+ const GRAMMAR_REFERENCE = 'src/skills/git-workflow/references/commit-subject.md';
550
+ const GRAMMAR_GENERATOR = 'src/scripts/generate_git_convention_grammar.ts';
551
+
552
+ /**
553
+ * The commit-subject reference is the fallback a command reads when the
554
+ * `agent-config` binary cannot run, so its grammar block has to be the grammar
555
+ * the binary runs. The page itself is a source too: a hand edit to the block is
556
+ * the drift this row exists to catch.
557
+ */
558
+ const GIT_CONVENTION_GRAMMAR_TRIPLE: Triple = {
559
+ id: 'git-convention-grammar',
560
+ output: GRAMMAR_REFERENCE,
561
+ remedy: './scripts-run src/scripts/generate_git_convention_grammar',
562
+ why: 'the reference carries a grammar and measurement block rendered from the modules the git:convention verb runs',
563
+ sourcesOf() {
564
+ return {
565
+ ok: true,
566
+ sources: [
567
+ { kind: 'file', value: 'src/scripts/_lib/git_convention_grammar.ts' },
568
+ { kind: 'file', value: 'src/scripts/_lib/git_convention_measure.ts' },
569
+ { kind: 'file', value: GRAMMAR_GENERATOR },
570
+ { kind: 'file', value: GRAMMAR_REFERENCE },
571
+ ],
572
+ };
573
+ },
574
+ regenerate(root, workDir) {
575
+ const outFile = path.join(workDir, 'commit-subject.md');
576
+ const tsx = path.join(root, 'node_modules', '.bin', process.platform === 'win32' ? 'tsx.cmd' : 'tsx');
577
+ if (!fs.existsSync(tsx)) {
578
+ return { ok: false, reason: `no tsx at ${path.relative(root, tsx)} — run \`npm ci\` before this gate` };
579
+ }
580
+ const res = spawnSync(tsx, [path.join(root, GRAMMAR_GENERATOR), '--out', outFile], {
581
+ cwd: root,
582
+ encoding: 'utf8',
583
+ maxBuffer: 64 * 1024 * 1024,
584
+ });
585
+ if (res.status !== 0) {
586
+ return { ok: false, reason: `generate_git_convention_grammar exited ${String(res.status)}: ${(res.stderr ?? '').trim()}` };
587
+ }
588
+ try {
589
+ return { ok: true, text: fs.readFileSync(outFile, 'utf8') };
590
+ } catch (e) {
591
+ return { ok: false, reason: `generate_git_convention_grammar reported success but wrote no readable file (${String(e)})` };
592
+ }
593
+ },
594
+ };
595
+
549
596
  export const REGISTRY: readonly Triple[] = [
550
597
  CENSUS_TRIPLE,
551
598
  INSTALL_BUNDLE_TRIPLE,
552
599
  HOOK_MANIFEST_TRIPLE,
553
600
  HOST_LOWERING_TRIPLE,
601
+ GIT_CONVENTION_GRAMMAR_TRIPLE,
554
602
  ];
555
603
 
556
604
  // ---------------------------------------------------------------------------
@@ -191,6 +191,95 @@ export function verdict(a: Analysis, budget: Budget): string[] {
191
191
  return findings;
192
192
  }
193
193
 
194
+ /**
195
+ * The raise rule, enforced against the base revision.
196
+ *
197
+ * `road-to-a-ratification-fence-that-follows-its-imports` 3.2. The budget's
198
+ * `shrink_only_note` used to say a raise needs a `raise_log` entry and that
199
+ * "the gate prints the rule but cannot enforce it, because a raise and a
200
+ * lowering are the same edit to a number". Against the base revision they are
201
+ * not: a working `max_bytes` above the base's is a raise, and it passes only if
202
+ * `raise_log` gained an entry — one absent from the base's log — whose `to`
203
+ * equals the new ceiling. A lowering needs nothing. The comparison is the
204
+ * merged value against the base, because that is what ships; a ceiling raised
205
+ * and lowered inside one branch is judged by where it ends.
206
+ *
207
+ * `baseRaw` is the base revision's budget file, or `null` when it has none
208
+ * (the registration diff), which is not a raise.
209
+ */
210
+ export function raiseFindings(baseRaw: string | null, workingRaw: string): string[] {
211
+ if (baseRaw === null) {
212
+ return [];
213
+ }
214
+ const base = JSON.parse(baseRaw) as Record<string, unknown>;
215
+ const working = JSON.parse(workingRaw) as Record<string, unknown>;
216
+ const baseMax = base['max_bytes'];
217
+ const workingMax = working['max_bytes'];
218
+ if (typeof baseMax !== 'number' || typeof workingMax !== 'number' || workingMax <= baseMax) {
219
+ return [];
220
+ }
221
+ const baseLog = Array.isArray(base['raise_log']) ? (base['raise_log'] as unknown[]) : [];
222
+ const workingLog = Array.isArray(working['raise_log']) ? (working['raise_log'] as unknown[]) : [];
223
+ const seen = new Set(baseLog.map((e) => JSON.stringify(e)));
224
+ const gained = workingLog.filter((e) => !seen.has(JSON.stringify(e)));
225
+ const matching = gained.find((e) => isRecord(e) && e['to'] === workingMax);
226
+ if (matching === undefined) {
227
+ return [
228
+ `max_bytes raised from ${String(baseMax)} to ${String(workingMax)} against the base revision ` +
229
+ `with no new raise_log entry whose \`to\` is ${String(workingMax)}. A raise needs a recorded ` +
230
+ `reason in ${BUDGET_REL}'s raise_log naming what was added and why it could not be avoided.`,
231
+ ];
232
+ }
233
+ const problems = raiseEntryProblems(matching as Record<string, unknown>, baseMax);
234
+ return problems.length === 0
235
+ ? []
236
+ : [`the raise_log entry for ${String(workingMax)} is incomplete: ${problems.join('; ')}.`];
237
+ }
238
+
239
+ function isRecord(v: unknown): v is Record<string, unknown> {
240
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
241
+ }
242
+
243
+ /** The prose fields an entry must carry, matching the entry the log already holds. */
244
+ const RAISE_REASON_FIELDS = ['what_was_added', 'why_it_could_not_be_avoided'] as const;
245
+
246
+ /**
247
+ * What a raise entry must say. A bare `{ "to": N }` matched the first version
248
+ * of this rule, which a ratification reviewer refused on: a log entry with no
249
+ * reason is the empty log the rule exists to refuse, wearing a key.
250
+ */
251
+ export function raiseEntryProblems(entry: Record<string, unknown>, baseMax: number): string[] {
252
+ const problems: string[] = [];
253
+ if (entry['from'] !== baseMax) {
254
+ problems.push(`\`from\` must be the base ceiling ${String(baseMax)}`);
255
+ }
256
+ if (typeof entry['date'] !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(entry['date'])) {
257
+ problems.push('`date` must be YYYY-MM-DD');
258
+ }
259
+ for (const field of RAISE_REASON_FIELDS) {
260
+ const v = entry[field];
261
+ if (typeof v !== 'string' || v.trim().length < 20) {
262
+ problems.push(`\`${field}\` must say what happened, in at least a sentence`);
263
+ }
264
+ }
265
+ return problems;
266
+ }
267
+
268
+ /** The base revision's budget file, `null` when absent there, `undefined` when no base resolves. */
269
+ function readBaseBudget(root: string, explicit: string | undefined): string | null | undefined {
270
+ const candidates = explicit !== undefined ? [explicit] : ['origin/main', 'main'];
271
+ for (const ref of candidates) {
272
+ const ok = spawnSync('git', ['rev-parse', '--verify', '--quiet', ref], {
273
+ cwd: root,
274
+ stdio: ['ignore', 'ignore', 'ignore'],
275
+ });
276
+ if (ok.status !== 0) continue;
277
+ const shown = spawnSync('git', ['show', `${ref}:${BUDGET_REL}`], { cwd: root, encoding: 'utf-8' });
278
+ return shown.status === 0 ? shown.stdout : null;
279
+ }
280
+ return undefined;
281
+ }
282
+
194
283
  /**
195
284
  * Build the hook bundle to a throwaway path and return its metafile JSON.
196
285
  *
@@ -331,6 +420,24 @@ export function main(argv: readonly string[] = process.argv.slice(2), root: stri
331
420
  }
332
421
 
333
422
  const findings = verdict(analysis, budget);
423
+ const baseAt = argv.indexOf('--base-ref');
424
+ const baseBudget = readBaseBudget(root, baseAt >= 0 ? argv[baseAt + 1] : undefined);
425
+ if (baseBudget === undefined) {
426
+ // In CI an unresolvable base is a broken checkout, not a registration
427
+ // diff: refusing there is the difference between a rule and a notice.
428
+ // Locally a missing base is ordinary (a fresh clone without origin), so
429
+ // it is said rather than failed.
430
+ if (process.env['GITHUB_ACTIONS'] === 'true') {
431
+ process.stderr.write(
432
+ 'check_hook_bundle_composition: no base revision resolved in CI — the max_bytes raise ' +
433
+ 'rule cannot be evaluated, and this gate fails closed rather than skip it\n',
434
+ );
435
+ return 2;
436
+ }
437
+ process.stdout.write('raise rule: no base revision resolved — the max_bytes raise check was not evaluated\n');
438
+ } else {
439
+ findings.push(...raiseFindings(baseBudget, fs.readFileSync(path.join(root, BUDGET_REL), 'utf-8')));
440
+ }
334
441
  // Reported on BOTH paths, red included: a census that goes quiet exactly
335
442
  // when the gate fires is the shape `reportScanned` exists to prevent.
336
443
  reportScanned({
@@ -33,8 +33,10 @@
33
33
  * hook plumbing — the YAML sources `hook_manifest.yaml` and
34
34
  * `host_lowering.yaml`, their compiled siblings `hook_manifest.json` and
35
35
  * `host_lowering.json`, the dispatcher `hooks/dispatch_hook.ts`, the
36
- * kernel-rule list `_lib/kernel_rules.ts`, a `*-dispatcher.sh`, either hook
37
- * budget file (see `PLUMBING_SOURCE_RE`) — or this gate itself, so it cannot
36
+ * kernel-rule list `_lib/kernel_rules.ts`, a `*-dispatcher.sh`, the token,
37
+ * latency and bundle budget files (see `PLUMBING_SOURCE_RE`), and every module
38
+ * the dispatcher imports that decides an exit code (derived at run time, see
39
+ * `derivedPlumbing`) — or this gate itself, so it cannot
38
40
  * be weakened without its own record. Such a diff must carry a ratification
39
41
  * artifact under the ratifications directory with `verdict: ratified`, valid
40
42
  * per the ratification-artifact contract.
@@ -73,6 +75,7 @@ import * as path from 'node:path';
73
75
  import { fileURLToPath, pathToFileURL } from 'node:url';
74
76
 
75
77
  import { GateLedger } from './_lib/gate_ledger.js';
78
+ import { dispatchImportClosure, verdictModules } from './_lib/dispatch_import_closure.js';
76
79
  import { is_kernel_rule } from './_lib/kernel_rules.js';
77
80
  import { reportScanned } from './_lib/scan_scope.js';
78
81
  import {
@@ -92,6 +95,13 @@ export const SELF_PATH = 'src/scripts/check_kernel_edit_ratified.ts';
92
95
  /** The reader this gate shares with the artifact contract, also self-watched. */
93
96
  export const READER_PATH = 'src/scripts/_lib/ratification_artifact.ts';
94
97
 
98
+ /**
99
+ * The reader that derives the dispatcher's verdict-deciding imports. It decides
100
+ * part of this gate's reach, so narrowing it is narrowing the gate — watched as
101
+ * part of the mechanism for the reason `READER_PATH` is.
102
+ */
103
+ export const CLOSURE_READER_PATH = 'src/scripts/_lib/dispatch_import_closure.ts';
104
+
95
105
  /** The in-repo quorum policy. Present on every runner; absent means refuse. */
96
106
  export const POLICY_PATH = 'src/config/ratification-policy.json';
97
107
 
@@ -185,7 +195,67 @@ const GOVERNANCE_HOOK_RE = /^src\/scripts\/hooks\/block_[a-z0-9_]+\.ts$/;
185
195
  * is the diff where only the JSON moves.
186
196
  */
187
197
  const PLUMBING_SOURCE_RE =
188
- /^(?:src\/scripts\/hook_manifest\.(?:yaml|json)|src\/scripts\/hooks\/host_lowering\.(?:yaml|json)|src\/scripts\/hooks\/dispatch_hook\.ts|src\/scripts\/_lib\/kernel_rules\.ts|src\/scripts\/hooks\/[a-z0-9-]+-dispatcher\.sh|src\/config\/hook-(?:token|latency)-budget\.json)$/;
198
+ /^(?:src\/scripts\/hook_manifest\.(?:yaml|json)|src\/scripts\/hooks\/host_lowering\.(?:yaml|json)|src\/scripts\/hooks\/dispatch_hook\.ts|src\/scripts\/_lib\/kernel_rules\.ts|src\/scripts\/hooks\/[a-z0-9-]+-dispatcher\.sh|src\/config\/hook-(?:token|latency|bundle)-budget\.json)$/;
199
+
200
+ /**
201
+ * The derived half of the plumbing set: every module in the static import
202
+ * closure of `dispatch_hook.ts` that decides an exit code or a refusal, read by
203
+ * `_lib/dispatch_import_closure.ts`.
204
+ *
205
+ * `road-to-a-ratification-fence-that-follows-its-imports` 2.2. The pattern
206
+ * above stayed correct until `_resolve_execution_failure` moved from the
207
+ * dispatcher into `concern_failure_policy.ts` — release finding `21900086c1a0`:
208
+ * a diff deciding whether a crashed blocking concern refuses then carried no
209
+ * record. A hand list fails the same way the next time a function moves, so
210
+ * this half is computed from the import graph at run time, and a module the
211
+ * dispatcher newly imports that names an exit code joins it with no edit here.
212
+ * Concerns stay outside: the walk stops at the concern table, and a governance
213
+ * concern is already gated by `GOVERNANCE_HOOK_RE`.
214
+ *
215
+ * `hook-bundle-budget.json` joins the pattern for D3: its ceiling was raised on
216
+ * its own registration day, and a raised ceiling is a looser budget reached one
217
+ * file earlier than the bundle it bounds.
218
+ */
219
+ let _repoDerived: readonly string[] | null = null;
220
+ export function derivedPlumbing(root: string = REPO): readonly string[] {
221
+ if (root === REPO) {
222
+ _repoDerived ??= verdictModules(REPO);
223
+ return _repoDerived;
224
+ }
225
+ return verdictModules(root);
226
+ }
227
+
228
+ /**
229
+ * Modules that ARRIVE in the dispatcher's closure: non-concern modules present
230
+ * in the closure under `root` and absent from the closure under `baseRoot`.
231
+ *
232
+ * The classifier reads names, so a verdict-deciding module with neutral names
233
+ * (`acceptsExecution(): boolean`, no exit constant) reads as `payload` or
234
+ * `neither` — the gap the first ratification round of this change refused it
235
+ * on. A name-based classifier cannot close that gap; what can is watching the
236
+ * one moment such a module becomes reachable. So any module newly reachable
237
+ * from the dispatcher is gated on the diff that makes it reachable, whatever
238
+ * its class, and a reviewer reads it once. Modules already in the base closure
239
+ * are judged by class, so routine edits to a payload helper stay record-free.
240
+ *
241
+ * The other direction needs no extra rule: a module the base classes as
242
+ * `verdict` stays watched through the union in `evaluate` even when the head
243
+ * strips the names that classed it, so declassifying one is itself a gated
244
+ * edit of it.
245
+ *
246
+ * Meaningful only where the two trees differ — in CI, where the gate's code is
247
+ * the base revision's and `root` is the head. A local run with `root` equal to
248
+ * the gate's own tree sees no arrivals, and says nothing it cannot measure.
249
+ */
250
+ export function closureArrivals(root: string, baseRoot: string = REPO): string[] {
251
+ if (path.resolve(root) === path.resolve(baseRoot)) {
252
+ return [];
253
+ }
254
+ const base = new Set(dispatchImportClosure(baseRoot).map((e) => e.path));
255
+ return dispatchImportClosure(root)
256
+ .filter((e) => e.class !== 'concern' && !base.has(e.path))
257
+ .map((e) => e.path);
258
+ }
189
259
 
190
260
  /**
191
261
  * A kernel rule, in the source tree or in any projection.
@@ -212,7 +282,11 @@ export interface GatedPaths {
212
282
  }
213
283
 
214
284
  /** Partition a changed-file list into the surfaces this gate watches. */
215
- export function classifyPaths(files: readonly string[]): GatedPaths {
285
+ export function classifyPaths(
286
+ files: readonly string[],
287
+ derived: readonly string[] = derivedPlumbing(),
288
+ ): GatedPaths {
289
+ const derivedSet = new Set(derived);
216
290
  const kernelRules: string[] = [];
217
291
  const governanceHooks: string[] = [];
218
292
  const plumbing: string[] = [];
@@ -225,6 +299,7 @@ export function classifyPaths(files: readonly string[]): GatedPaths {
225
299
  if (
226
300
  p === SELF_PATH ||
227
301
  p === READER_PATH ||
302
+ p === CLOSURE_READER_PATH ||
228
303
  p === POLICY_PATH ||
229
304
  p === WORKFLOW_PATH ||
230
305
  ANCHOR_PATHS.includes(p)
@@ -241,7 +316,7 @@ export function classifyPaths(files: readonly string[]): GatedPaths {
241
316
  governanceHooks.push(p);
242
317
  continue;
243
318
  }
244
- if (PLUMBING_SOURCE_RE.test(p)) {
319
+ if (PLUMBING_SOURCE_RE.test(p) || derivedSet.has(p)) {
245
320
  plumbing.push(p);
246
321
  }
247
322
  }
@@ -319,7 +394,12 @@ export function evaluate(
319
394
  providerCount: number | null,
320
395
  ): GateResult {
321
396
  const lines: string[] = [];
322
- const gated = classifyPaths(files);
397
+ // The union of the closure read from the tree under review and from this
398
+ // script's own tree: under CI the gate code is the base revision's and
399
+ // `root` is the head, so a module present on either side is watched.
400
+ const gated = classifyPaths(files, [
401
+ ...new Set([...derivedPlumbing(), ...derivedPlumbing(root), ...closureArrivals(root)]),
402
+ ]);
323
403
  const scanned = files.length;
324
404
 
325
405
  // Every changed path is a planned target: the gate's denominator is the
@@ -332,7 +332,7 @@ export function payloadFingerprint(entryPath: string, size: number): string {
332
332
  * convention and the class is empty by observation.
333
333
  */
334
334
  const BOUND_PAYLOAD_EXCEPTIONS: readonly BoundPayloadException[] = [
335
- { fingerprint: '47e4328e71652a0375ade7eb4dac8a3e4b6df1c6e4e74caa75287266676cc9a6', path: 'agents/templates/.ai-council.yml.example', size: 30561, why: 'shipped council config TEMPLATE — a dotfile because the file it is copied to is one. RE-PINNED 2026-09-07, 29,872 -> 30,561 bytes: the exception is path-AND-size-bound by design, so this branch adding a `disabled_reason` honest-null block to the gemini seat in the template invalidated it and the gate refused the entry as unaccounted. The re-pin excepts the SAME path for the SAME reason at its measured new size — it does not widen the class, raise a cap, or except anything the gate was not already carrying.' },
335
+ { fingerprint: '6de9a60d02af4883ab8f09171673a44924ca78ddadd55518f743e95651d3d257', path: 'agents/templates/.ai-council.yml.example', size: 31548, why: 'shipped council config TEMPLATE — a dotfile because the file it is copied to is one. RE-PINNED 2026-10-06, 30,561 -> 31,548 bytes: the exception is path-AND-size-bound by design, so step 3.1 of road-to-a-spend-bound-only-where-one-was-set moving the template cost_budget and debate ceilings to 0 (ADR-279), removing the stale "always asks before invoking" sentence and explaining both invalidated it and the gate refused the entry as unaccounted. The re-pin excepts the SAME path for the SAME reason at its measured new size — it does not widen the class, raise a cap, or except anything the gate was not already carrying. (Previously RE-PINNED 2026-09-07, 29,872 -> 30,561 bytes, for a `disabled_reason` honest-null block on the gemini seat.)' },
336
336
  { fingerprint: 'd36a53951c184db7481139235056e90b53a853714b3a68b31ba1349ecb95ac1d', path: 'agents/templates/.ai-video.xml.example', size: 9209, why: 'shipped video-provider config template — same reason as the council template' },
337
337
  { fingerprint: 'f83229412cf8cceaadd0cb1934140a0c7c8277df43edc590f370572f6df6da98', path: 'dist/agent-src/templates/agents/.gitattributes.fragment', size: 2140, why: 'gitattributes fragment the installer appends to a consumer repo' },
338
338
  { fingerprint: 'a4f51dba3a66c0f2c3548e77961271ed4d7b5ec8a6661ea359ff044758f0d921', path: 'src/templates/minimal/.agent-settings.yml', size: 1042, why: 'the minimal-install settings template; the dot is the consumer-side filename' },
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Release-manifest content check — the content half beside
4
+ * `check_release_pr_shape`.
5
+ *
6
+ * The shape check lets a release PR carry `package.json`, `package-lock.json`
7
+ * and the three plugin manifests, and it reads only their NAMES. Smoke is
8
+ * skipped on release heads (`docs/contracts/release-pr-gating.md`), so an added
9
+ * script, a new dependency or a changed `bin` path could ride a release PR with
10
+ * no gate reading it. This compares each manifest against the base and fails on
11
+ * any difference outside the version fields the release writes.
12
+ *
13
+ * Version fields are named per file, never matched by key name anywhere: in
14
+ * `package-lock.json` every dependency also has a `version`, and a key-name
15
+ * rule would wave a dependency bump through as a version bump.
16
+ *
17
+ * Usage: check_release_manifest_content [--base REF] [--root DIR]
18
+ * --base REF ref the head is compared against (default: origin/main)
19
+ * --root DIR repository root to read the head and run git in (testing)
20
+ *
21
+ * Exit codes: 0 = only version fields differ · 1 = other difference · 2 = usage/env.
22
+ */
23
+
24
+ import { spawnSync } from 'node:child_process';
25
+ import * as fs from 'node:fs';
26
+ import * as path from 'node:path';
27
+ import { fileURLToPath, pathToFileURL } from 'node:url';
28
+
29
+ import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
30
+
31
+ const _HERE = fileURLToPath(import.meta.url);
32
+ const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
33
+
34
+ type Segment = string;
35
+ /** A JSON path pattern; `*` matches any array index. */
36
+ type Pattern = readonly Segment[];
37
+
38
+ /** The manifests a release PR may carry, and the fields the release writes in each. */
39
+ export const VERSION_FIELDS: Readonly<Record<string, readonly Pattern[]>> = {
40
+ 'package.json': [['version']],
41
+ 'package-lock.json': [['version'], ['packages', '', 'version']],
42
+ '.claude-plugin/marketplace.json': [['version'], ['metadata', 'version'], ['plugins', '*', 'version']],
43
+ '.augment-plugin/plugin.json': [['version']],
44
+ '.augment-plugin/marketplace.json': [['version'], ['metadata', 'version'], ['plugins', '*', 'version']],
45
+ };
46
+
47
+ function _matches(p: readonly Segment[], pat: Pattern): boolean {
48
+ if (p.length !== pat.length) return false;
49
+ return pat.every((seg, i) => seg === p[i] || (seg === '*' && /^\d+$/u.test(p[i] ?? '')));
50
+ }
51
+
52
+ function _render(p: readonly Segment[]): string {
53
+ return p.length === 0 ? '(root)' : p.map((s) => (/^\d+$/u.test(s) ? `[${s}]` : JSON.stringify(s))).join('.');
54
+ }
55
+
56
+ function _isObject(v: unknown): v is Record<string, unknown> {
57
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
58
+ }
59
+
60
+ /** Every JSON path at which `a` and `b` differ, leaf-first where both are containers. */
61
+ function _diffPaths(a: unknown, b: unknown, at: Segment[] = []): Segment[][] {
62
+ if (Array.isArray(a) && Array.isArray(b)) {
63
+ if (a.length !== b.length) return [at];
64
+ return a.flatMap((v, i) => _diffPaths(v, b[i], [...at, String(i)]));
65
+ }
66
+ if (_isObject(a) && _isObject(b)) {
67
+ const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
68
+ const out: Segment[][] = [];
69
+ for (const k of keys) {
70
+ if (!(k in a) || !(k in b)) {
71
+ out.push([...at, k]);
72
+ continue;
73
+ }
74
+ out.push(..._diffPaths(a[k], b[k], [...at, k]));
75
+ }
76
+ return out;
77
+ }
78
+ return JSON.stringify(a) === JSON.stringify(b) ? [] : [at];
79
+ }
80
+
81
+ /**
82
+ * The differences between `base` and `head` text of one manifest that are NOT a
83
+ * version-string change in a declared version field. Empty means in shape.
84
+ */
85
+ export function manifestDifferences(file: string, base: string | null, head: string | null): string[] {
86
+ if (base === null && head === null) return [];
87
+ if (base === null) return [`${file}: added — absent at the base`];
88
+ if (head === null) return [`${file}: removed — present at the base`];
89
+ let a: unknown;
90
+ let b: unknown;
91
+ try {
92
+ a = JSON.parse(base);
93
+ b = JSON.parse(head);
94
+ } catch (err) {
95
+ return [`${file}: not parseable JSON (${(err as Error).message})`];
96
+ }
97
+ const allowed = VERSION_FIELDS[file] ?? [];
98
+ const out: string[] = [];
99
+ for (const p of _diffPaths(a, b)) {
100
+ const atVersion = allowed.some((pat) => _matches(p, pat));
101
+ let before: unknown = a;
102
+ let after: unknown = b;
103
+ for (const s of p) {
104
+ before = (before as Record<string, unknown> | undefined)?.[s];
105
+ after = (after as Record<string, unknown> | undefined)?.[s];
106
+ }
107
+ if (atVersion && typeof before === 'string' && typeof after === 'string') continue;
108
+ out.push(`${file}: ${_render(p)} differs outside the version fields`);
109
+ }
110
+ return out;
111
+ }
112
+
113
+ function _git(args: readonly string[], cwd: string): { status: number; stdout: string } {
114
+ const r = spawnSync('git', args, { cwd, encoding: 'utf8' });
115
+ return { status: r.status ?? 1, stdout: r.stdout ?? '' };
116
+ }
117
+
118
+ function _readHead(root: string, file: string): string | null {
119
+ const abs = path.join(root, file);
120
+ return fs.existsSync(abs) ? fs.readFileSync(abs, 'utf8') : null;
121
+ }
122
+
123
+ export function main(argv: readonly string[] = process.argv.slice(2)): number {
124
+ let base = 'origin/main';
125
+ let root = REPO_ROOT;
126
+ for (let i = 0; i < argv.length; i += 1) {
127
+ const a = argv[i];
128
+ if (a === '--base' || a === '--root') {
129
+ const v = argv[i + 1];
130
+ if (v === undefined || v === '') {
131
+ process.stderr.write(`error: ${a} needs a value\n`);
132
+ return 2;
133
+ }
134
+ if (a === '--base') base = v;
135
+ else root = path.resolve(v);
136
+ i += 1;
137
+ continue;
138
+ }
139
+ process.stderr.write(`error: unknown argument ${String(a)}\n`);
140
+ return 2;
141
+ }
142
+ if (_git(['rev-parse', '--verify', `${base}^{commit}`], root).status !== 0) {
143
+ process.stderr.write(`error: base \`${base}\` does not resolve to a commit in ${root}\n`);
144
+ return 2;
145
+ }
146
+
147
+ const findings: string[] = [];
148
+ let scanned = 0;
149
+ for (const file of Object.keys(VERSION_FIELDS)) {
150
+ const shown = _git(['show', `${base}:${file}`], root);
151
+ const before = shown.status === 0 ? shown.stdout : null;
152
+ const after = _readHead(root, file);
153
+ if (before !== null || after !== null) scanned += 1;
154
+ findings.push(...manifestDifferences(file, before, after));
155
+ }
156
+ try {
157
+ reportScanned({ gate: 'check_release_manifest_content', scanned, units: 'manifests', roots: [root] });
158
+ } catch (err) {
159
+ if (err instanceof DeadScopeError) {
160
+ process.stderr.write(`${err.message}\n`);
161
+ return 2;
162
+ }
163
+ throw err;
164
+ }
165
+ if (findings.length > 0) {
166
+ process.stdout.write(
167
+ `❌ release manifests differ from ${base} outside their version fields:\n` +
168
+ findings.map((f) => ` · ${f}`).join('\n') +
169
+ '\n A release PR carries version bumps only. Land the other change on main via its own PR.\n',
170
+ );
171
+ return 1;
172
+ }
173
+ process.stdout.write(`✅ release manifests differ from ${base} in version fields only (${String(scanned)} read)\n`);
174
+ return 0;
175
+ }
176
+
177
+ function _isCliEntry(): boolean {
178
+ if (process.argv[1] === undefined) return false;
179
+ if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
180
+ try {
181
+ return fs.realpathSync(_HERE) === fs.realpathSync(path.resolve(process.argv[1]));
182
+ } catch {
183
+ return false;
184
+ }
185
+ }
186
+
187
+ if (_isCliEntry()) {
188
+ process.exit(main());
189
+ }