@event4u/agent-config 16.2.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 (651) 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 +337 -234
  5. package/README.md +15 -13
  6. package/agents/templates/.ai-council.yml.example +26 -8
  7. package/dist/agent-src/commands/analyze/inbox.md +11 -8
  8. package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
  9. package/dist/agent-src/commands/bug/fix.md +17 -2
  10. package/dist/agent-src/commands/bug/investigate.md +1 -1
  11. package/dist/agent-src/commands/commit/in-chunks.md +40 -31
  12. package/dist/agent-src/commands/commit.md +72 -33
  13. package/dist/agent-src/commands/condense.md +2 -8
  14. package/dist/agent-src/commands/council/debate.md +11 -7
  15. package/dist/agent-src/commands/council/default.md +10 -9
  16. package/dist/agent-src/commands/council.md +1 -1
  17. package/dist/agent-src/commands/estimate-ticket.md +1 -1
  18. package/dist/agent-src/commands/feature/explore.md +3 -3
  19. package/dist/agent-src/commands/feature/plan.md +2 -2
  20. package/dist/agent-src/commands/feature/roadmap.md +1 -1
  21. package/dist/agent-src/commands/fix/ci.md +18 -4
  22. package/dist/agent-src/commands/fix/commit-messages.md +48 -23
  23. package/dist/agent-src/commands/fix/pr-comments.md +3 -6
  24. package/dist/agent-src/commands/implement-ticket.md +4 -4
  25. package/dist/agent-src/commands/jira-ticket.md +1 -1
  26. package/dist/agent-src/commands/memory/add.md +4 -16
  27. package/dist/agent-src/commands/memory/load.md +5 -6
  28. package/dist/agent-src/commands/memory/promote.md +3 -16
  29. package/dist/agent-src/commands/mission/upgrade.md +3 -2
  30. package/dist/agent-src/commands/optimize/agents-dir.md +2 -2
  31. package/dist/agent-src/commands/optimize/deep.md +4 -2
  32. package/dist/agent-src/commands/optimize/rtk.md +4 -26
  33. package/dist/agent-src/commands/pr/create/description-only.md +18 -15
  34. package/dist/agent-src/commands/pr/create.md +42 -34
  35. package/dist/agent-src/commands/pr/merge.md +136 -9
  36. package/dist/agent-src/commands/prepare-for-review.md +13 -11
  37. package/dist/agent-src/commands/project/analyze.md +7 -35
  38. package/dist/agent-src/commands/refine-ticket.md +1 -1
  39. package/dist/agent-src/commands/review/changes.md +14 -19
  40. package/dist/agent-src/commands/roadmap/create.md +1 -1
  41. package/dist/agent-src/commands/roadmap/materialize.md +1 -1
  42. package/dist/agent-src/commands/roadmap/next.md +10 -1
  43. package/dist/agent-src/commands/roadmap/process-full.md +56 -42
  44. package/dist/agent-src/commands/roadmap/resolve-blockers.md +411 -0
  45. package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
  46. package/dist/agent-src/commands/roadmap.md +18 -4
  47. package/dist/agent-src/commands/tests/create.md +17 -3
  48. package/dist/agent-src/commands/tests/execute.md +22 -5
  49. package/dist/agent-src/commands/worktree/create.md +7 -3
  50. package/dist/agent-src/commands/worktree/verify.md +2 -1
  51. package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
  52. package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
  53. package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +5 -3
  54. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +7 -9
  55. package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +8 -6
  56. package/dist/agent-src/contexts/contracts/frugality-charter.md +8 -5
  57. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +7 -7
  58. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +0 -1
  59. package/dist/agent-src/contexts/execution/evidence-discipline.md +2 -2
  60. package/dist/agent-src/contexts/execution/non-interactive-contract.md +5 -8
  61. package/dist/agent-src/contexts/execution/rdp-gate.md +4 -4
  62. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +9 -8
  63. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +99 -54
  64. package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
  65. package/dist/agent-src/contexts/execution/subagent-routing.md +8 -8
  66. package/dist/agent-src/contexts/execution/subagent-steering.md +6 -4
  67. package/dist/agent-src/contexts/execution/terminal-states.md +2 -2
  68. package/dist/agent-src/contexts/execution/toolchain-resolver.md +95 -7
  69. package/dist/agent-src/contexts/subagent-configuration.md +1 -1
  70. package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
  71. package/dist/agent-src/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
  72. package/dist/agent-src/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
  73. package/dist/agent-src/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
  74. package/dist/agent-src/guidelines/agent-infra/layered-settings.md +13 -1
  75. package/dist/agent-src/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  76. package/dist/agent-src/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
  77. package/dist/agent-src/guidelines/agent-infra/size-and-scope.md +36 -0
  78. package/dist/agent-src/guidelines/php/git.md +15 -2
  79. package/dist/agent-src/rules/active-remediation.md +1 -2
  80. package/dist/agent-src/rules/analysis-skill-routing.md +0 -1
  81. package/dist/agent-src/rules/architecture.md +0 -1
  82. package/dist/agent-src/rules/artifact-drafting-protocol.md +0 -1
  83. package/dist/agent-src/rules/artifact-engagement-recording.md +0 -1
  84. package/dist/agent-src/rules/augment-edit-discipline.md +0 -1
  85. package/dist/agent-src/rules/autonomous-execution.md +1 -1
  86. package/dist/agent-src/rules/brand-consistency.md +0 -1
  87. package/dist/agent-src/rules/brand-source-of-truth.md +0 -1
  88. package/dist/agent-src/rules/broken-access-control.md +1 -1
  89. package/dist/agent-src/rules/cli-output-handling.md +0 -1
  90. package/dist/agent-src/rules/code-comment-discipline.md +0 -1
  91. package/dist/agent-src/rules/code-provenance.md +0 -1
  92. package/dist/agent-src/rules/command-suggestion-policy.md +1 -1
  93. package/dist/agent-src/rules/commit-conventions.md +1 -2
  94. package/dist/agent-src/rules/communication-through-line.md +1 -2
  95. package/dist/agent-src/rules/content-quoting-floor.md +1 -2
  96. package/dist/agent-src/rules/context-hygiene.md +6 -6
  97. package/dist/agent-src/rules/copilot-routing.md +1 -2
  98. package/dist/agent-src/rules/council-availability.md +4 -4
  99. package/dist/agent-src/rules/cross-source-consistency.md +4 -6
  100. package/dist/agent-src/rules/decision-revisit-gate.md +17 -35
  101. package/dist/agent-src/rules/delegation-policy.md +2 -3
  102. package/dist/agent-src/rules/design-fidelity.md +12 -16
  103. package/dist/agent-src/rules/design-review-after-ui-write.md +3 -3
  104. package/dist/agent-src/rules/devcontainer-routing.md +1 -2
  105. package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -1
  106. package/dist/agent-src/rules/docker-commands.md +0 -1
  107. package/dist/agent-src/rules/domain-adoption-policy.md +0 -1
  108. package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -1
  109. package/dist/agent-src/rules/domain-safety-pii.md +1 -1
  110. package/dist/agent-src/rules/domain-safety-retention.md +1 -1
  111. package/dist/agent-src/rules/downstream-changes.md +0 -1
  112. package/dist/agent-src/rules/engineering-safety-floor.md +1 -1
  113. package/dist/agent-src/rules/evaluator-independence.md +3 -2
  114. package/dist/agent-src/rules/external-code-graph-interop.md +0 -1
  115. package/dist/agent-src/rules/external-reference-deep-dive.md +0 -1
  116. package/dist/agent-src/rules/fast-path-marker-visibility.md +2 -2
  117. package/dist/agent-src/rules/finance-safety-floor.md +1 -1
  118. package/dist/agent-src/rules/fix-what-you-see.md +6 -32
  119. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +0 -1
  120. package/dist/agent-src/rules/git-history-discipline.md +2 -2
  121. package/dist/agent-src/rules/guidelines.md +0 -1
  122. package/dist/agent-src/rules/history-discipline.md +0 -1
  123. package/dist/agent-src/rules/icon-consistency.md +0 -1
  124. package/dist/agent-src/rules/image-likeness-and-rights.md +1 -1
  125. package/dist/agent-src/rules/improve-before-implement.md +0 -1
  126. package/dist/agent-src/rules/invite-challenge.md +0 -1
  127. package/dist/agent-src/rules/laravel-routing.md +1 -2
  128. package/dist/agent-src/rules/laravel-translations.md +0 -1
  129. package/dist/agent-src/rules/legal-safety-floor.md +3 -3
  130. package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -1
  131. package/dist/agent-src/rules/linked-projects-onboarding-gate.md +0 -1
  132. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -1
  133. package/dist/agent-src/rules/markdown-safe-codeblocks.md +0 -1
  134. package/dist/agent-src/rules/media-governance-routing.md +13 -17
  135. package/dist/agent-src/rules/media-sync-ground-truth.md +0 -1
  136. package/dist/agent-src/rules/minimal-safe-diff.md +0 -1
  137. package/dist/agent-src/rules/missing-skill-recovery.md +0 -1
  138. package/dist/agent-src/rules/missing-tool-handling.md +0 -1
  139. package/dist/agent-src/rules/model-recommendation.md +0 -1
  140. package/dist/agent-src/rules/neighbour-precedence.md +64 -0
  141. package/dist/agent-src/rules/no-attribution-footers.md +0 -1
  142. package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +0 -1
  143. package/dist/agent-src/rules/no-pr-progress-comments.md +0 -1
  144. package/dist/agent-src/rules/no-roadmap-references.md +0 -1
  145. package/dist/agent-src/rules/notes-first-reasoning.md +0 -1
  146. package/dist/agent-src/rules/onboarding-gate.md +0 -1
  147. package/dist/agent-src/rules/output-discipline.md +0 -1
  148. package/dist/agent-src/rules/package-ci-checks.md +0 -1
  149. package/dist/agent-src/rules/persona-governance.md +4 -5
  150. package/dist/agent-src/rules/php-coding.md +0 -1
  151. package/dist/agent-src/rules/prefer-enums-over-literals.md +0 -1
  152. package/dist/agent-src/rules/preservation-guard.md +0 -1
  153. package/dist/agent-src/rules/provider-lifecycle-discipline.md +3 -4
  154. package/dist/agent-src/rules/question-not-instruction.md +1 -1
  155. package/dist/agent-src/rules/reviewer-awareness.md +0 -1
  156. package/dist/agent-src/rules/roadmap-ci-steps-policy.md +0 -1
  157. package/dist/agent-src/rules/roadmap-progress-sync.md +4 -7
  158. package/dist/agent-src/rules/role-mode-adherence.md +0 -1
  159. package/dist/agent-src/rules/rule-type-governance.md +0 -1
  160. package/dist/agent-src/rules/runtime-safety.md +1 -1
  161. package/dist/agent-src/rules/scale-discipline.md +0 -1
  162. package/dist/agent-src/rules/secret-vcs-guard.md +1 -1
  163. package/dist/agent-src/rules/security-sensitive-stop.md +3 -3
  164. package/dist/agent-src/rules/self-repair-loop.md +0 -1
  165. package/dist/agent-src/rules/senior-engineering-discipline.md +0 -1
  166. package/dist/agent-src/rules/session-canary.md +7 -62
  167. package/dist/agent-src/rules/settings-ask-protocol.md +6 -6
  168. package/dist/agent-src/rules/size-enforcement.md +0 -1
  169. package/dist/agent-src/rules/skill-improvement-trigger.md +2 -3
  170. package/dist/agent-src/rules/skill-quality.md +0 -1
  171. package/dist/agent-src/rules/slash-command-routing-policy.md +0 -1
  172. package/dist/agent-src/rules/source-confidentiality.md +1 -1
  173. package/dist/agent-src/rules/source-discovery-gate.md +0 -1
  174. package/dist/agent-src/rules/source-of-truth.md +0 -1
  175. package/dist/agent-src/rules/spreadsheet-source-quality.md +1 -2
  176. package/dist/agent-src/rules/strategy-safety-floor.md +1 -1
  177. package/dist/agent-src/rules/symfony-routing.md +1 -2
  178. package/dist/agent-src/rules/think-before-action.md +0 -1
  179. package/dist/agent-src/rules/token-budget-discipline.md +12 -46
  180. package/dist/agent-src/rules/token-efficiency.md +0 -1
  181. package/dist/agent-src/rules/token-optimizer-maintenance.md +0 -1
  182. package/dist/agent-src/rules/tool-safety.md +1 -1
  183. package/dist/agent-src/rules/ui-audit-gate.md +1 -2
  184. package/dist/agent-src/rules/untrusted-input-defense.md +1 -1
  185. package/dist/agent-src/rules/upstream-proposal.md +0 -1
  186. package/dist/agent-src/rules/user-interaction.md +0 -1
  187. package/dist/agent-src/rules/user-interrupt-priority.md +1 -1
  188. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  189. package/dist/agent-src/scripts/deferral_carry.ts +339 -0
  190. package/dist/agent-src/scripts/gate_budget.ts +47 -23
  191. package/dist/agent-src/scripts/gate_execute.ts +12 -4
  192. package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
  193. package/dist/agent-src/skills/ai-council/SKILL.md +7 -4
  194. package/dist/agent-src/skills/ai-council/references/cost-and-redaction.md +21 -11
  195. package/dist/agent-src/skills/ai-council/references/procedure.md +12 -6
  196. package/dist/agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -1
  197. package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
  198. package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
  199. package/dist/agent-src/skills/bug-analyzer/SKILL.md +1 -1
  200. package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
  201. package/dist/agent-src/skills/command-routing/SKILL.md +3 -4
  202. package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +127 -139
  203. package/dist/agent-src/skills/corpus-grounding/ATTRIBUTION.md +39 -0
  204. package/dist/agent-src/skills/corpus-grounding/SKILL.md +8 -2
  205. package/dist/agent-src/skills/database/data/manifest.json +2 -2
  206. package/dist/agent-src/skills/database/data/query-tuning.csv +13 -13
  207. package/dist/agent-src/skills/design-system-capture/SKILL.md +0 -3
  208. package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
  209. package/dist/agent-src/skills/estimate-ticket/SKILL.md +1 -1
  210. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +2 -2
  211. package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
  212. package/dist/agent-src/skills/feature-planning/SKILL.md +1 -1
  213. package/dist/agent-src/skills/git-workflow/SKILL.md +44 -44
  214. package/dist/agent-src/skills/git-workflow/references/branch-update.md +312 -0
  215. package/dist/agent-src/skills/git-workflow/references/commit-subject.md +205 -0
  216. package/dist/agent-src/skills/iconography/SKILL.md +1 -1
  217. package/dist/agent-src/skills/jira-integration/SKILL.md +3 -3
  218. package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
  219. package/dist/agent-src/skills/merge-conflicts/SKILL.md +10 -4
  220. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
  221. package/dist/agent-src/skills/po-discovery/SKILL.md +1 -1
  222. package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
  223. package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
  224. package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
  225. package/dist/agent-src/skills/refine-ticket/SKILL.md +4 -4
  226. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  227. package/dist/agent-src/skills/roadmap-writing/SKILL.md +2 -2
  228. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +5 -3
  229. package/dist/agent-src/skills/source-discovery/SKILL.md +1 -1
  230. package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
  231. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +4 -2
  232. package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
  233. package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
  234. package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
  235. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
  236. package/dist/agent-src/skills/ui-component-architect/SKILL.md +2 -2
  237. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +1 -1
  238. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +2 -2
  239. package/dist/agent-src/templates/AGENTS.md +1 -1
  240. package/dist/agent-src/templates/agent-settings.md +46 -129
  241. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +3 -3
  242. package/dist/agent-src/templates/command.md +2 -2
  243. package/dist/agent-src/templates/roadmaps.md +6 -1
  244. package/dist/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
  245. package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
  246. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
  247. package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
  248. package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
  249. package/dist/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
  250. package/dist/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
  251. package/dist/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
  252. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  253. package/dist/agent-src/templates/skill.md +1 -1
  254. package/dist/cli/registry.js +2 -1
  255. package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
  256. package/dist/cli-delegate/check_update_banner.js +207 -120
  257. package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
  258. package/dist/cli-delegate/{chunk-FP36SWJD.js → chunk-5GPULQBE.js} +2797 -338
  259. package/dist/cli-delegate/{chunk-IGD6ERX6.js → chunk-6SRJTYJS.js} +42 -176
  260. package/dist/cli-delegate/chunk-6V5FMA3P.js +186 -0
  261. package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
  262. package/dist/cli-delegate/chunk-6YQC2HLF.js +415 -0
  263. package/dist/cli-delegate/{chunk-E4XIZDIB.js → chunk-7HKRE54K.js} +1 -64
  264. package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
  265. package/dist/cli-delegate/{chunk-YJ72UIAK.js → chunk-AED2VQGM.js} +1245 -249
  266. package/dist/cli-delegate/{chunk-7HQ52DHU.js → chunk-AL3RZ22D.js} +1 -1
  267. package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
  268. package/dist/cli-delegate/{chunk-DBH4AHDK.js → chunk-ED7KCMLB.js} +9 -11
  269. package/dist/cli-delegate/chunk-F3QDG2GT.js +2569 -0
  270. package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-G5VVIZRC.js} +3 -3
  271. package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-H76PHZBI.js} +149 -61
  272. package/dist/cli-delegate/chunk-IAYTIIQW.js +67 -0
  273. package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
  274. package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
  275. package/dist/cli-delegate/{chunk-7RQP4UDH.js → chunk-KR6EM23A.js} +235 -1455
  276. package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-KXXWJTDO.js} +6 -11
  277. package/dist/cli-delegate/{chunk-T7L2QK3K.js → chunk-LQOCRFWT.js} +1 -1
  278. package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-MDPPKQCQ.js} +58 -9
  279. package/dist/cli-delegate/{chunk-4XFP2Y3E.js → chunk-MSUL5NYP.js} +5 -5
  280. package/dist/cli-delegate/chunk-OAFSJBHH.js +272 -0
  281. package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
  282. package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
  283. package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-PWX7CKMD.js} +4 -4
  284. package/dist/cli-delegate/{chunk-NDJLNC6Q.js → chunk-T6BP34WI.js} +1 -0
  285. package/dist/cli-delegate/{chunk-7XGBX6ZH.js → chunk-T7XSJSUQ.js} +1144 -589
  286. package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
  287. package/dist/cli-delegate/chunk-WQWXGIWB.js +1779 -0
  288. package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-XQTPXKFA.js} +1 -1
  289. package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
  290. package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
  291. package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
  292. package/dist/cli-delegate/cmd_analyze_session.js +223 -43
  293. package/dist/cli-delegate/cmd_brand_status.js +3 -2
  294. package/dist/cli-delegate/cmd_conformance.js +1252 -249
  295. package/dist/cli-delegate/cmd_converge.js +3 -3
  296. package/dist/cli-delegate/cmd_doctor.js +19 -9
  297. package/dist/cli-delegate/cmd_doctor_neighbours.js +30 -0
  298. package/dist/cli-delegate/cmd_explain.js +45 -21
  299. package/dist/cli-delegate/cmd_export.js +13 -10
  300. package/dist/cli-delegate/cmd_fleet.js +3 -3
  301. package/dist/cli-delegate/cmd_git_convention.js +1851 -0
  302. package/dist/cli-delegate/cmd_handoff.js +44 -22
  303. package/dist/cli-delegate/cmd_mcp_available.js +3 -2
  304. package/dist/cli-delegate/cmd_memory_get.js +3 -1
  305. package/dist/cli-delegate/cmd_migrate.js +3 -3
  306. package/dist/cli-delegate/cmd_packs_active.js +5 -4
  307. package/dist/cli-delegate/cmd_preflight.js +6 -6
  308. package/dist/cli-delegate/cmd_prune.js +14 -11
  309. package/dist/cli-delegate/cmd_refresh.js +2 -1
  310. package/dist/cli-delegate/cmd_route_audit.js +10 -8
  311. package/dist/cli-delegate/cmd_route_explain.js +4 -4
  312. package/dist/cli-delegate/cmd_session_recycle.js +10 -7
  313. package/dist/cli-delegate/cmd_settings_check.js +54 -7
  314. package/dist/cli-delegate/cmd_settings_get.js +18 -8
  315. package/dist/cli-delegate/cmd_settings_migrate.js +13 -10
  316. package/dist/cli-delegate/cmd_settings_set.js +4 -4
  317. package/dist/cli-delegate/cmd_sync.js +14 -11
  318. package/dist/cli-delegate/cmd_uninstall.js +15 -12
  319. package/dist/cli-delegate/cmd_update.js +7 -7
  320. package/dist/cli-delegate/cmd_upgrade.js +9 -8
  321. package/dist/cli-delegate/cmd_validate.js +15 -12
  322. package/dist/cli-delegate/cmd_versions.js +5 -5
  323. package/dist/cli-delegate/deferral_carry.js +16 -0
  324. package/dist/cli-delegate/gate_budget.js +1 -1
  325. package/dist/cli-delegate/gate_execute.js +3 -3
  326. package/dist/cli-delegate/roadmap_gates.js +6 -6
  327. package/dist/cli-delegate/update_roadmap_progress.js +1 -1
  328. package/dist/discovery/deprecation-report.md +1 -1
  329. package/dist/discovery/discovery-manifest.json +232 -141
  330. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  331. package/dist/discovery/discovery-manifest.summary.md +3 -3
  332. package/dist/discovery/dormancy-report.md +1 -1
  333. package/dist/discovery/orphan-report.md +1 -1
  334. package/dist/discovery/packs.json +26 -9
  335. package/dist/discovery/trust-report.md +3 -3
  336. package/dist/discovery/workspaces.json +7 -4
  337. package/dist/hooks/dispatch.js +5655 -6623
  338. package/dist/hooks/dispatch.sha256 +1 -1
  339. package/dist/install/claudePathsPlan.js +47 -6
  340. package/dist/install/claudeRuleRewrite.js +7 -0
  341. package/dist/install/emit_host_rules_cli.js +39 -36
  342. package/dist/install/globalRuleScope.js +87 -0
  343. package/dist/install/host_rule_ownership.js +160 -0
  344. package/dist/install/install.mjs +2336 -1249
  345. package/dist/install/installThinLayer.js +289 -0
  346. package/dist/install/installedRuleLinks.js +262 -0
  347. package/dist/install/wizard-plan.js +24 -0
  348. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  349. package/dist/mcp/mcp-cloudflare-catalogue.json +2 -2
  350. package/dist/mcp/registry-manifest.json +5 -5
  351. package/dist/mcp/server.json +2 -2
  352. package/dist/mcp/server.mjs +36504 -30986
  353. package/dist/router.json +1 -1
  354. package/dist/scripts/_lib/agent_settings.js +26 -120
  355. package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
  356. package/dist/scripts/_lib/compile_time_toggles.js +12 -21
  357. package/dist/scripts/_lib/git_convention.js +232 -0
  358. package/dist/scripts/_lib/global_deploy_inventory.js +730 -0
  359. package/dist/scripts/_lib/installed_layer.js +704 -0
  360. package/dist/scripts/_lib/lean_projection_mode.js +218 -15
  361. package/dist/scripts/_lib/package_root.js +68 -0
  362. package/dist/scripts/_lib/rule_consequence_class.js +45 -0
  363. package/dist/scripts/_lib/rule_injection.js +67 -10
  364. package/dist/scripts/_lib/rule_law_section.js +122 -0
  365. package/dist/scripts/_lib/settings_removed_keys.js +168 -0
  366. package/dist/scripts/_lib/thin_rules.js +535 -0
  367. package/dist/scripts/_lib/windsurf_render.js +60 -0
  368. package/dist/scripts/condense.js +14 -26
  369. package/dist/scripts/project_thin_rules.js +14 -294
  370. package/dist/server/app.js +2 -1
  371. package/dist/server/gitKeysGate.js +105 -0
  372. package/dist/server/routes/settings.js +67 -8
  373. package/dist/server/routes/wizard.js +4 -0
  374. package/dist/server/schemas/settings.js +29 -81
  375. package/dist/shared/skillRanking.js +103 -16
  376. package/dist/ui/assets/{index-Cwq4d0hX.js → index-C3djEJah.js} +2 -2
  377. package/dist/ui/index.html +1 -1
  378. package/docs/MIGRATION.md +72 -1
  379. package/docs/contracts/settings-classes.md +39 -67
  380. package/docs/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
  381. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
  382. package/docs/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
  383. package/docs/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
  384. package/docs/guidelines/agent-infra/layered-settings.md +13 -1
  385. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  386. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
  387. package/docs/guidelines/agent-infra/size-and-scope.md +36 -0
  388. package/docs/guidelines/php/git.md +15 -2
  389. package/package.json +1 -1
  390. package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  391. package/src/agent-src/scripts/deferral_carry.ts +339 -0
  392. package/src/agent-src/scripts/gate_budget.ts +47 -23
  393. package/src/agent-src/scripts/gate_execute.ts +12 -4
  394. package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
  395. package/src/agent-src/templates/AGENTS.md +1 -1
  396. package/src/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
  397. package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
  398. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
  399. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
  400. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
  401. package/src/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
  402. package/src/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
  403. package/src/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
  404. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  405. package/src/config/agent-settings.template.yml +141 -334
  406. package/src/config/agents-paths.yml +16 -0
  407. package/src/config/assurance-capability-registry.json +7 -3
  408. package/src/config/ci-local-parity.yml +3 -0
  409. package/src/config/continuity-surface.json +10 -3
  410. package/src/config/discovery/packs.yml +17 -1
  411. package/src/config/evaluator-budgets.json +23 -10
  412. package/src/config/gate-coverage.yml +138 -3
  413. package/src/config/gate-violation-baselines.json +64 -16
  414. package/src/config/gitignore-block.txt +19 -0
  415. package/src/config/hook-bundle-budget.json +25 -0
  416. package/src/config/hook-token-budget.json +6 -1
  417. package/src/config/host-instruction-limits.json +33 -0
  418. package/src/config/release-gate-locality.yml +2 -1
  419. package/src/config/routing-coverage-seed.json +67 -4
  420. package/src/config/rule-activation-census.json +7 -3
  421. package/src/config/rule-consequence-class.json +161 -0
  422. package/src/config/rule-law-ceilings.json +105 -0
  423. package/src/config/rule-obligations.json +833 -0
  424. package/src/install/claudePathsPlan.ts +46 -4
  425. package/src/install/claudeRuleRewrite.ts +10 -1
  426. package/src/install/emit_host_rules_cli.ts +43 -34
  427. package/src/install/globalRuleScope.ts +109 -0
  428. package/src/install/host_rule_ownership.ts +170 -0
  429. package/src/install/installThinLayer.ts +378 -0
  430. package/src/install/installedRuleLinks.ts +308 -0
  431. package/src/install/wizard-plan.ts +24 -0
  432. package/src/scripts/_cli/cmd_analyze_session.ts +9 -15
  433. package/src/scripts/_cli/cmd_conformance.ts +13 -2
  434. package/src/scripts/_cli/cmd_doctor.ts +33 -81
  435. package/src/scripts/_cli/cmd_doctor_neighbours.ts +426 -0
  436. package/src/scripts/_cli/cmd_explain.ts +72 -14
  437. package/src/scripts/_cli/cmd_git_convention.ts +637 -0
  438. package/src/scripts/_cli/cmd_settings_check.ts +66 -8
  439. package/src/scripts/_cli/cmd_settings_get.ts +18 -3
  440. package/src/scripts/_cli/doctor_execution.ts +72 -1
  441. package/src/scripts/_dispatch.bash +53 -4
  442. package/src/scripts/_lib/agent_settings.ts +26 -124
  443. package/src/scripts/_lib/blocked_by_marker.ts +1 -1
  444. package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
  445. package/src/scripts/_lib/compile_time_toggles.ts +12 -21
  446. package/src/scripts/_lib/dispatch_import_closure.ts +163 -0
  447. package/src/scripts/_lib/estate_offsets.ts +241 -0
  448. package/src/scripts/_lib/exemption_shape.ts +143 -0
  449. package/src/scripts/_lib/fnv.ts +23 -0
  450. package/src/scripts/_lib/foreign_scan.ts +106 -0
  451. package/src/scripts/_lib/git_base_ref.ts +92 -0
  452. package/src/scripts/_lib/git_convention.ts +291 -0
  453. package/src/scripts/_lib/git_convention_carrier.ts +389 -0
  454. package/src/scripts/_lib/git_convention_grammar.ts +246 -0
  455. package/src/scripts/_lib/git_convention_measure.ts +344 -0
  456. package/src/scripts/_lib/gitignore_block.ts +314 -0
  457. package/src/scripts/_lib/global_deploy_inventory.ts +106 -0
  458. package/src/scripts/_lib/graph_feeder_record.ts +437 -0
  459. package/src/scripts/_lib/hook_settings.ts +73 -0
  460. package/src/scripts/_lib/host_capability.ts +40 -19
  461. package/src/scripts/_lib/host_hook_merge.ts +165 -0
  462. package/src/scripts/_lib/installed_layer.ts +963 -0
  463. package/src/scripts/_lib/json_merge.ts +82 -0
  464. package/src/scripts/_lib/json_pointers.ts +93 -11
  465. package/src/scripts/_lib/knowledge_global.ts +14 -1
  466. package/src/scripts/_lib/lean_projection_mode.ts +275 -15
  467. package/src/scripts/_lib/machine_wake.ts +16 -3
  468. package/src/scripts/_lib/module_reach.ts +456 -0
  469. package/src/scripts/_lib/neighbour_census.ts +760 -0
  470. package/src/scripts/_lib/neighbour_contradictions.ts +236 -0
  471. package/src/scripts/_lib/neighbour_scan.ts +122 -0
  472. package/src/scripts/_lib/neighbour_tool_use.ts +187 -0
  473. package/src/scripts/_lib/prompt_shape.ts +46 -0
  474. package/src/scripts/_lib/ratification_artifact.ts +220 -1
  475. package/src/scripts/_lib/ratification_subject.ts +92 -0
  476. package/src/scripts/_lib/release_findings_ingest.ts +15 -7
  477. package/src/scripts/_lib/release_highlights.ts +5 -0
  478. package/src/scripts/_lib/release_migration_gate.ts +19 -3
  479. package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
  480. package/src/scripts/_lib/review_coverage.ts +134 -0
  481. package/src/scripts/_lib/rule_consequence_class.ts +71 -0
  482. package/src/scripts/_lib/rule_injection.ts +130 -10
  483. package/src/scripts/_lib/rule_law_section.ts +147 -0
  484. package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
  485. package/src/scripts/_lib/rule_obligations.ts +205 -0
  486. package/src/scripts/_lib/self_repair.ts +1 -1
  487. package/src/scripts/_lib/settings_removed_keys.ts +173 -0
  488. package/src/scripts/_lib/skill_origin.ts +254 -0
  489. package/src/scripts/_lib/structured_ask.ts +64 -21
  490. package/src/scripts/_lib/test_red_state.ts +5 -0
  491. package/src/scripts/_lib/thin_rules.ts +620 -0
  492. package/src/scripts/_lib/touched_file_quality.ts +570 -0
  493. package/src/scripts/_lib/turn_end_refusals.ts +77 -2
  494. package/src/scripts/_lib/windsurf_render.ts +63 -0
  495. package/src/scripts/_lib/worker_budget.ts +1 -1
  496. package/src/scripts/adr/regenerate_index.ts +16 -1
  497. package/src/scripts/ai_council/cli_call_budget.ts +13 -5
  498. package/src/scripts/ai_council/clients.ts +26 -57
  499. package/src/scripts/ai_council/config.ts +8 -8
  500. package/src/scripts/ai_council/modification_review.ts +100 -0
  501. package/src/scripts/ai_council/modification_review_questions.ts +90 -0
  502. package/src/scripts/ai_council/orchestrator.ts +5 -5
  503. package/src/scripts/ai_council/spend_gate.ts +18 -7
  504. package/src/scripts/ai_council/vendor_defaults.ts +45 -0
  505. package/src/scripts/ai_team/config.ts +11 -16
  506. package/src/scripts/audit_skill_overlap.ts +261 -0
  507. package/src/scripts/audit_user_type_axis.ts +20 -8
  508. package/src/scripts/before_complete_hook.ts +243 -12
  509. package/src/scripts/bench_ab_clone.ts +1 -2
  510. package/src/scripts/bench_concern_spawn_path.ts +129 -0
  511. package/src/scripts/bench_graph_feeder_latency.ts +584 -0
  512. package/src/scripts/bench_touched_file_quality.ts +238 -0
  513. package/src/scripts/check_agent_artifact_location.ts +36 -0
  514. package/src/scripts/check_branch_freshness.ts +147 -24
  515. package/src/scripts/check_enforcement_coverage.ts +130 -0
  516. package/src/scripts/check_enforcement_matrix.ts +377 -20
  517. package/src/scripts/check_estate_count.ts +130 -153
  518. package/src/scripts/check_evaluator_budgets.ts +4 -0
  519. package/src/scripts/check_finding_dispositions.ts +196 -21
  520. package/src/scripts/check_gate_coverage.ts +4 -3
  521. package/src/scripts/check_gate_reachability.ts +48 -1
  522. package/src/scripts/check_generator_sync.ts +48 -0
  523. package/src/scripts/check_hook_bundle_composition.ts +477 -0
  524. package/src/scripts/check_kernel_edit_ratified.ts +132 -14
  525. package/src/scripts/check_memory.ts +7 -1
  526. package/src/scripts/check_pack_size.ts +1 -1
  527. package/src/scripts/check_release_highlights.ts +10 -0
  528. package/src/scripts/check_release_manifest_content.ts +189 -0
  529. package/src/scripts/check_release_pr_shape.ts +38 -15
  530. package/src/scripts/check_standing_rule_delivery.ts +129 -13
  531. package/src/scripts/check_suppression_hygiene.ts +2 -5
  532. package/src/scripts/check_verify_expectation_delta.ts +521 -0
  533. package/src/scripts/ci_settle.ts +42 -5
  534. package/src/scripts/classify_merge_risk.ts +320 -0
  535. package/src/scripts/closure_scan.ts +91 -1
  536. package/src/scripts/code_graph/detect.ts +127 -7
  537. package/src/scripts/code_graph/foreign.ts +194 -0
  538. package/src/scripts/code_graph/query.ts +217 -4
  539. package/src/scripts/code_graph/types.ts +26 -2
  540. package/src/scripts/code_graph/validate.ts +3 -1
  541. package/src/scripts/code_graph/verbs.ts +103 -0
  542. package/src/scripts/command_suggester/settings.ts +8 -108
  543. package/src/scripts/command_suggester/types.ts +4 -5
  544. package/src/scripts/compile_hook_manifest.ts +33 -1
  545. package/src/scripts/condense.ts +14 -27
  546. package/src/scripts/consumer_matrix.ts +102 -0
  547. package/src/scripts/context_hygiene_hook.ts +13 -23
  548. package/src/scripts/cost/preflight.mjs +12 -1
  549. package/src/scripts/council_cli.ts +7 -7
  550. package/src/scripts/dispatch_r2_reviewer.ts +24 -11
  551. package/src/scripts/estate_exemption_shape.ts +202 -0
  552. package/src/scripts/explain_run.ts +8 -13
  553. package/src/scripts/generate_git_convention_grammar.ts +127 -0
  554. package/src/scripts/generate_host_cost_table.ts +21 -4
  555. package/src/scripts/handoff_context_hook.ts +86 -37
  556. package/src/scripts/hook_manifest.json +1 -1
  557. package/src/scripts/hook_manifest.yaml +175 -15
  558. package/src/scripts/hooks/block_config_weakening.ts +115 -7
  559. package/src/scripts/hooks/block_plumbing_writes.ts +37 -5
  560. package/src/scripts/hooks/code_graph_context_hook.ts +252 -23
  561. package/src/scripts/hooks/concern_failure_policy.ts +280 -0
  562. package/src/scripts/hooks/concern_registry.ts +2 -0
  563. package/src/scripts/hooks/delegation_nudge_hook.ts +2 -3
  564. package/src/scripts/hooks/dispatch_hook.ts +52 -52
  565. package/src/scripts/hooks/evidence_independence.ts +12 -4
  566. package/src/scripts/hooks/exit_codes.ts +2 -1
  567. package/src/scripts/hooks/host_lowering.json +1 -1
  568. package/src/scripts/hooks/host_lowering.ts +19 -1
  569. package/src/scripts/hooks/mcp_usage_observation_hook.ts +121 -0
  570. package/src/scripts/hooks/one_question_per_ask_hook.ts +41 -25
  571. package/src/scripts/hooks/payload_stub.ts +10 -1
  572. package/src/scripts/hooks/push_settle_hook.ts +4 -3
  573. package/src/scripts/hooks/rule_inject_hook.ts +795 -60
  574. package/src/scripts/hooks/state_io.ts +8 -4
  575. package/src/scripts/hooks/table_fingerprint.ts +21 -0
  576. package/src/scripts/hooks/telemetry_usage_hook.ts +24 -7
  577. package/src/scripts/hooks/turn_end_gate_hook.ts +85 -0
  578. package/src/scripts/hooks_status.ts +112 -0
  579. package/src/scripts/injection_scan_hook.ts +7 -0
  580. package/src/scripts/install-hooks.sh +42 -14
  581. package/src/scripts/install.ts +78 -215
  582. package/src/scripts/installed_layer_report.ts +103 -0
  583. package/src/scripts/language_mirror_hook.ts +15 -6
  584. package/src/scripts/learning_sidecar.ts +119 -8
  585. package/src/scripts/lint_blocker_citations.ts +198 -0
  586. package/src/scripts/lint_evidence_artifacts.ts +9 -0
  587. package/src/scripts/lint_hook_concern_budget.ts +10 -21
  588. package/src/scripts/lint_hook_manifest.ts +53 -0
  589. package/src/scripts/lint_major_migration_sections.ts +156 -26
  590. package/src/scripts/lint_pack_boundaries.ts +465 -29
  591. package/src/scripts/lint_roadmap_blockers.ts +282 -29
  592. package/src/scripts/lint_roadmap_complexity.ts +4 -2
  593. package/src/scripts/lint_rule_law_section.ts +647 -0
  594. package/src/scripts/lint_rule_skill_pack_reach.ts +17 -0
  595. package/src/scripts/lint_settings_classes.ts +1 -1
  596. package/src/scripts/lint_ticked_unmet_criteria.ts +165 -0
  597. package/src/scripts/lint_workflow_security.ts +173 -6
  598. package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
  599. package/src/scripts/mcp_server/graph_tools.ts +72 -3
  600. package/src/scripts/measure_routing_signal.ts +54 -16
  601. package/src/scripts/measure_skill_ranker_baseline.ts +221 -8
  602. package/src/scripts/memory_learn_hook.ts +91 -6
  603. package/src/scripts/model_rule_injection.ts +55 -8
  604. package/src/scripts/onboarding_gate_hook.ts +7 -6
  605. package/src/scripts/print_required_checks.ts +15 -3
  606. package/src/scripts/probe_host_compliance.ts +33 -5
  607. package/src/scripts/probe_turnaround.ts +183 -3
  608. package/src/scripts/project_thin_rules.ts +34 -327
  609. package/src/scripts/ratification_header.ts +77 -0
  610. package/src/scripts/refusal_envelope.ts +138 -0
  611. package/src/scripts/release_publication.ts +29 -3
  612. package/src/scripts/report_dispatch_import_closure.ts +76 -0
  613. package/src/scripts/report_evidence_temperature.ts +657 -0
  614. package/src/scripts/report_installed_rule_links.ts +274 -0
  615. package/src/scripts/report_label_agreement.ts +233 -0
  616. package/src/scripts/report_module_reach.ts +212 -0
  617. package/src/scripts/report_obligation_mechanism.ts +228 -0
  618. package/src/scripts/report_parked_blockers.ts +222 -0
  619. package/src/scripts/report_required_checks_drift.ts +196 -0
  620. package/src/scripts/report_single_token_triggers.ts +277 -0
  621. package/src/scripts/report_skill_ranker_confusion.ts +543 -0
  622. package/src/scripts/report_standing_payload_by_host.ts +188 -15
  623. package/src/scripts/report_verification_record_coverage.ts +306 -0
  624. package/src/scripts/routing_doctor.ts +2 -2
  625. package/src/scripts/rule_activation_census.ts +5 -2
  626. package/src/scripts/rule_trigger_eval.ts +9 -9
  627. package/src/scripts/schemas/agent-settings.schema.json +17 -31
  628. package/src/scripts/schemas/command.schema.json +1 -1
  629. package/src/scripts/schemas/review-findings.schema.json +3 -2
  630. package/src/scripts/schemas/rule.schema.json +5 -0
  631. package/src/scripts/schemas/skill.schema.json +1 -1
  632. package/src/scripts/self_review_gate.ts +101 -9
  633. package/src/scripts/skill_tools/score_skill_relevance.ts +314 -40
  634. package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
  635. package/src/scripts/sync_gitignore.ts +29 -235
  636. package/src/scripts/sync_pr_branch.ts +403 -132
  637. package/src/scripts/trigger_eval_grandfather.json +0 -21
  638. package/src/server/schemas/settings.ts +42 -176
  639. package/src/shared/skillRanking.ts +169 -14
  640. package/dist/cli-delegate/chunk-5R7HOLAF.js +0 -99
  641. package/dist/cli-delegate/chunk-JNMVLWLR.js +0 -4457
  642. package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
  643. package/src/scripts/_lib/config_chain.ts +0 -477
  644. package/src/scripts/_lib/conformance_report.ts +0 -403
  645. package/src/scripts/_lib/eval_discrimination.ts +0 -95
  646. package/src/scripts/_lib/evaluator_promotion.ts +0 -225
  647. package/src/scripts/_lib/file_slicer.ts +0 -117
  648. package/src/scripts/_lib/legacy_boundary_map.ts +0 -228
  649. package/src/scripts/_lib/minimality_tiebreak.ts +0 -168
  650. package/src/scripts/_lib/overbuild_lens_contract.ts +0 -196
  651. package/src/scripts/_lib/role_split.ts +0 -338
@@ -34,13 +34,45 @@
34
34
  * this gate now matches that definition.
35
35
  * - **BROKEN deliberately:** exit code 2 is new (dead scan scope). 0 and 1
36
36
  * keep their meanings.
37
+ * - **BROKEN deliberately (2026-10-01):** the always-installed set is the
38
+ * hard-coded `core` PLUS every pack flagged `always_on: true`. The original
39
+ * knew only `core`, so it reported a violation for a target the resolver
40
+ * provably does install — the same defect shape as the direct-vs-transitive
41
+ * `requires` comparison above. `config/packs.resolve_active_packs` seeds the
42
+ * active set with the always-on packs before expanding any selection, and
43
+ * `docs/contracts/capability-packs.md` § Always-on packs states such a pack
44
+ * "cannot be deselected". One-way: a link OUT of an always-on pack into a
45
+ * gated one still dangles and is still reported.
37
46
  * - **STILL HOLDS:** the CLI surface (`--format text|json`, `--quiet`, `-h`),
38
47
  * the link regex and its fragment/query stripping, link-resolution semantics
39
48
  * (external / absolute / out-of-tree targets ignored), the allow rule
40
- * (same pack · `core` · declared `requires`), the per-violation text and
49
+ * (same pack · always-installed · declared `requires`), the per-violation text and
41
50
  * JSON shapes, the stdout/stderr split, and exit 0 clean / 1 violations.
51
+ * - **ADDED (2026-10-07):** a `scanned: <N>` line on every path (stdout in text
52
+ * mode, stderr under `--format json` so the payload stays parseable), and
53
+ * `--self-test`, which runs this CLI against planted fixture trees. Both are
54
+ * what `src/config/gate-coverage.yml` asks of a gate a pull request runs.
42
55
  *
43
- * ## Where the `requires` graph is read from
56
+ * THE ADVISORY `suggests` EDGE, AND THE SIBLING GATE THAT REFUSES IT.
57
+ * Since D5 of `road-to-gates-a-pull-request-can-hear` (AI council 2026-10-07)
58
+ * this gate reads `suggests` as PERMITTING a cross-pack link: advisory,
59
+ * non-installing, one-hop, one-way. `lint_rule_skill_pack_reach` states in its
60
+ * own header that `suggests` is deliberately NOT followed. Both are correct,
61
+ * and the discriminator is the direction of the claim:
62
+ *
63
+ * - THAT gate asserts a route WILL RESOLVE. Counting an advisory edge would
64
+ * assert resolution on installs that may not exist.
65
+ * - THIS gate reports a link that MAY DANGLE. An advisory edge is the author
66
+ * stating they accept the dangle for a consumer who declines the companion,
67
+ * so reading it downgrades a finding the author has already answered.
68
+ *
69
+ * The permit is per EDGE, not per link. The council's condition — only
70
+ * safely-degrading links may be permitted — was verified once, by hand, over
71
+ * the 203 links at the 2026-10-09 baseline; nothing re-verifies it for links
72
+ * added later. That is why the permitted COUNT prints on every run including
73
+ * `--quiet`: it is the only standing signal that the set is growing.
74
+ *
75
+ * WHERE THE `requires` GRAPH IS READ FROM.
44
76
  *
45
77
  * `src/config/discovery/packs.yml` is the source of truth for the pack
46
78
  * vocabulary and its `requires` edges — `generate_pack_manifests.ts` DERIVES
@@ -53,6 +85,7 @@
53
85
  */
54
86
 
55
87
  import * as fs from 'node:fs';
88
+ import * as os from 'node:os';
56
89
  import * as path from 'node:path';
57
90
  import { fileURLToPath, pathToFileURL } from 'node:url';
58
91
  import { parse as parseYaml } from 'yaml';
@@ -65,7 +98,8 @@ import {
65
98
  iter_artefacts,
66
99
  } from './_lib/agent_src.js';
67
100
  import { checkRatchet } from './_lib/gate_baseline.js';
68
- import { DeadScopeError, assertScanned } from './_lib/scan_scope.js';
101
+ import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
102
+ import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
69
103
  import { parse_frontmatter } from './validate_frontmatter.js';
70
104
 
71
105
  const _HERE = path.resolve(fileURLToPath(import.meta.url));
@@ -109,12 +143,66 @@ function _set_paths_for_test(opts: { root?: string; vocab?: string }): void {
109
143
  }
110
144
  }
111
145
 
146
+ // `--self-test` drives this CLI from a CHILD process, which cannot reach the
147
+ // setter above, so the fixture root is also readable from the environment.
148
+ // Applied through the setter rather than at the `ROOT` declaration, so a
149
+ // fixture run is still recognised as overridden and never judged by the
150
+ // repo's violation ratchet.
151
+ // Honoured only inside a self-test child, so an inherited value can never
152
+ // redirect the production gate or switch its ratchet off.
153
+ const _ENV_ROOT =
154
+ process.env['GATE_SELF_TEST_CHILD'] === '1' ? process.env['LINT_PACK_BOUNDARIES_ROOT'] : undefined;
155
+ if (_ENV_ROOT !== undefined && _ENV_ROOT !== '') {
156
+ _set_paths_for_test({ root: _realpath(path.resolve(_ENV_ROOT)) });
157
+ }
158
+
112
159
  // [..](target) with an optional #fragment / ?query stripped from the target.
113
160
  const LINK_RE = /\[[^\]]*\]\(([^)#?]+)(?:[#?][^)]*)?\)/g;
114
161
 
115
162
  /** A pack every install carries — a link into it can never dangle. */
116
163
  const ALWAYS_INSTALLED = 'core';
117
164
 
165
+ /**
166
+ * Packs every projection carries, so a link INTO one can never dangle.
167
+ *
168
+ * `core` is the hard-coded floor. Beyond it, `always_on: true` in the pack
169
+ * vocabulary means exactly this: `config/packs.resolve_active_packs` seeds the
170
+ * active set with every always-on pack BEFORE expanding the selected profile's
171
+ * `requires` closure, and `docs/contracts/capability-packs.md` § Always-on
172
+ * packs states the pack "is never gated by the selected profile, workspace, or
173
+ * pack set, and it cannot be deselected".
174
+ *
175
+ * Reading only `core` was the same class of defect this file's header already
176
+ * records for the direct-vs-transitive `requires` comparison: the gate reported
177
+ * a violation for a target the resolver provably does install. The direction is
178
+ * one-way — a link OUT of an always-on pack into a gated one still dangles and
179
+ * is still a violation.
180
+ */
181
+ function _always_installed_packs(): Set<string> {
182
+ const out = new Set<string>([ALWAYS_INSTALLED]);
183
+ if (_exists(VOCAB)) {
184
+ const vocab = parseYaml(fs.readFileSync(VOCAB, 'utf-8'), { version: '1.1' });
185
+ if (Array.isArray(vocab)) {
186
+ for (const entry of vocab) {
187
+ if (entry !== null && typeof entry === 'object' && !Array.isArray(entry)) {
188
+ const e = entry as Record<string, unknown>;
189
+ if (typeof e['id'] === 'string' && e['always_on'] === true) {
190
+ out.add(e['id']);
191
+ }
192
+ }
193
+ }
194
+ }
195
+ }
196
+ for (const dir of _pack_home_dirs()) {
197
+ const meta = _load_pack_meta(dir);
198
+ if (meta['always_on'] === true) {
199
+ const id = typeof meta['id'] === 'string' ? meta['id'] : path.basename(dir);
200
+ out.add(id);
201
+ }
202
+ }
203
+ return out;
204
+ }
205
+
118
206
  type ViolationKind =
119
207
  /** Link crosses into a pack the source pack does not require. */
120
208
  | 'cross-pack'
@@ -130,6 +218,35 @@ interface ViolationRecord {
130
218
  link: string;
131
219
  }
132
220
 
221
+ /**
222
+ * Which edge permits a cross-pack link. `null` is the violation case.
223
+ *
224
+ * `suggests` is the advisory, non-installing edge added for the base-into-
225
+ * narrow class (D5 of `road-to-gates-a-pull-request-can-hear`, AI council
226
+ * 2026-10-07). It is the WEAKEST promise in the list, which is why the ranking
227
+ * below exists: a link that needs it is reported as needing it, never as a
228
+ * `requires` link that happens to also hold.
229
+ */
230
+ type PermitReason = 'same-pack' | 'always-installed' | 'requires' | 'suggests' | null;
231
+
232
+ /** Strength order — lower is a stronger guarantee that the target is present. */
233
+ const PERMIT_RANK: Record<Exclude<PermitReason, null>, number> = {
234
+ 'same-pack': 0,
235
+ 'always-installed': 1,
236
+ requires: 2,
237
+ suggests: 3,
238
+ };
239
+
240
+ /** A link permitted only by `suggests`, kept for the `--show-permitted` report. */
241
+ interface PermittedRecord {
242
+ source_pack: string;
243
+ target_pack: string;
244
+ source: string;
245
+ target: string;
246
+ link: string;
247
+ reason: Exclude<PermitReason, null>;
248
+ }
249
+
133
250
  /** Mirror Python `Path.resolve()`: canonicalize existing prefix, append rest. */
134
251
  function _realpath(p: string): string {
135
252
  try {
@@ -275,7 +392,36 @@ function _pack_home_dirs(): string[] {
275
392
  * manifests as an overlay for pack homes the vocabulary does not list.
276
393
  */
277
394
  function _pack_requires(): Map<string, string[]> {
278
- const out = new Map<string, string[]>();
395
+ return _pack_edges().requires;
396
+ }
397
+
398
+ /**
399
+ * `pack id -> direct suggests`.
400
+ *
401
+ * Deliberately NOT expanded: `suggests` is one-hop. Transitive expansion would
402
+ * give the advisory edge the install-forcing reach `requires` has, which is the
403
+ * property the base-into-narrow decision depends on it not having.
404
+ */
405
+ function _pack_suggests(): Map<string, string[]> {
406
+ return _pack_edges().suggests;
407
+ }
408
+
409
+ /**
410
+ * Both edge maps, from ONE read of the vocabulary and one walk of the pack
411
+ * homes.
412
+ *
413
+ * One reader rather than two near-identical ones, so the VOCAB-wins precedence
414
+ * below exists in a single place: two copies would have to be kept in step by
415
+ * hand, and a `requires` map that fell out of step with a `suggests` map read
416
+ * from the same file is a drift nothing reports.
417
+ *
418
+ * NOTE for anyone adding an edge: a `pack.yaml` is only consulted for a pack
419
+ * the vocabulary does not list, so declaring `suggests` there alone has no
420
+ * effect on this gate. `packs.yml` is where an edge has to go.
421
+ */
422
+ function _pack_edges(): { requires: Map<string, string[]>; suggests: Map<string, string[]> } {
423
+ const requires = new Map<string, string[]>();
424
+ const suggests = new Map<string, string[]>();
279
425
  const asList = (v: unknown): string[] => (Array.isArray(v) ? v.map(String) : []);
280
426
 
281
427
  if (_exists(VOCAB)) {
@@ -285,7 +431,8 @@ function _pack_requires(): Map<string, string[]> {
285
431
  if (entry !== null && typeof entry === 'object' && !Array.isArray(entry)) {
286
432
  const e = entry as Record<string, unknown>;
287
433
  if (typeof e['id'] === 'string') {
288
- out.set(e['id'], asList(e['requires']));
434
+ requires.set(e['id'], asList(e['requires']));
435
+ suggests.set(e['id'], asList(e['suggests']));
289
436
  }
290
437
  }
291
438
  }
@@ -294,11 +441,12 @@ function _pack_requires(): Map<string, string[]> {
294
441
  for (const dir of _pack_home_dirs()) {
295
442
  const meta = _load_pack_meta(dir);
296
443
  const id = typeof meta['id'] === 'string' ? meta['id'] : path.basename(dir);
297
- if (!out.has(id)) {
298
- out.set(id, asList(meta['requires']));
444
+ if (!requires.has(id)) {
445
+ requires.set(id, asList(meta['requires']));
446
+ suggests.set(id, asList(meta['suggests']));
299
447
  }
300
448
  }
301
- return out;
449
+ return { requires, suggests };
302
450
  }
303
451
 
304
452
  /** Transitive expansion of `requires`, cycle-safe. */
@@ -479,14 +627,45 @@ function _scan_file(p: string): string[] {
479
627
  return out;
480
628
  }
481
629
 
482
- function _is_allowed(source_pack: string, target_pack: string, requires: string[]): boolean {
630
+ /**
631
+ * Which edge, if any, lets a link out of `source_pack` reach `target_pack`.
632
+ *
633
+ * `null` is the violation case. The reason is returned rather than a bare
634
+ * boolean because `suggests` is advisory: a reader who sees a permitted
635
+ * base-into-narrow link needs to know it was permitted by an edge that does
636
+ * NOT install the target, which is a different promise from `requires`.
637
+ */
638
+ function _permit_reason(
639
+ source_pack: string,
640
+ target_pack: string,
641
+ requires: string[],
642
+ always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
643
+ suggests: readonly string[] = [],
644
+ ): PermitReason {
483
645
  if (source_pack === target_pack) {
484
- return true;
646
+ return 'same-pack';
485
647
  }
486
- if (target_pack === ALWAYS_INSTALLED) {
487
- return true;
648
+ if (always_installed.has(target_pack)) {
649
+ return 'always-installed';
488
650
  }
489
- return (requires || []).includes(target_pack);
651
+ if ((requires || []).includes(target_pack)) {
652
+ return 'requires';
653
+ }
654
+ // One-hop and one-way by construction: the caller passes the SOURCE pack's
655
+ // own direct `suggests` list, never a closure over it. A transitive
656
+ // advisory edge would re-create the install-forcing reach `requires` has,
657
+ // which is the property this edge exists not to have.
658
+ return suggests.includes(target_pack) ? 'suggests' : null;
659
+ }
660
+
661
+ function _is_allowed(
662
+ source_pack: string,
663
+ target_pack: string,
664
+ requires: string[],
665
+ always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
666
+ suggests: readonly string[] = [],
667
+ ): boolean {
668
+ return _permit_reason(source_pack, target_pack, requires, always_installed, suggests) !== null;
490
669
  }
491
670
 
492
671
  /**
@@ -501,11 +680,48 @@ function _link_allowed(
501
680
  source_packs: readonly string[],
502
681
  target_packs: readonly string[],
503
682
  closureOf: (pack: string) => Set<string>,
683
+ always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
684
+ suggestsOf: (pack: string) => readonly string[] = () => [],
504
685
  ): boolean {
505
- return source_packs.every((s) => {
686
+ return (
687
+ _link_permit_reason(source_packs, target_packs, closureOf, always_installed, suggestsOf) !==
688
+ null
689
+ );
690
+ }
691
+
692
+ /**
693
+ * The weakest edge the link relies on, or `null` when nothing permits it.
694
+ *
695
+ * Weakest, not first: a link permitted for one source pack by `requires` and
696
+ * for another only by `suggests` is reported as `suggests`, because that is
697
+ * the promise a consumer actually gets.
698
+ */
699
+ function _link_permit_reason(
700
+ source_packs: readonly string[],
701
+ target_packs: readonly string[],
702
+ closureOf: (pack: string) => Set<string>,
703
+ always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
704
+ suggestsOf: (pack: string) => readonly string[] = () => [],
705
+ ): PermitReason {
706
+ let weakest: PermitReason = 'same-pack';
707
+ for (const s of source_packs) {
506
708
  const reach = [...closureOf(s)];
507
- return target_packs.some((t) => _is_allowed(s, t, reach));
508
- });
709
+ const sug = suggestsOf(s);
710
+ let best: PermitReason = null;
711
+ for (const t of target_packs) {
712
+ const r = _permit_reason(s, t, reach, always_installed, sug);
713
+ if (r !== null && (best === null || PERMIT_RANK[r] < PERMIT_RANK[best])) {
714
+ best = r;
715
+ }
716
+ }
717
+ if (best === null) {
718
+ return null;
719
+ }
720
+ if (PERMIT_RANK[best] > PERMIT_RANK[weakest]) {
721
+ weakest = best;
722
+ }
723
+ }
724
+ return weakest;
509
725
  }
510
726
 
511
727
  /** Mirror Python `json.dump(obj, indent=2)` with `ensure_ascii=True`. */
@@ -528,11 +744,14 @@ function _json_dumps_ascii(obj: unknown): string {
528
744
  interface ParsedArgs {
529
745
  format: 'text' | 'json';
530
746
  quiet: boolean;
747
+ /** List the links permitted only by an advisory `suggests` edge. */
748
+ show_permitted: boolean;
531
749
  }
532
750
 
533
751
  function parse_args(argv: readonly string[]): ParsedArgs {
534
752
  let format: 'text' | 'json' = 'text';
535
753
  let quiet = false;
754
+ let show_permitted = false;
536
755
  for (let i = 0; i < argv.length; i++) {
537
756
  const arg = argv[i] as string;
538
757
  if (arg === '--format') {
@@ -556,16 +775,19 @@ function parse_args(argv: readonly string[]): ParsedArgs {
556
775
  format = v;
557
776
  } else if (arg === '--quiet') {
558
777
  quiet = true;
778
+ } else if (arg === '--show-permitted') {
779
+ show_permitted = true;
559
780
  } else if (arg === '-h' || arg === '--help') {
560
781
  process.stdout.write(
561
- 'usage: lint_pack_boundaries [-h] [--format {text,json}] [--quiet]\n',
782
+ 'usage: lint_pack_boundaries [-h] [--format {text,json}] [--quiet] ' +
783
+ '[--show-permitted] [--self-test]\n',
562
784
  );
563
785
  process.exit(0);
564
786
  } else {
565
787
  _argparse_error(`unrecognized arguments: ${arg}`);
566
788
  }
567
789
  }
568
- return { format, quiet };
790
+ return { format, quiet, show_permitted };
569
791
  }
570
792
 
571
793
  function _argparse_error(message: string): never {
@@ -573,8 +795,161 @@ function _argparse_error(message: string): never {
573
795
  process.exit(2);
574
796
  }
575
797
 
798
+ /**
799
+ * Plant fixture trees and run this gate's real CLI against each one.
800
+ *
801
+ * Three rejecting cases cover the three exits a pull request can be failed by:
802
+ * an undeclared cross-pack link, an artefact with no resolvable pack, and an
803
+ * empty corpus. The two accepting cases pin the allow rule from the other side,
804
+ * so a gate that started rejecting everything fails here too.
805
+ */
806
+ function selfTest(): number {
807
+ const plant = (name: string, files: Record<string, string>): string => {
808
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), `lpb-selftest-${name}-`));
809
+ for (const [rel, body] of Object.entries(files)) {
810
+ const p = path.join(dir, rel);
811
+ fs.mkdirSync(path.dirname(p), { recursive: true });
812
+ fs.writeFileSync(p, body, 'utf-8');
813
+ }
814
+ return dir;
815
+ };
816
+ const skill = (slug: string, packs: string, body: string): [string, string] => [
817
+ `skills/${slug}/SKILL.md`,
818
+ `---\nname: ${slug}\npacks: [${packs}]\n---\n\n${body}\n`,
819
+ ];
820
+ const run = (dir: string): number => {
821
+ const prev = process.env['LINT_PACK_BOUNDARIES_ROOT'];
822
+ process.env['LINT_PACK_BOUNDARIES_ROOT'] = dir;
823
+ try {
824
+ return runGateCli(
825
+ _DEFAULT_ROOT,
826
+ path.join('src', 'scripts', 'lint_pack_boundaries.ts'),
827
+ ['--quiet'],
828
+ _DEFAULT_ROOT,
829
+ );
830
+ } finally {
831
+ if (prev === undefined) {
832
+ delete process.env['LINT_PACK_BOUNDARIES_ROOT'];
833
+ } else {
834
+ process.env['LINT_PACK_BOUNDARIES_ROOT'] = prev;
835
+ }
836
+ fs.rmSync(dir, { recursive: true, force: true });
837
+ }
838
+ };
839
+ const twoPacks = '- id: alpha\n requires: []\n- id: beta\n requires: []\n';
840
+ // A reject case counts only on the exit it names: a crash or a dead-scope
841
+ // exit on a fixture that should yield a finding reads as NOT rejected.
842
+ const rejectsWith = (want: number, got: number): number => (got === want ? 1 : 0);
843
+
844
+ return runSelfTest({
845
+ gate: 'lint_pack_boundaries',
846
+ minCases: 7,
847
+ minRejectCases: 4,
848
+ cases: [
849
+ {
850
+ name: 'an undeclared cross-pack link is rejected with exit 1',
851
+ expect: 'reject',
852
+ run: () =>
853
+ rejectsWith(1, run(
854
+ plant('cross', {
855
+ 'packs.yml': twoPacks,
856
+ ...Object.fromEntries([
857
+ skill('a-one', 'alpha', 'reaches [b](../b-one/SKILL.md)'),
858
+ skill('b-one', 'beta', 'leaf'),
859
+ ]),
860
+ }),
861
+ )),
862
+ },
863
+ {
864
+ name: 'a SKILL.md with no packs is a finding (exit 1), never a silent pass',
865
+ expect: 'reject',
866
+ run: () =>
867
+ rejectsWith(1, run(
868
+ plant('nopack', {
869
+ 'packs.yml': twoPacks,
870
+ 'skills/nopack/SKILL.md': '---\nname: nopack\n---\n\nno packs key\n',
871
+ }),
872
+ )),
873
+ },
874
+ {
875
+ name: 'an empty corpus is a dead scope (exit 2), not "no cross-pack drift"',
876
+ expect: 'reject',
877
+ run: () => rejectsWith(2, run(plant('empty', { 'packs.yml': twoPacks }))),
878
+ },
879
+ {
880
+ name: 'a link declared through requires passes',
881
+ expect: 'accept',
882
+ run: () =>
883
+ run(
884
+ plant('declared', {
885
+ 'packs.yml': '- id: alpha\n requires: [beta]\n- id: beta\n requires: []\n',
886
+ ...Object.fromEntries([
887
+ skill('a-one', 'alpha', 'reaches [b](../b-one/SKILL.md)'),
888
+ skill('b-one', 'beta', 'leaf'),
889
+ ]),
890
+ }),
891
+ ),
892
+ },
893
+ {
894
+ name: 'a link inside one pack passes',
895
+ expect: 'accept',
896
+ run: () =>
897
+ run(
898
+ plant('same', {
899
+ 'packs.yml': twoPacks,
900
+ ...Object.fromEntries([
901
+ skill('a-one', 'alpha', 'reaches [two](../a-two/SKILL.md)'),
902
+ skill('a-two', 'alpha', 'leaf'),
903
+ ]),
904
+ }),
905
+ ),
906
+ },
907
+ {
908
+ name: 'a link an advisory `suggests` edge permits passes',
909
+ expect: 'accept',
910
+ run: () =>
911
+ run(
912
+ plant('suggests-permit', {
913
+ 'packs.yml':
914
+ '- id: alpha\n requires: []\n suggests: [beta]\n' +
915
+ '- id: beta\n requires: []\n',
916
+ ...Object.fromEntries([
917
+ skill('a-one', 'alpha', 'reaches [b](../b-one/SKILL.md)'),
918
+ skill('b-one', 'beta', 'leaf'),
919
+ ]),
920
+ }),
921
+ ),
922
+ },
923
+ {
924
+ // The denial half. Without it the case above cannot tell a
925
+ // working permit from a gate that stopped reporting at all.
926
+ name: 'the same link without the `suggests` edge is still rejected with exit 1',
927
+ expect: 'reject',
928
+ run: () =>
929
+ rejectsWith(1, run(
930
+ plant('suggests-absent', {
931
+ 'packs.yml': twoPacks,
932
+ ...Object.fromEntries([
933
+ skill('a-one', 'alpha', 'reaches [b](../b-one/SKILL.md)'),
934
+ skill('b-one', 'beta', 'leaf'),
935
+ ]),
936
+ }),
937
+ )),
938
+ },
939
+ ],
940
+ });
941
+ }
942
+
576
943
  function main(argv?: readonly string[]): number {
577
- const args = parse_args(argv ?? process.argv.slice(2));
944
+ const rawArgv = argv ?? process.argv.slice(2);
945
+ if (rawArgv.includes('--self-test')) {
946
+ if (process.env['GATE_SELF_TEST_CHILD'] === '1') {
947
+ process.stderr.write('lint_pack_boundaries: --self-test does not recurse\n');
948
+ return 2;
949
+ }
950
+ return selfTest();
951
+ }
952
+ const args = parse_args(rawArgv);
578
953
 
579
954
  const { index: artefact_pack, unassigned, scanned } = _build_artefact_index();
580
955
 
@@ -582,12 +957,17 @@ function main(argv?: readonly string[]): number {
582
957
  // clean. That was this gate's shipped state until 2026-08-02 — it walked
583
958
  // the deleted `packages/` tree and skipped green forever.
584
959
  try {
585
- assertScanned({
586
- gate: 'lint_pack_boundaries',
587
- scanned,
588
- units: 'artefact(s)',
589
- roots: _scan_roots().map((r) => _relPosix(r, ROOT) || '.'),
590
- });
960
+ reportScanned(
961
+ {
962
+ gate: 'lint_pack_boundaries',
963
+ scanned,
964
+ units: 'artefact(s)',
965
+ roots: _scan_roots().map((r) => _relPosix(r, ROOT) || '.'),
966
+ },
967
+ args.format === 'json'
968
+ ? process.stderr.write.bind(process.stderr)
969
+ : process.stdout.write.bind(process.stdout),
970
+ );
591
971
  } catch (exc) {
592
972
  if (!(exc instanceof DeadScopeError)) {
593
973
  throw exc;
@@ -596,7 +976,9 @@ function main(argv?: readonly string[]): number {
596
976
  return 2;
597
977
  }
598
978
 
599
- const pack_requires = _pack_requires();
979
+ const { requires: pack_requires, suggests: pack_suggests } = _pack_edges();
980
+ const suggestsOf = (pack: string): readonly string[] => pack_suggests.get(pack) ?? [];
981
+ const always_installed = _always_installed_packs();
600
982
  const closureCache = new Map<string, Set<string>>();
601
983
  const closureOf = (pack: string): Set<string> => {
602
984
  let c = closureCache.get(pack);
@@ -608,6 +990,7 @@ function main(argv?: readonly string[]): number {
608
990
  };
609
991
 
610
992
  const violations: ViolationRecord[] = [];
993
+ const permitted: PermittedRecord[] = [];
611
994
 
612
995
  // Fail-safe: a unit-defining artefact with no resolvable pack cannot be
613
996
  // boundary-checked, so it is a finding rather than a silent exclusion.
@@ -635,7 +1018,27 @@ function main(argv?: readonly string[]): number {
635
1018
  if (target_packs === undefined) {
636
1019
  continue; // docs/, scripts/, root files, unassigned — not pack-scoped
637
1020
  }
638
- if (_link_allowed(src_packs, target_packs, closureOf)) {
1021
+ const reason = _link_permit_reason(
1022
+ src_packs,
1023
+ target_packs,
1024
+ closureOf,
1025
+ always_installed,
1026
+ suggestsOf,
1027
+ );
1028
+ if (reason !== null) {
1029
+ // Only the advisory edge is worth reporting: the other three
1030
+ // mean the target is installed, so there is nothing a reader
1031
+ // has to weigh.
1032
+ if (reason === 'suggests') {
1033
+ permitted.push({
1034
+ source_pack: src_packs.join('+'),
1035
+ target_pack: target_packs.join('+'),
1036
+ source: rel_path,
1037
+ target: target_rel,
1038
+ link: raw,
1039
+ reason,
1040
+ });
1041
+ }
639
1042
  continue;
640
1043
  }
641
1044
  violations.push({
@@ -665,6 +1068,7 @@ function main(argv?: readonly string[]): number {
665
1068
  count: violations.length,
666
1069
  scanned,
667
1070
  unassigned: unassigned.length,
1071
+ permitted_by_suggests: permitted,
668
1072
  ratchet:
669
1073
  verdict === null ? null : { status: verdict.status, baseline: verdict.baseline },
670
1074
  }) + '\n',
@@ -678,6 +1082,32 @@ function main(argv?: readonly string[]): number {
678
1082
  `${pack_requires.size} packs (${unassigned.length} outside pack scope)\n`,
679
1083
  );
680
1084
  }
1085
+ // Two different questions, so two different defaults.
1086
+ //
1087
+ // HOW MANY links an advisory edge is carrying prints on EVERY run,
1088
+ // `--quiet` included. The permit is granted per EDGE, not per link: once an
1089
+ // edge is declared, every future link on it is permitted without anyone
1090
+ // re-checking that it degrades safely. An adversarial review demonstrated
1091
+ // that by planting a link on a declared edge and watching this gate exit 0
1092
+ // where it would previously have failed the pull request. `--quiet` is what
1093
+ // CI passes, so a count visible only without it would miss the one log that
1094
+ // matters.
1095
+ //
1096
+ // WHICH links they are stays behind `--show-permitted`. A permit is not a
1097
+ // finding, and printing dozens of lines beside the violations reads as one.
1098
+ process.stdout.write(
1099
+ `${permitted.length} link(s) permitted by an advisory \`suggests\` edge` +
1100
+ (args.show_permitted ? '' : ' (--show-permitted lists them)') +
1101
+ '\n',
1102
+ );
1103
+ if (args.show_permitted) {
1104
+ for (const p of permitted) {
1105
+ process.stdout.write(
1106
+ ` ~ ${p.source_pack} -> ${p.target_pack} : ${p.source} \u2192 ${p.target} ` +
1107
+ `(link: ${p.link}) — permitted by \`${p.reason}\`\n`,
1108
+ );
1109
+ }
1110
+ }
681
1111
  for (const v of violations) {
682
1112
  if (v.kind === 'unresolved-pack') {
683
1113
  process.stdout.write(
@@ -693,8 +1123,8 @@ function main(argv?: readonly string[]): number {
693
1123
  }
694
1124
  if (violations.length > 0) {
695
1125
  process.stdout.write(
696
- `\n${violations.length} cross-pack violation(s) — declare 'requires' in ` +
697
- 'pack.yaml or move the artefact\n',
1126
+ `\n${violations.length} cross-pack violation(s) — declare 'requires' or an ` +
1127
+ "advisory 'suggests' edge in packs.yml, or move the artefact\n",
698
1128
  );
699
1129
  if (verdict !== null) {
700
1130
  if (verdict.ok) {
@@ -743,9 +1173,15 @@ export {
743
1173
  _build_artefact_index,
744
1174
  _resolve_link,
745
1175
  _scan_file,
1176
+ _always_installed_packs,
1177
+ type PermitReason,
746
1178
  _is_allowed,
747
1179
  _link_allowed,
1180
+ _link_permit_reason,
1181
+ _pack_suggests,
1182
+ _permit_reason,
748
1183
  _load_pack_meta,
1184
+ _pack_edges,
749
1185
  _pack_requires,
750
1186
  _requires_closure,
751
1187
  _packs_of,