@event4u/agent-config 16.1.0 → 16.3.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 (467) 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 +98 -257
  5. package/README.md +14 -12
  6. package/dist/agent-src/commands/analyze/inbox.md +1 -1
  7. package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
  8. package/dist/agent-src/commands/bug/fix.md +17 -2
  9. package/dist/agent-src/commands/feature/plan.md +1 -1
  10. package/dist/agent-src/commands/feature/roadmap.md +1 -1
  11. package/dist/agent-src/commands/fix/ci.md +1 -1
  12. package/dist/agent-src/commands/implement-ticket.md +1 -1
  13. package/dist/agent-src/commands/jira-ticket.md +1 -1
  14. package/dist/agent-src/commands/roadmap/create.md +1 -1
  15. package/dist/agent-src/commands/roadmap/materialize.md +1 -1
  16. package/dist/agent-src/commands/roadmap/process-full.md +5 -5
  17. package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
  18. package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
  19. package/dist/agent-src/commands/roadmap.md +18 -4
  20. package/dist/agent-src/commands/tests/create.md +17 -3
  21. package/dist/agent-src/commands/tests/execute.md +22 -5
  22. package/dist/agent-src/commands/work.md +4 -0
  23. package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
  24. package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
  25. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
  26. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +4 -8
  27. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
  28. package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
  29. package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
  30. package/dist/agent-src/rules/active-remediation.md +1 -1
  31. package/dist/agent-src/rules/autonomous-execution.md +1 -0
  32. package/dist/agent-src/rules/broken-access-control.md +1 -0
  33. package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
  34. package/dist/agent-src/rules/context-hygiene.md +1 -1
  35. package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
  36. package/dist/agent-src/rules/design-fidelity.md +13 -16
  37. package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
  38. package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
  39. package/dist/agent-src/rules/domain-safety-pii.md +1 -0
  40. package/dist/agent-src/rules/domain-safety-retention.md +1 -0
  41. package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
  42. package/dist/agent-src/rules/evaluator-independence.md +3 -2
  43. package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
  44. package/dist/agent-src/rules/finance-safety-floor.md +1 -0
  45. package/dist/agent-src/rules/git-history-discipline.md +1 -0
  46. package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
  47. package/dist/agent-src/rules/legal-safety-floor.md +3 -2
  48. package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
  49. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
  50. package/dist/agent-src/rules/media-governance-routing.md +14 -17
  51. package/dist/agent-src/rules/persona-governance.md +2 -2
  52. package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
  53. package/dist/agent-src/rules/question-not-instruction.md +1 -0
  54. package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
  55. package/dist/agent-src/rules/runtime-safety.md +1 -0
  56. package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
  57. package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
  58. package/dist/agent-src/rules/session-canary.md +8 -62
  59. package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
  60. package/dist/agent-src/rules/source-confidentiality.md +1 -0
  61. package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
  62. package/dist/agent-src/rules/tool-safety.md +1 -0
  63. package/dist/agent-src/rules/ui-audit-gate.md +1 -2
  64. package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
  65. package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
  66. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  67. package/dist/agent-src/scripts/deferral_carry.ts +339 -0
  68. package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
  69. package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +1 -1
  70. package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +2 -2
  71. package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
  72. package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
  73. package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
  74. package/dist/agent-src/skills/design-review/SKILL.md +30 -4
  75. package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
  76. package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
  77. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +18 -3
  78. package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
  79. package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
  80. package/dist/agent-src/skills/iconography/SKILL.md +1 -1
  81. package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
  82. package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
  83. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
  84. package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
  85. package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
  86. package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
  87. package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
  88. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  89. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
  90. package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
  91. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
  92. package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
  93. package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
  94. package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
  95. package/dist/agent-src/skills/ui-component-architect/SKILL.md +25 -2
  96. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  97. package/dist/agent-src/templates/roadmaps.md +30 -0
  98. package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
  99. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
  100. package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
  101. package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
  102. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  103. package/dist/agent-src/templates/scripts/work_engine/state.ts +57 -7
  104. package/dist/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
  105. package/dist/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
  106. package/dist/cli/python/knowledge_ingest.js +1 -1
  107. package/dist/cli/python/workspace_drive.js +1 -1
  108. package/dist/cli/registry.js +1 -1
  109. package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
  110. package/dist/cli-delegate/check_update_banner.js +12 -1
  111. package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
  112. package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
  113. package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
  114. package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
  115. package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
  116. package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
  117. package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
  118. package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
  119. package/dist/cli-delegate/{chunk-UNCRJBT3.js → chunk-JQVYKIZA.js} +41 -0
  120. package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
  121. package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
  122. package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-KR6EM23A.js} +235 -1455
  123. package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
  124. package/dist/cli-delegate/chunk-NQ7WT43P.js +2729 -0
  125. package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
  126. package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
  127. package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
  128. package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
  129. package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
  130. package/dist/cli-delegate/{chunk-HDVVGPQW.js → chunk-RQNNW7IF.js} +1405 -567
  131. package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-S4UMZNES.js} +1 -1
  132. package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
  133. package/dist/cli-delegate/{chunk-GJCBB2UG.js → chunk-TRI6DQZ6.js} +3054 -325
  134. package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
  135. package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
  136. package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
  137. package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
  138. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  139. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  140. package/dist/cli-delegate/cmd_conformance.js +1862 -809
  141. package/dist/cli-delegate/cmd_doctor.js +13 -6
  142. package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
  143. package/dist/cli-delegate/cmd_explain.js +5 -5
  144. package/dist/cli-delegate/cmd_export.js +11 -8
  145. package/dist/cli-delegate/cmd_fleet.js +3 -3
  146. package/dist/cli-delegate/cmd_handoff.js +10 -7
  147. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  148. package/dist/cli-delegate/cmd_memory_get.js +3 -1
  149. package/dist/cli-delegate/cmd_migrate.js +2 -2
  150. package/dist/cli-delegate/cmd_packs_active.js +3 -3
  151. package/dist/cli-delegate/cmd_preflight.js +6 -6
  152. package/dist/cli-delegate/cmd_prune.js +11 -8
  153. package/dist/cli-delegate/cmd_refresh.js +2 -1
  154. package/dist/cli-delegate/cmd_route_audit.js +8 -6
  155. package/dist/cli-delegate/cmd_route_explain.js +4 -4
  156. package/dist/cli-delegate/cmd_session_recycle.js +4 -3
  157. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  158. package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
  159. package/dist/cli-delegate/cmd_settings_set.js +4 -4
  160. package/dist/cli-delegate/cmd_sync.js +11 -8
  161. package/dist/cli-delegate/cmd_uninstall.js +11 -8
  162. package/dist/cli-delegate/cmd_update.js +1 -1
  163. package/dist/cli-delegate/cmd_upgrade.js +3 -2
  164. package/dist/cli-delegate/cmd_validate.js +11 -8
  165. package/dist/cli-delegate/cmd_versions.js +1 -1
  166. package/dist/cli-delegate/deferral_carry.js +16 -0
  167. package/dist/cli-delegate/gate_execute.js +2 -2
  168. package/dist/cli-delegate/roadmap_gates.js +5 -5
  169. package/dist/cli-delegate/update_roadmap_progress.js +1 -1
  170. package/dist/discovery/deprecation-report.md +1 -1
  171. package/dist/discovery/discovery-manifest.json +132 -80
  172. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  173. package/dist/discovery/discovery-manifest.summary.md +3 -3
  174. package/dist/discovery/dormancy-report.md +1 -1
  175. package/dist/discovery/orphan-report.md +1 -1
  176. package/dist/discovery/packs.json +7 -5
  177. package/dist/discovery/trust-report.md +2 -2
  178. package/dist/discovery/workspaces.json +6 -4
  179. package/dist/hooks/dispatch.js +7972 -5186
  180. package/dist/hooks/dispatch.sha256 +1 -0
  181. package/dist/install/claudePathsPlan.js +47 -6
  182. package/dist/install/claudeRuleRewrite.js +7 -0
  183. package/dist/install/emit_host_rules_cli.js +39 -36
  184. package/dist/install/globalRuleScope.js +87 -0
  185. package/dist/install/host_rule_ownership.js +160 -0
  186. package/dist/install/install.mjs +2226 -1055
  187. package/dist/install/installThinLayer.js +261 -0
  188. package/dist/install/installedRuleLinks.js +176 -0
  189. package/dist/install/wizard-plan.js +24 -0
  190. package/dist/mcp/registry-manifest.json +3 -3
  191. package/dist/mcp/server.json +2 -2
  192. package/dist/mcp/server.mjs +40913 -34865
  193. package/dist/scripts/_lib/agent_settings.js +11 -0
  194. package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
  195. package/dist/scripts/_lib/installed_layer.js +378 -0
  196. package/dist/scripts/_lib/lean_projection_mode.js +218 -15
  197. package/dist/scripts/_lib/rule_consequence_class.js +45 -0
  198. package/dist/scripts/_lib/rule_injection.js +67 -10
  199. package/dist/scripts/_lib/rule_law_section.js +122 -0
  200. package/dist/scripts/_lib/thin_rules.js +458 -0
  201. package/dist/scripts/_lib/windsurf_render.js +60 -0
  202. package/dist/scripts/condense.js +14 -26
  203. package/dist/scripts/project_thin_rules.js +14 -294
  204. package/dist/server/schemas/settings.js +29 -0
  205. package/dist/shared/skillRanking.js +74 -13
  206. package/dist/ui/assets/index-Cwq4d0hX.js +23 -0
  207. package/dist/ui/assets/index-Cyjy8bWO.css +1 -0
  208. package/dist/ui/index.html +2 -2
  209. package/docs/contracts/settings-classes.md +10 -6
  210. package/package.json +4 -4
  211. package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  212. package/src/agent-src/scripts/deferral_carry.ts +339 -0
  213. package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
  214. package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
  215. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
  216. package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
  217. package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
  218. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  219. package/src/agent-src/templates/scripts/work_engine/state.ts +57 -7
  220. package/src/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
  221. package/src/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
  222. package/src/config/agent-settings.template.yml +91 -22
  223. package/src/config/ci-local-parity.yml +18 -0
  224. package/src/config/continuity-surface.json +9 -2
  225. package/src/config/evaluator-budgets.json +4 -4
  226. package/src/config/gate-coverage.yml +327 -3
  227. package/src/config/gate-violation-baselines.json +21 -9
  228. package/src/config/hook-bundle-budget.json +25 -0
  229. package/src/config/hook-latency-budget.json +21 -0
  230. package/src/config/hook-token-budget.json +8 -3
  231. package/src/config/host-instruction-limits.json +33 -0
  232. package/src/config/metric-registry.yml +114 -0
  233. package/src/config/placeholder-drift-budget.json +10 -0
  234. package/src/config/routing-coverage-seed.json +38 -3
  235. package/src/config/rule-activation-census.json +7 -3
  236. package/src/config/rule-consequence-class.json +161 -0
  237. package/src/config/rule-law-ceilings.json +99 -0
  238. package/src/install/claudePathsPlan.ts +46 -4
  239. package/src/install/claudeRuleRewrite.ts +10 -1
  240. package/src/install/emit_host_rules_cli.ts +43 -34
  241. package/src/install/globalRuleScope.ts +109 -0
  242. package/src/install/host_rule_ownership.ts +170 -0
  243. package/src/install/installThinLayer.ts +312 -0
  244. package/src/install/installedRuleLinks.ts +220 -0
  245. package/src/install/wizard-plan.ts +24 -0
  246. package/src/scripts/_cli/cmd_doctor.ts +28 -90
  247. package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
  248. package/src/scripts/_cli/doctor_execution.ts +100 -17
  249. package/src/scripts/_cli/doctor_network_posture.ts +226 -0
  250. package/src/scripts/_dispatch.bash +16 -2
  251. package/src/scripts/_lib/agent_settings.ts +11 -0
  252. package/src/scripts/_lib/body_portable.ts +102 -0
  253. package/src/scripts/_lib/cc_transcript.ts +132 -1
  254. package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
  255. package/src/scripts/_lib/concern_sla_window.ts +200 -0
  256. package/src/scripts/_lib/estate_offsets.ts +241 -0
  257. package/src/scripts/_lib/exemption_shape.ts +143 -0
  258. package/src/scripts/_lib/fnv.ts +23 -0
  259. package/src/scripts/_lib/foreign_scan.ts +106 -0
  260. package/src/scripts/_lib/forge_protection.ts +114 -0
  261. package/src/scripts/_lib/forge_reader.ts +558 -0
  262. package/src/scripts/_lib/gitignore_block.ts +314 -0
  263. package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
  264. package/src/scripts/_lib/graph_feeder_record.ts +214 -0
  265. package/src/scripts/_lib/hook_settings.ts +73 -0
  266. package/src/scripts/_lib/host_capability.ts +40 -19
  267. package/src/scripts/_lib/host_env_write.ts +111 -0
  268. package/src/scripts/_lib/host_hook_merge.ts +165 -0
  269. package/src/scripts/_lib/installed_layer.ts +538 -0
  270. package/src/scripts/_lib/json_merge.ts +82 -0
  271. package/src/scripts/_lib/json_pointers.ts +93 -11
  272. package/src/scripts/_lib/lean_projection_mode.ts +275 -15
  273. package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
  274. package/src/scripts/_lib/machine_wake.ts +16 -3
  275. package/src/scripts/_lib/neighbour_census.ts +760 -0
  276. package/src/scripts/_lib/neighbour_scan.ts +122 -0
  277. package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
  278. package/src/scripts/_lib/obligations.ts +119 -8
  279. package/src/scripts/_lib/probe_inputs.ts +271 -0
  280. package/src/scripts/_lib/prompt_shape.ts +46 -0
  281. package/src/scripts/_lib/read_surface_scan.ts +322 -0
  282. package/src/scripts/_lib/release_highlights.ts +2 -1
  283. package/src/scripts/_lib/release_migration_gate.ts +19 -3
  284. package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
  285. package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
  286. package/src/scripts/_lib/review_coverage.ts +134 -0
  287. package/src/scripts/_lib/rule_consequence_class.ts +71 -0
  288. package/src/scripts/_lib/rule_injection.ts +130 -10
  289. package/src/scripts/_lib/rule_law_section.ts +147 -0
  290. package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
  291. package/src/scripts/_lib/shell_write_shapes.ts +108 -0
  292. package/src/scripts/_lib/skill_origin.ts +254 -0
  293. package/src/scripts/_lib/structural_hiding.ts +622 -0
  294. package/src/scripts/_lib/structured_ask.ts +64 -21
  295. package/src/scripts/_lib/thin_rules.ts +540 -0
  296. package/src/scripts/_lib/touched_file_quality.ts +434 -0
  297. package/src/scripts/_lib/turn_end_refusals.ts +600 -4
  298. package/src/scripts/_lib/turn_end_transcript.ts +216 -0
  299. package/src/scripts/_lib/verification_command.ts +324 -0
  300. package/src/scripts/_lib/verification_evidence.ts +647 -0
  301. package/src/scripts/_lib/verify_clause.ts +280 -0
  302. package/src/scripts/_lib/windsurf_render.ts +63 -0
  303. package/src/scripts/ai_council/cli_call_budget.ts +13 -5
  304. package/src/scripts/ai_council/clients.ts +26 -57
  305. package/src/scripts/ai_council/config.ts +1 -1
  306. package/src/scripts/ai_council/vendor_defaults.ts +45 -0
  307. package/src/scripts/ai_team/team_dispatch.ts +4 -0
  308. package/src/scripts/audit_skill_overlap.ts +261 -0
  309. package/src/scripts/before_complete_hook.ts +573 -25
  310. package/src/scripts/bench_hook_latency.ts +412 -5
  311. package/src/scripts/bench_touched_file_quality.ts +238 -0
  312. package/src/scripts/cache_realization_report.ts +61 -1
  313. package/src/scripts/check_argument_hint.ts +287 -0
  314. package/src/scripts/check_claims.ts +125 -1
  315. package/src/scripts/check_enforcement_coverage.ts +38 -9
  316. package/src/scripts/check_enforcement_matrix.ts +621 -22
  317. package/src/scripts/check_estate_count.ts +130 -153
  318. package/src/scripts/check_finding_dispositions.ts +138 -7
  319. package/src/scripts/check_generator_sync.ts +71 -0
  320. package/src/scripts/check_hook_bundle_composition.ts +370 -0
  321. package/src/scripts/check_host_docs_digest.ts +786 -0
  322. package/src/scripts/check_host_format_column.ts +559 -0
  323. package/src/scripts/check_input_references.ts +228 -0
  324. package/src/scripts/check_inputs_parity.ts +235 -0
  325. package/src/scripts/check_kernel_edit_ratified.ts +89 -9
  326. package/src/scripts/check_kill_switch_table.ts +294 -0
  327. package/src/scripts/check_memory.ts +7 -1
  328. package/src/scripts/check_placeholder_drift.ts +221 -0
  329. package/src/scripts/check_read_surface_coverage.ts +515 -0
  330. package/src/scripts/check_release_highlights.ts +10 -0
  331. package/src/scripts/check_release_holds.ts +2 -1
  332. package/src/scripts/check_release_pr_shape.ts +38 -15
  333. package/src/scripts/check_routing_coverage.ts +378 -11
  334. package/src/scripts/check_standing_rule_delivery.ts +33 -13
  335. package/src/scripts/check_static_parity.ts +17 -0
  336. package/src/scripts/check_verify_expectation_delta.ts +521 -0
  337. package/src/scripts/ci_settle.ts +145 -19
  338. package/src/scripts/closure_scan.ts +115 -1
  339. package/src/scripts/code_graph/detect.ts +127 -7
  340. package/src/scripts/code_graph/foreign.ts +194 -0
  341. package/src/scripts/code_graph/query.ts +217 -4
  342. package/src/scripts/code_graph/types.ts +26 -2
  343. package/src/scripts/code_graph/validate.ts +3 -1
  344. package/src/scripts/code_graph/verbs.ts +103 -0
  345. package/src/scripts/compile_hook_manifest.ts +90 -14
  346. package/src/scripts/condense.ts +14 -27
  347. package/src/scripts/estate_exemption_shape.ts +202 -0
  348. package/src/scripts/external_sources_denylist.json +29 -4
  349. package/src/scripts/generate_host_cost_table.ts +1 -1
  350. package/src/scripts/hook_manifest.json +1 -1
  351. package/src/scripts/hook_manifest.yaml +192 -14
  352. package/src/scripts/hooks/block_config_weakening.ts +294 -4
  353. package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
  354. package/src/scripts/hooks/block_plumbing_writes.ts +342 -0
  355. package/src/scripts/hooks/bundle_integrity.ts +291 -0
  356. package/src/scripts/hooks/chain_nudge_hook.ts +1 -2
  357. package/src/scripts/hooks/code_graph_context_hook.ts +253 -25
  358. package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
  359. package/src/scripts/hooks/concern_failure_policy.ts +280 -0
  360. package/src/scripts/hooks/concern_registry.ts +2 -0
  361. package/src/scripts/hooks/concern_timings.ts +94 -0
  362. package/src/scripts/hooks/delegation_nudge_hook.ts +1 -2
  363. package/src/scripts/hooks/design_pass_hook.ts +100 -9
  364. package/src/scripts/hooks/design_slop_hook.ts +1 -2
  365. package/src/scripts/hooks/dispatch_hook.ts +77 -71
  366. package/src/scripts/hooks/edit_shape_hook.ts +1 -2
  367. package/src/scripts/hooks/end_review_nudge_hook.ts +1 -1
  368. package/src/scripts/hooks/evidence_independence.ts +1 -2
  369. package/src/scripts/hooks/exit_codes.ts +129 -0
  370. package/src/scripts/hooks/host_lowering.json +1 -0
  371. package/src/scripts/hooks/host_lowering.ts +146 -3
  372. package/src/scripts/hooks/host_lowering.yaml +262 -46
  373. package/src/scripts/hooks/host_semantics.ts +30 -2
  374. package/src/scripts/hooks/injection_budget.ts +9 -2
  375. package/src/scripts/hooks/interruption_ledger_hook.ts +1 -2
  376. package/src/scripts/hooks/journal_record_hook.ts +1 -2
  377. package/src/scripts/hooks/memory_recall_hook.ts +1 -2
  378. package/src/scripts/hooks/obligation_settle_hook.ts +151 -5
  379. package/src/scripts/hooks/one_question_per_ask_hook.ts +43 -6
  380. package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
  381. package/src/scripts/hooks/payload_stub.ts +10 -1
  382. package/src/scripts/hooks/permission_gate.ts +1 -2
  383. package/src/scripts/hooks/push_settle_hook.ts +1 -3
  384. package/src/scripts/hooks/replay_hook.ts +2 -1
  385. package/src/scripts/hooks/reread_guard_hook.ts +1 -2
  386. package/src/scripts/hooks/review_baseline_hook.ts +1 -2
  387. package/src/scripts/hooks/rtk_wrap_hook.ts +1 -2
  388. package/src/scripts/hooks/rule_inject_hook.ts +765 -68
  389. package/src/scripts/hooks/run_continuation_hook.ts +13 -15
  390. package/src/scripts/hooks/skill_route_hook.ts +1 -2
  391. package/src/scripts/hooks/source_first_gate_hook.ts +1 -2
  392. package/src/scripts/hooks/spawn_guard_shadow_hook.ts +1 -2
  393. package/src/scripts/hooks/subagent_ledger_hook.ts +1 -2
  394. package/src/scripts/hooks/suggestion_capture_hook.ts +1 -1
  395. package/src/scripts/hooks/table_fingerprint.ts +70 -0
  396. package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
  397. package/src/scripts/hooks/telemetry_usage_hook.ts +65 -10
  398. package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
  399. package/src/scripts/hooks/turn_end_gate_hook.ts +421 -324
  400. package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
  401. package/src/scripts/hooks_status.ts +112 -0
  402. package/src/scripts/injection_scan_hook.ts +7 -0
  403. package/src/scripts/install.ts +75 -189
  404. package/src/scripts/installed_layer_report.ts +103 -0
  405. package/src/scripts/language_mirror_hook.ts +15 -6
  406. package/src/scripts/learning_sidecar.ts +119 -8
  407. package/src/scripts/lint_deny_text.ts +419 -0
  408. package/src/scripts/lint_exit_codes.ts +262 -0
  409. package/src/scripts/lint_hook_manifest.ts +108 -0
  410. package/src/scripts/lint_major_migration_sections.ts +156 -26
  411. package/src/scripts/lint_pack_boundaries.ts +63 -5
  412. package/src/scripts/lint_roadmap_blockers.ts +78 -12
  413. package/src/scripts/lint_rule_law_section.ts +517 -0
  414. package/src/scripts/lint_skill_descriptions.ts +1 -1
  415. package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
  416. package/src/scripts/lint_workflow_security.ts +161 -5
  417. package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
  418. package/src/scripts/mcp_server/graph_tools.ts +72 -3
  419. package/src/scripts/mcp_server/prompts.ts +142 -1
  420. package/src/scripts/measure_routing_signal.ts +54 -16
  421. package/src/scripts/measure_skill_ranker_baseline.ts +515 -53
  422. package/src/scripts/measure_turn_end_gate.ts +193 -0
  423. package/src/scripts/memory_learn_hook.ts +91 -6
  424. package/src/scripts/memory_lookup.ts +1 -1
  425. package/src/scripts/model_rule_injection.ts +52 -5
  426. package/src/scripts/prepack-check.mjs +53 -0
  427. package/src/scripts/project_thin_rules.ts +34 -327
  428. package/src/scripts/release_publication.ts +13 -1
  429. package/src/scripts/report_evidence_temperature.ts +657 -0
  430. package/src/scripts/report_installed_rule_links.ts +157 -0
  431. package/src/scripts/report_invocation_surface.ts +383 -0
  432. package/src/scripts/report_label_agreement.ts +233 -0
  433. package/src/scripts/report_obligation_carriers.ts +699 -0
  434. package/src/scripts/report_obligation_mechanism.ts +230 -0
  435. package/src/scripts/report_obligation_writer_split.ts +236 -0
  436. package/src/scripts/report_single_token_triggers.ts +277 -0
  437. package/src/scripts/report_skill_menu_census.ts +208 -0
  438. package/src/scripts/report_skill_ranker_confusion.ts +442 -0
  439. package/src/scripts/report_standing_payload_by_host.ts +188 -15
  440. package/src/scripts/report_verification_record_coverage.ts +306 -0
  441. package/src/scripts/roadmap_verify_share.ts +213 -0
  442. package/src/scripts/rule_activation_census.ts +5 -2
  443. package/src/scripts/rule_trigger_eval.ts +9 -9
  444. package/src/scripts/schemas/command.schema.json +44 -0
  445. package/src/scripts/schemas/review-findings.schema.json +7 -2
  446. package/src/scripts/schemas/rule.schema.json +5 -0
  447. package/src/scripts/schemas/skill.schema.json +44 -0
  448. package/src/scripts/self_review_gate.ts +421 -17
  449. package/src/scripts/semantic_parity_census.ts +314 -0
  450. package/src/scripts/session_eol_report.ts +54 -1
  451. package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
  452. package/src/scripts/sweep_dead_scan_roots.ts +1 -1
  453. package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
  454. package/src/scripts/sync_gitignore.ts +29 -235
  455. package/src/scripts/trigger_eval_grandfather.json +0 -7
  456. package/src/scripts/trigger_eval_rotation.ts +122 -27
  457. package/src/scripts/ui_conformance_probe.ts +156 -4
  458. package/src/scripts/update_prices.ts +85 -3
  459. package/src/scripts/write_bundle_digest.mjs +74 -0
  460. package/src/server/schemas/settings.ts +41 -0
  461. package/src/shared/skillRanking.ts +117 -11
  462. package/src/templates/consumer-settings/ONBOARDING.md +1 -0
  463. package/dist/cli-delegate/chunk-FXYUYU4N.js +0 -4416
  464. package/dist/cli-delegate/chunk-QJWAUMJW.js +0 -1072
  465. package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
  466. package/dist/ui/assets/index-DH1xc62v.js +0 -29
  467. package/dist/ui/assets/index-jSfMW8_t.css +0 -1
@@ -53,6 +53,23 @@ const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
53
53
 
54
54
  export const GATE = 'lint_major_migration_sections';
55
55
  export const MIGRATION_PATH = path.join('docs', 'MIGRATION.md');
56
+
57
+ /**
58
+ * The consumer-facing index of what every major broke.
59
+ *
60
+ * The SECOND obligation this gate carries, and it is the same obligation
61
+ * pointed at a different reader. `docs/MIGRATION.md` answers "what do I have to
62
+ * do"; this table answers "what happened, and when" — it is the first thing
63
+ * somebody planning an upgrade across several majors opens, because it is the
64
+ * only place the breaks are side by side.
65
+ *
66
+ * It stopped at 9.0.0 while the archived changelogs carried 10.0.0 through
67
+ * 16.0.0. Seven majors with no row, and nothing in the tree could see it: the
68
+ * forward half (`lint_scheduled_deprecations`) looks at commitments, the
69
+ * backward half looked only at `MIGRATION.md`, and the index was guarded by
70
+ * nobody. The source that reported it counted the report as its twentieth.
71
+ */
72
+ export const BREAKING_INDEX_PATH = 'BREAKING_CHANGES.md';
56
73
  const CHANGELOG_PATH = 'CHANGELOG.md';
57
74
  const ARCHIVE_DIR = path.join('docs', 'archive');
58
75
 
@@ -145,8 +162,37 @@ export function migrationVersions(text: string): Set<string> {
145
162
  return out;
146
163
  }
147
164
 
165
+ /**
166
+ * Versions the breaking-changes index carries a ROW for.
167
+ *
168
+ * Reads the FIRST cell only, and that is the load-bearing choice rather than a
169
+ * parsing convenience. The live table's Migration cells end in pointers like
170
+ * "See [CHANGELOG 8.0.0](CHANGELOG.md)", so a whole-line scan would hand the
171
+ * index rows it does not have — and would do it in the direction that makes the
172
+ * gate green, which is the direction a reader cannot detect.
173
+ *
174
+ * The bold spelling the table happens to use is not required: a row is a row.
175
+ */
176
+ export function indexVersions(text: string): Set<string> {
177
+ const out = new Set<string>();
178
+ for (const line of text.split('\n')) {
179
+ const trimmed = line.trim();
180
+ if (!trimmed.startsWith('|')) continue;
181
+ const first = trimmed.slice(1).split('|')[0];
182
+ if (first === undefined) continue;
183
+ for (const m of first.matchAll(/(?<![\d.])(\d+)\.0\.0(?![\d.])/g)) {
184
+ out.add(`${m[1] as string}.0.0`);
185
+ }
186
+ }
187
+ return out;
188
+ }
189
+
190
+ /** Which of the two obligations a major failed. Never empty on a finding. */
191
+ export type MissingKind = 'migration' | 'index';
192
+
148
193
  export interface Finding {
149
194
  readonly section: MajorSection;
195
+ readonly missing: readonly MissingKind[];
150
196
  }
151
197
 
152
198
  /** Read every changelog file under `root`, newest-era file first. */
@@ -171,15 +217,23 @@ export interface EvaluateResult {
171
217
  }
172
218
 
173
219
  /**
174
- * Compare the majors found against the sections MIGRATION.md carries.
220
+ * Compare the majors found against BOTH records a breaking major owes.
175
221
  *
176
222
  * Every section reaches exactly one ledger outcome: out of scope below the
177
- * floor, out of scope with no BREAKING entries, completed when a heading
178
- * exists, failed when it does not.
223
+ * floor, out of scope with no BREAKING entries, completed when both records
224
+ * name it, failed when either does not.
225
+ *
226
+ * The two are checked together and reported apart. Together, because they are
227
+ * one obligation — "a major that broke something is written down where a
228
+ * consumer looks" — and splitting it across two gates would mean two copies of
229
+ * `findMajorSections` free to disagree about what a major even is. Apart,
230
+ * because a finding that says only "17.0.0 is undocumented" leaves the reader
231
+ * to discover which of two files to open.
179
232
  */
180
233
  export function evaluate(
181
234
  sections: readonly MajorSection[],
182
235
  migration: ReadonlySet<string>,
236
+ index: ReadonlySet<string>,
183
237
  ledger: GateLedger,
184
238
  ): EvaluateResult {
185
239
  const findings: Finding[] = [];
@@ -196,12 +250,24 @@ export function evaluate(
196
250
  continue;
197
251
  }
198
252
  inScope += 1;
199
- if (migration.has(s.version)) {
253
+ const missing: MissingKind[] = [];
254
+ if (!migration.has(s.version)) missing.push('migration');
255
+ if (!index.has(s.version)) missing.push('index');
256
+ if (missing.length === 0) {
200
257
  ledger.complete(target);
201
258
  continue;
202
259
  }
203
- ledger.fail(target, `no docs/MIGRATION.md section for ${s.version}`);
204
- findings.push({ section: s });
260
+ ledger.fail(
261
+ target,
262
+ missing
263
+ .map((k) =>
264
+ k === 'migration'
265
+ ? `no ${MIGRATION_PATH} section for ${s.version}`
266
+ : `no ${BREAKING_INDEX_PATH} row for ${s.version}`,
267
+ )
268
+ .join('; '),
269
+ );
270
+ findings.push({ section: s, missing });
205
271
  }
206
272
  return { findings, sections: [...sections], inScope };
207
273
  }
@@ -220,6 +286,7 @@ export function pendingMajorFinding(
220
286
  target: string,
221
287
  changelogEntry: string,
222
288
  migrationText: string,
289
+ indexText: string,
223
290
  ): string | null {
224
291
  const m = /^(\d+)\.0\.0$/.exec(target.trim());
225
292
  if (m === null) return null;
@@ -227,12 +294,19 @@ export function pendingMajorFinding(
227
294
  const breaking = sections.reduce((n, s) => n + s.breaking, 0);
228
295
  if (breaking === 0) return null;
229
296
  if (Number(m[1]) < FLOOR_MAJOR) return null;
230
- if (migrationVersions(migrationText).has(target)) return null;
297
+ const owed: string[] = [];
298
+ if (!migrationVersions(migrationText).has(target)) {
299
+ owed.push(`${MIGRATION_PATH} has no "## " heading naming ${target}`);
300
+ }
301
+ if (!indexVersions(indexText).has(target)) {
302
+ owed.push(`${BREAKING_INDEX_PATH} has no row naming ${target}`);
303
+ }
304
+ if (owed.length === 0) return null;
231
305
  return (
232
306
  `the ${target} entry carries ${String(breaking)} BREAKING CHANGES entr(y/ies) and ` +
233
- `docs/MIGRATION.md has no "## " heading naming ${target}. Add one before the cut — ` +
234
- 'a section stating that the change asks nothing of a consumer satisfies this, and is ' +
235
- 'the right answer when it is true. What is not acceptable is silence.'
307
+ `${owed.join(', and ')}. Add them before the cut — a section stating that the change ` +
308
+ 'asks nothing of a consumer satisfies the first, and is the right answer when it is ' +
309
+ 'true. What is not acceptable is silence.'
236
310
  );
237
311
  }
238
312
 
@@ -264,14 +338,28 @@ function selfTest(): number {
264
338
  '',
265
339
  ].join('\n');
266
340
 
341
+ const indexTable = (versions: readonly string[]): string =>
342
+ [
343
+ '# Breaking Changes',
344
+ '',
345
+ '## Breaking changes by major',
346
+ '',
347
+ '| Version | Date | What broke | Migration |',
348
+ '|---|---|---|---|',
349
+ ...versions.map((v) => `| **${v}** | 2026-01-01 | something | do a thing |`),
350
+ '',
351
+ ].join('\n');
352
+
267
353
  const fixture = (
268
354
  name: string,
269
355
  changelogText: string,
270
356
  migrationHeadings: readonly string[],
357
+ indexRows: readonly string[] = [],
271
358
  ): number => {
272
359
  const dir = path.join(root, name);
273
360
  fs.mkdirSync(path.join(dir, 'docs'), { recursive: true });
274
361
  fs.writeFileSync(path.join(dir, 'CHANGELOG.md'), changelogText, 'utf8');
362
+ fs.writeFileSync(path.join(dir, BREAKING_INDEX_PATH), indexTable(indexRows), 'utf8');
275
363
  fs.writeFileSync(
276
364
  path.join(dir, 'docs', 'MIGRATION.md'),
277
365
  ['# Migration Guide', '', ...migrationHeadings.flatMap((h) => [h, '', 'body', ''])].join(
@@ -293,28 +381,48 @@ function selfTest(): number {
293
381
  // one half proves the refusal fires, the other that the heading is
294
382
  // what clears it, so neither can be satisfied by a gate that always
295
383
  // reds or always passes.
296
- name: 'the same major passes once the heading exists',
384
+ name: 'the same major passes once the heading and the index row exist',
297
385
  expect: 'accept',
298
386
  run: () =>
299
- fixture('present', changelog('17.0.0', ['**x:** drop y']), [
300
- '## 17.0.0 — what to do',
301
- ]),
387
+ fixture(
388
+ 'present',
389
+ changelog('17.0.0', ['**x:** drop y']),
390
+ ['## 17.0.0 — what to do'],
391
+ ['17.0.0'],
392
+ ),
302
393
  },
303
394
  {
304
395
  name: 'a heading naming a DIFFERENT major does not satisfy the requirement',
305
396
  expect: 'reject',
306
397
  run: () =>
307
- fixture('wrong-version', changelog('17.0.0', ['**x:** drop y']), [
308
- '## 16.0.0 — what to do',
398
+ fixture(
399
+ 'wrong-version',
400
+ changelog('17.0.0', ['**x:** drop y']),
401
+ ['## 16.0.0 — what to do'],
402
+ ['17.0.0'],
403
+ ),
404
+ },
405
+ {
406
+ // The index half of the same pair. Section present, row absent —
407
+ // so this case can only pass by checking the index, and the
408
+ // 'present' case above can only pass by accepting a correct one.
409
+ name: 'a major with a migration section but no index row is refused',
410
+ expect: 'reject',
411
+ run: () =>
412
+ fixture('no-index-row', changelog('17.0.0', ['**x:** drop y']), [
413
+ '## 17.0.0 — what to do',
309
414
  ]),
310
415
  },
311
416
  {
312
417
  name: 'an arrow-form heading naming the version satisfies it',
313
418
  expect: 'accept',
314
419
  run: () =>
315
- fixture('arrow', changelog('17.0.0', ['**x:** drop y']), [
316
- '## 16.x → 17.0.0 — what to do',
317
- ]),
420
+ fixture(
421
+ 'arrow',
422
+ changelog('17.0.0', ['**x:** drop y']),
423
+ ['## 16.x → 17.0.0 — what to do'],
424
+ ['17.0.0'],
425
+ ),
318
426
  },
319
427
  {
320
428
  name: 'a major BELOW the floor is forgiven',
@@ -336,6 +444,10 @@ function selfTest(): number {
336
444
  const dir = path.join(root, 'no-changelog');
337
445
  fs.mkdirSync(path.join(dir, 'docs'), { recursive: true });
338
446
  fs.writeFileSync(path.join(dir, 'docs', 'MIGRATION.md'), '# Migration Guide\n', 'utf8');
447
+ // The index IS present, so the refusal below can only be the
448
+ // dead-scan-root one. Without it this case would reject on a
449
+ // missing file and stop testing what it is named for.
450
+ fs.writeFileSync(path.join(dir, BREAKING_INDEX_PATH), indexTable([]), 'utf8');
339
451
  return runGateCli(repo, script, ['--root', dir, '--quiet'], repo);
340
452
  },
341
453
  },
@@ -381,6 +493,15 @@ export function main(argv: readonly string[]): number {
381
493
  return 1;
382
494
  }
383
495
  const migration = migrationVersions(fs.readFileSync(migrationFile, 'utf-8'));
496
+ // An absent index reds rather than skipping the index half. A missing
497
+ // comparand that silently narrows the comparison is how a gate reports
498
+ // "nothing wrong" about a question it stopped asking.
499
+ const indexFile = path.join(root, BREAKING_INDEX_PATH);
500
+ if (!fs.existsSync(indexFile)) {
501
+ process.stderr.write(`❌ ${GATE}: ${BREAKING_INDEX_PATH} not found under ${root}\n`);
502
+ return 1;
503
+ }
504
+ const index = indexVersions(fs.readFileSync(indexFile, 'utf-8'));
384
505
 
385
506
  const sources = changelogSources(root);
386
507
  const sections: MajorSection[] = [];
@@ -389,7 +510,7 @@ export function main(argv: readonly string[]): number {
389
510
  }
390
511
 
391
512
  const ledger = new GateLedger(GATE);
392
- const result = evaluate(sections, migration, ledger);
513
+ const result = evaluate(sections, migration, index, ledger);
393
514
  const tally = ledger.finalize();
394
515
 
395
516
  try {
@@ -400,7 +521,7 @@ export function main(argv: readonly string[]): number {
400
521
  gate: GATE,
401
522
  scanned: tally.planned,
402
523
  units: 'major changelog section(s)',
403
- roots: [CHANGELOG_PATH, ARCHIVE_DIR],
524
+ roots: [CHANGELOG_PATH, ARCHIVE_DIR, MIGRATION_PATH, BREAKING_INDEX_PATH],
404
525
  });
405
526
  } catch (exc) {
406
527
  if (exc instanceof DeadScopeError) {
@@ -412,13 +533,22 @@ export function main(argv: readonly string[]): number {
412
533
 
413
534
  if (result.findings.length > 0) {
414
535
  for (const f of result.findings) {
536
+ const owed = f.missing
537
+ .map((k) =>
538
+ k === 'migration'
539
+ ? `${MIGRATION_PATH} carries no "## " heading naming it`
540
+ : `${BREAKING_INDEX_PATH} carries no row naming it`,
541
+ )
542
+ .join(', and ');
415
543
  process.stderr.write(
416
544
  `❌ ${GATE}: ${f.section.version} ships ${String(f.section.breaking)} BREAKING ` +
417
545
  `CHANGES entr(y/ies) (${f.section.source}:${String(f.section.line)}) and ` +
418
- `${MIGRATION_PATH} carries no "## " heading naming it.\n` +
419
- ` Add a section for ${f.section.version}. A section stating that the change\n` +
420
- ' asks nothing of a consumer satisfies this and is the right answer when it\n' +
421
- ' is true — the requirement is a stated answer, never a procedure.\n',
546
+ `${owed}.\n` +
547
+ ` Add what is missing for ${f.section.version}. A migration section stating\n` +
548
+ ' that the change asks nothing of a consumer satisfies that half and is the\n' +
549
+ ' right answer when it is true — the requirement is a stated answer, never a\n' +
550
+ ` procedure. The ${BREAKING_INDEX_PATH} row is one line in the by-major table,\n` +
551
+ ' linking the changelog section it came from.\n',
422
552
  );
423
553
  }
424
554
  return 1;
@@ -429,7 +559,7 @@ export function main(argv: readonly string[]): number {
429
559
  process.stdout.write(
430
560
  `✅ ${GATE}: ${String(tally.planned)} major section(s) read, ` +
431
561
  `${String(result.inScope)} in scope (major >= ${String(FLOOR_MAJOR)} with BREAKING ` +
432
- 'CHANGES), each with a migration section' +
562
+ 'CHANGES), each with a migration section and an index row' +
433
563
  (result.inScope === 0
434
564
  ? ' — NONE in scope this run, so no comparison ran. Green here means\n' +
435
565
  ' "nothing to compare", not "the comparison passed".\n'
@@ -34,10 +34,19 @@
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.
42
51
  *
43
52
  * ## Where the `requires` graph is read from
@@ -115,6 +124,47 @@ const LINK_RE = /\[[^\]]*\]\(([^)#?]+)(?:[#?][^)]*)?\)/g;
115
124
  /** A pack every install carries — a link into it can never dangle. */
116
125
  const ALWAYS_INSTALLED = 'core';
117
126
 
127
+ /**
128
+ * Packs every projection carries, so a link INTO one can never dangle.
129
+ *
130
+ * `core` is the hard-coded floor. Beyond it, `always_on: true` in the pack
131
+ * vocabulary means exactly this: `config/packs.resolve_active_packs` seeds the
132
+ * active set with every always-on pack BEFORE expanding the selected profile's
133
+ * `requires` closure, and `docs/contracts/capability-packs.md` § Always-on
134
+ * packs states the pack "is never gated by the selected profile, workspace, or
135
+ * pack set, and it cannot be deselected".
136
+ *
137
+ * Reading only `core` was the same class of defect this file's header already
138
+ * records for the direct-vs-transitive `requires` comparison: the gate reported
139
+ * a violation for a target the resolver provably does install. The direction is
140
+ * one-way — a link OUT of an always-on pack into a gated one still dangles and
141
+ * is still a violation.
142
+ */
143
+ function _always_installed_packs(): Set<string> {
144
+ const out = new Set<string>([ALWAYS_INSTALLED]);
145
+ if (_exists(VOCAB)) {
146
+ const vocab = parseYaml(fs.readFileSync(VOCAB, 'utf-8'), { version: '1.1' });
147
+ if (Array.isArray(vocab)) {
148
+ for (const entry of vocab) {
149
+ if (entry !== null && typeof entry === 'object' && !Array.isArray(entry)) {
150
+ const e = entry as Record<string, unknown>;
151
+ if (typeof e['id'] === 'string' && e['always_on'] === true) {
152
+ out.add(e['id']);
153
+ }
154
+ }
155
+ }
156
+ }
157
+ }
158
+ for (const dir of _pack_home_dirs()) {
159
+ const meta = _load_pack_meta(dir);
160
+ if (meta['always_on'] === true) {
161
+ const id = typeof meta['id'] === 'string' ? meta['id'] : path.basename(dir);
162
+ out.add(id);
163
+ }
164
+ }
165
+ return out;
166
+ }
167
+
118
168
  type ViolationKind =
119
169
  /** Link crosses into a pack the source pack does not require. */
120
170
  | 'cross-pack'
@@ -479,11 +529,16 @@ function _scan_file(p: string): string[] {
479
529
  return out;
480
530
  }
481
531
 
482
- function _is_allowed(source_pack: string, target_pack: string, requires: string[]): boolean {
532
+ function _is_allowed(
533
+ source_pack: string,
534
+ target_pack: string,
535
+ requires: string[],
536
+ always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
537
+ ): boolean {
483
538
  if (source_pack === target_pack) {
484
539
  return true;
485
540
  }
486
- if (target_pack === ALWAYS_INSTALLED) {
541
+ if (always_installed.has(target_pack)) {
487
542
  return true;
488
543
  }
489
544
  return (requires || []).includes(target_pack);
@@ -501,10 +556,11 @@ function _link_allowed(
501
556
  source_packs: readonly string[],
502
557
  target_packs: readonly string[],
503
558
  closureOf: (pack: string) => Set<string>,
559
+ always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
504
560
  ): boolean {
505
561
  return source_packs.every((s) => {
506
562
  const reach = [...closureOf(s)];
507
- return target_packs.some((t) => _is_allowed(s, t, reach));
563
+ return target_packs.some((t) => _is_allowed(s, t, reach, always_installed));
508
564
  });
509
565
  }
510
566
 
@@ -597,6 +653,7 @@ function main(argv?: readonly string[]): number {
597
653
  }
598
654
 
599
655
  const pack_requires = _pack_requires();
656
+ const always_installed = _always_installed_packs();
600
657
  const closureCache = new Map<string, Set<string>>();
601
658
  const closureOf = (pack: string): Set<string> => {
602
659
  let c = closureCache.get(pack);
@@ -635,7 +692,7 @@ function main(argv?: readonly string[]): number {
635
692
  if (target_packs === undefined) {
636
693
  continue; // docs/, scripts/, root files, unassigned — not pack-scoped
637
694
  }
638
- if (_link_allowed(src_packs, target_packs, closureOf)) {
695
+ if (_link_allowed(src_packs, target_packs, closureOf, always_installed)) {
639
696
  continue;
640
697
  }
641
698
  violations.push({
@@ -743,6 +800,7 @@ export {
743
800
  _build_artefact_index,
744
801
  _resolve_link,
745
802
  _scan_file,
803
+ _always_installed_packs,
746
804
  _is_allowed,
747
805
  _link_allowed,
748
806
  _load_pack_meta,
@@ -3,7 +3,8 @@
3
3
  * Hard-gate linter for the roadmap `## Blockers` contract
4
4
  * (`templates/roadmaps.md` rule 20 / `roadmap-ci-steps-policy` siblings).
5
5
  *
6
- * Validates, for every active roadmap under `agents/roadmaps/*.md`:
6
+ * Validates, for every active roadmap and every parked idea one directory
7
+ * down in `stubs/`:
7
8
  *
8
9
  * 1. Every `### blocker: <id>` entry declares all five required fields
9
10
  * (Status, Owner, Blocks, What to do, Resolved when).
@@ -22,11 +23,14 @@
22
23
  * road-to-asked-not-parked exists to stop; without this field a marker
23
24
  * cannot distinguish a declined decision from an unoffered one.
24
25
  *
25
- * HARD, not ratcheted, and it can be: no active roadmap carries a real
26
- * checkbox annotation today, so on the day it ships the rule fires on
27
- * nothing — the same "no backlog to grandfather" argument the `Class:`
28
- * contract above makes. `later/` and `archive/` are outside this gate's
29
- * glob and are untouched by it.
26
+ * HARD, not ratcheted, and it can be: no file in scope carries a real
27
+ * checkbox annotation pointing at a blocker today, so on the day it ships
28
+ * the rule fires on nothing — the same "no backlog to grandfather"
29
+ * argument the `Class:` contract above makes. Re-measured when `stubs/`
30
+ * entered scope on 2026-09-28: 7 stubs carry checkboxes and 0 of them
31
+ * carry a `blocked-by:` marker, so the rule stays latent there too.
32
+ * `later/`, `archive/` and `skipped/` are outside this gate's glob and
33
+ * are untouched by it; `stubs/` is inside it — see § SCOPE.
30
34
  *
31
35
  * 5. An entry that declares `- **Ownership:**` declares one of the three
32
36
  * OWNER-OWNED classes (`product-owned`, `business-owned`,
@@ -41,10 +45,49 @@
41
45
  * field, so on the day it ships no entry in the tree declares one and the
42
46
  * rule fires on nothing.
43
47
  *
48
+ * SCOPE — the active tree plus `stubs/`, and deliberately nothing else.
49
+ *
50
+ * Widened from the active tree alone by an owner ruling on 2026-09-28. Before
51
+ * it, a stub's hold was unreachable by every blocker gate: a parked idea is
52
+ * where a hold sits LONGEST, so excluding it exempted exactly the entries most
53
+ * likely to rot. The rejected alternative was to keep the scope and reword the
54
+ * acceptance criterion that named this gate — refused because a criterion
55
+ * edited to match what was achieved stops being an acceptance test.
56
+ *
57
+ * Measured on the tree the widening shipped against: 121 files under `stubs/`
58
+ * (120 stubs plus the directory README), of which 6 carry a `### blocker:`
59
+ * heading and 4 declare one open inside a `## Blockers` section. Zero hard
60
+ * violations, zero additions to the decidability ratchet, zero new
61
+ * active/archived overlaps. So it lands on nothing — the same "no backlog to
62
+ * grandfather" argument the `Class:` and `Ownership:` contracts make.
63
+ *
64
+ * REACH, stated honestly, because the obvious reading of the paragraph above
65
+ * is wrong: this does NOT hold every future stub blocker to the contract. Both
66
+ * scanners require the entry to sit under a `## Blockers` heading, and 2 of
67
+ * today's 6 put it under `## State` instead — so a third of the population is
68
+ * in the glob and still unread. Stub headings are free-form, unlike the
69
+ * template-driven roadmaps this gate was written for, so that is the likely
70
+ * shape rather than an edge case. Widening the glob fixes WHERE the gate looks
71
+ * and not WHAT it can parse; the second half is the sibling defect recorded in
72
+ * `stubs/road-to-blocker-parse-visibility.md`, and it is untouched here.
73
+ *
74
+ * `later/`, `archive/` and `skipped/` stay OUT, and the reason is not symmetry:
75
+ * those record decisions already taken (parked, closed, dropped), so a blocker
76
+ * left unresolved there is history rather than debt. A stub records a decision
77
+ * still to take. The polarity is pinned in both directions by
78
+ * `tests/scripts/lint_roadmap_blockers.test.ts` § the scanned scope, so
79
+ * widening further cannot happen by accident.
80
+ *
81
+ * One consequence worth naming rather than discovering: `_archiveOverlap`
82
+ * defaults its ACTIVE corpus to this glob, so a stub declaring a blocker open
83
+ * that an archived roadmap also declares open now fails. That is the same
84
+ * self-contradiction the assertion already caught one directory up, and it
85
+ * measured 0 on the widening tree.
86
+ *
44
87
  * Fenced code blocks are stripped before scanning so a roadmap that shows
45
88
  * the `## Blockers` shape as a documentation example is not flagged.
46
89
  *
47
- * Exit codes: 0 = clean / no active roadmaps, 1 = violations.
90
+ * Exit codes: 0 = clean / nothing in scope, 1 = violations.
48
91
  */
49
92
 
50
93
  import * as fs from 'node:fs';
@@ -58,7 +101,14 @@ const _HERE = fileURLToPath(import.meta.url);
58
101
  const QUIET = process.argv.slice(2).includes('--quiet');
59
102
 
60
103
  const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
61
- const ROADMAP_GLOB = 'agents/roadmaps/*.md';
104
+ /**
105
+ * The scanned scope, for display. Two plain globs rather than one brace
106
+ * expression: nothing globs with this string, and a `{,stubs/}` empty
107
+ * alternative is bash-only syntax that would mislead anyone who tried.
108
+ */
109
+ const ROADMAP_GLOB = 'agents/roadmaps/*.md + agents/roadmaps/stubs/*.md';
110
+ /** The one subdirectory inside the glob. See § SCOPE for why only this one. */
111
+ const SCANNED_SUBDIRS: readonly string[] = ['stubs'];
62
112
 
63
113
  const FENCED_CODE_RE = /^[ \t]*```[^\n]*\n[\s\S]*?^[ \t]*```[ \t]*$/gm;
64
114
  const BLOCKERS_SECTION_RE = /^##[ \t]+Blockers[ \t]*$/im;
@@ -370,13 +420,14 @@ function _scanBoth(rawText: string): ScanResult {
370
420
  return { hard: violations, decidability };
371
421
  }
372
422
 
373
- /** Sorted `agents/roadmaps/*.md` (non-recursive — active roadmaps only). */
374
- function _globRoadmaps(): string[] {
375
- const dir = path.join(REPO_ROOT, 'agents', 'roadmaps');
423
+ /** Sorted `*.md` directly inside `dir` — never recursive. */
424
+ function _globFlat(dir: string): string[] {
376
425
  let entries: fs.Dirent[];
377
426
  try {
378
427
  entries = fs.readdirSync(dir, { withFileTypes: true });
379
428
  } catch {
429
+ // A missing directory is not an error: `stubs/` is optional, and the
430
+ // dead-scope assertion in `main` is what catches a MOVED root.
380
431
  return [];
381
432
  }
382
433
  const out: string[] = [];
@@ -388,6 +439,21 @@ function _globRoadmaps(): string[] {
388
439
  return out.sort();
389
440
  }
390
441
 
442
+ /**
443
+ * The files this gate judges: active roadmaps, plus `stubs/`. See § SCOPE.
444
+ *
445
+ * Takes its root so the scope can be driven from a fixture tree. Asserting the
446
+ * rule against the real tree would only restate today's file list; the test
447
+ * pins which DIRECTORIES are in and which are out, in both directions.
448
+ */
449
+ function _globRoadmaps(roadmapRoot: string = path.join(REPO_ROOT, 'agents', 'roadmaps')): string[] {
450
+ const out = _globFlat(roadmapRoot);
451
+ for (const sub of SCANNED_SUBDIRS) {
452
+ out.push(..._globFlat(path.join(roadmapRoot, sub)));
453
+ }
454
+ return out;
455
+ }
456
+
391
457
  function _relPosix(target: string, root: string): string {
392
458
  return path.relative(root, target).split(path.sep).join('/');
393
459
  }
@@ -561,7 +627,7 @@ function main(): number {
561
627
  const roadmaps = _globRoadmaps();
562
628
  if (roadmaps.length === 0) {
563
629
  if (!QUIET) {
564
- process.stdout.write(`✅ no active roadmaps under ${ROADMAP_GLOB}\n`);
630
+ process.stdout.write(`✅ nothing in scope under ${ROADMAP_GLOB}\n`);
565
631
  }
566
632
  return 0;
567
633
  }