@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
@@ -48,8 +48,31 @@
48
48
  * (external / absolute / out-of-tree targets ignored), the allow rule
49
49
  * (same pack · always-installed · declared `requires`), the per-violation text and
50
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.
51
55
  *
52
- * ## 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.
53
76
  *
54
77
  * `src/config/discovery/packs.yml` is the source of truth for the pack
55
78
  * vocabulary and its `requires` edges — `generate_pack_manifests.ts` DERIVES
@@ -62,6 +85,7 @@
62
85
  */
63
86
 
64
87
  import * as fs from 'node:fs';
88
+ import * as os from 'node:os';
65
89
  import * as path from 'node:path';
66
90
  import { fileURLToPath, pathToFileURL } from 'node:url';
67
91
  import { parse as parseYaml } from 'yaml';
@@ -74,7 +98,8 @@ import {
74
98
  iter_artefacts,
75
99
  } from './_lib/agent_src.js';
76
100
  import { checkRatchet } from './_lib/gate_baseline.js';
77
- 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';
78
103
  import { parse_frontmatter } from './validate_frontmatter.js';
79
104
 
80
105
  const _HERE = path.resolve(fileURLToPath(import.meta.url));
@@ -118,6 +143,19 @@ function _set_paths_for_test(opts: { root?: string; vocab?: string }): void {
118
143
  }
119
144
  }
120
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
+
121
159
  // [..](target) with an optional #fragment / ?query stripped from the target.
122
160
  const LINK_RE = /\[[^\]]*\]\(([^)#?]+)(?:[#?][^)]*)?\)/g;
123
161
 
@@ -180,6 +218,35 @@ interface ViolationRecord {
180
218
  link: string;
181
219
  }
182
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
+
183
250
  /** Mirror Python `Path.resolve()`: canonicalize existing prefix, append rest. */
184
251
  function _realpath(p: string): string {
185
252
  try {
@@ -325,7 +392,36 @@ function _pack_home_dirs(): string[] {
325
392
  * manifests as an overlay for pack homes the vocabulary does not list.
326
393
  */
327
394
  function _pack_requires(): Map<string, string[]> {
328
- 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[]>();
329
425
  const asList = (v: unknown): string[] => (Array.isArray(v) ? v.map(String) : []);
330
426
 
331
427
  if (_exists(VOCAB)) {
@@ -335,7 +431,8 @@ function _pack_requires(): Map<string, string[]> {
335
431
  if (entry !== null && typeof entry === 'object' && !Array.isArray(entry)) {
336
432
  const e = entry as Record<string, unknown>;
337
433
  if (typeof e['id'] === 'string') {
338
- out.set(e['id'], asList(e['requires']));
434
+ requires.set(e['id'], asList(e['requires']));
435
+ suggests.set(e['id'], asList(e['suggests']));
339
436
  }
340
437
  }
341
438
  }
@@ -344,11 +441,12 @@ function _pack_requires(): Map<string, string[]> {
344
441
  for (const dir of _pack_home_dirs()) {
345
442
  const meta = _load_pack_meta(dir);
346
443
  const id = typeof meta['id'] === 'string' ? meta['id'] : path.basename(dir);
347
- if (!out.has(id)) {
348
- 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']));
349
447
  }
350
448
  }
351
- return out;
449
+ return { requires, suggests };
352
450
  }
353
451
 
354
452
  /** Transitive expansion of `requires`, cycle-safe. */
@@ -529,19 +627,45 @@ function _scan_file(p: string): string[] {
529
627
  return out;
530
628
  }
531
629
 
532
- function _is_allowed(
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(
533
639
  source_pack: string,
534
640
  target_pack: string,
535
641
  requires: string[],
536
642
  always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
537
- ): boolean {
643
+ suggests: readonly string[] = [],
644
+ ): PermitReason {
538
645
  if (source_pack === target_pack) {
539
- return true;
646
+ return 'same-pack';
540
647
  }
541
648
  if (always_installed.has(target_pack)) {
542
- return true;
649
+ return 'always-installed';
650
+ }
651
+ if ((requires || []).includes(target_pack)) {
652
+ return 'requires';
543
653
  }
544
- return (requires || []).includes(target_pack);
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;
545
669
  }
546
670
 
547
671
  /**
@@ -557,11 +681,47 @@ function _link_allowed(
557
681
  target_packs: readonly string[],
558
682
  closureOf: (pack: string) => Set<string>,
559
683
  always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
684
+ suggestsOf: (pack: string) => readonly string[] = () => [],
560
685
  ): boolean {
561
- 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) {
562
708
  const reach = [...closureOf(s)];
563
- return target_packs.some((t) => _is_allowed(s, t, reach, always_installed));
564
- });
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;
565
725
  }
566
726
 
567
727
  /** Mirror Python `json.dump(obj, indent=2)` with `ensure_ascii=True`. */
@@ -584,11 +744,14 @@ function _json_dumps_ascii(obj: unknown): string {
584
744
  interface ParsedArgs {
585
745
  format: 'text' | 'json';
586
746
  quiet: boolean;
747
+ /** List the links permitted only by an advisory `suggests` edge. */
748
+ show_permitted: boolean;
587
749
  }
588
750
 
589
751
  function parse_args(argv: readonly string[]): ParsedArgs {
590
752
  let format: 'text' | 'json' = 'text';
591
753
  let quiet = false;
754
+ let show_permitted = false;
592
755
  for (let i = 0; i < argv.length; i++) {
593
756
  const arg = argv[i] as string;
594
757
  if (arg === '--format') {
@@ -612,16 +775,19 @@ function parse_args(argv: readonly string[]): ParsedArgs {
612
775
  format = v;
613
776
  } else if (arg === '--quiet') {
614
777
  quiet = true;
778
+ } else if (arg === '--show-permitted') {
779
+ show_permitted = true;
615
780
  } else if (arg === '-h' || arg === '--help') {
616
781
  process.stdout.write(
617
- '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',
618
784
  );
619
785
  process.exit(0);
620
786
  } else {
621
787
  _argparse_error(`unrecognized arguments: ${arg}`);
622
788
  }
623
789
  }
624
- return { format, quiet };
790
+ return { format, quiet, show_permitted };
625
791
  }
626
792
 
627
793
  function _argparse_error(message: string): never {
@@ -629,8 +795,161 @@ function _argparse_error(message: string): never {
629
795
  process.exit(2);
630
796
  }
631
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
+
632
943
  function main(argv?: readonly string[]): number {
633
- 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);
634
953
 
635
954
  const { index: artefact_pack, unassigned, scanned } = _build_artefact_index();
636
955
 
@@ -638,12 +957,17 @@ function main(argv?: readonly string[]): number {
638
957
  // clean. That was this gate's shipped state until 2026-08-02 — it walked
639
958
  // the deleted `packages/` tree and skipped green forever.
640
959
  try {
641
- assertScanned({
642
- gate: 'lint_pack_boundaries',
643
- scanned,
644
- units: 'artefact(s)',
645
- roots: _scan_roots().map((r) => _relPosix(r, ROOT) || '.'),
646
- });
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
+ );
647
971
  } catch (exc) {
648
972
  if (!(exc instanceof DeadScopeError)) {
649
973
  throw exc;
@@ -652,7 +976,8 @@ function main(argv?: readonly string[]): number {
652
976
  return 2;
653
977
  }
654
978
 
655
- 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) ?? [];
656
981
  const always_installed = _always_installed_packs();
657
982
  const closureCache = new Map<string, Set<string>>();
658
983
  const closureOf = (pack: string): Set<string> => {
@@ -665,6 +990,7 @@ function main(argv?: readonly string[]): number {
665
990
  };
666
991
 
667
992
  const violations: ViolationRecord[] = [];
993
+ const permitted: PermittedRecord[] = [];
668
994
 
669
995
  // Fail-safe: a unit-defining artefact with no resolvable pack cannot be
670
996
  // boundary-checked, so it is a finding rather than a silent exclusion.
@@ -692,7 +1018,27 @@ function main(argv?: readonly string[]): number {
692
1018
  if (target_packs === undefined) {
693
1019
  continue; // docs/, scripts/, root files, unassigned — not pack-scoped
694
1020
  }
695
- if (_link_allowed(src_packs, target_packs, closureOf, always_installed)) {
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
+ }
696
1042
  continue;
697
1043
  }
698
1044
  violations.push({
@@ -722,6 +1068,7 @@ function main(argv?: readonly string[]): number {
722
1068
  count: violations.length,
723
1069
  scanned,
724
1070
  unassigned: unassigned.length,
1071
+ permitted_by_suggests: permitted,
725
1072
  ratchet:
726
1073
  verdict === null ? null : { status: verdict.status, baseline: verdict.baseline },
727
1074
  }) + '\n',
@@ -735,6 +1082,32 @@ function main(argv?: readonly string[]): number {
735
1082
  `${pack_requires.size} packs (${unassigned.length} outside pack scope)\n`,
736
1083
  );
737
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
+ }
738
1111
  for (const v of violations) {
739
1112
  if (v.kind === 'unresolved-pack') {
740
1113
  process.stdout.write(
@@ -750,8 +1123,8 @@ function main(argv?: readonly string[]): number {
750
1123
  }
751
1124
  if (violations.length > 0) {
752
1125
  process.stdout.write(
753
- `\n${violations.length} cross-pack violation(s) — declare 'requires' in ` +
754
- '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",
755
1128
  );
756
1129
  if (verdict !== null) {
757
1130
  if (verdict.ok) {
@@ -801,9 +1174,14 @@ export {
801
1174
  _resolve_link,
802
1175
  _scan_file,
803
1176
  _always_installed_packs,
1177
+ type PermitReason,
804
1178
  _is_allowed,
805
1179
  _link_allowed,
1180
+ _link_permit_reason,
1181
+ _pack_suggests,
1182
+ _permit_reason,
806
1183
  _load_pack_meta,
1184
+ _pack_edges,
807
1185
  _pack_requires,
808
1186
  _requires_closure,
809
1187
  _packs_of,