@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
@@ -24,6 +24,7 @@ import * as path from 'node:path';
24
24
  import { REPO_ROOT } from '../release_env.js';
25
25
  import { die, run, type RunResult } from '../release_publication.js';
26
26
  import {
27
+ BREAKING_INDEX_PATH,
27
28
  MIGRATION_PATH as MAJOR_MIGRATION_PATH,
28
29
  pendingMajorFinding,
29
30
  } from '../lint_major_migration_sections.js';
@@ -148,8 +149,15 @@ export function assert_scheduled_deprecations_clear(
148
149
  * real run will refuse and returns, because `--dry-run exits 0` is a contract
149
150
  * this file's own tests assert.
150
151
  *
152
+ * A major owes TWO records and this seam reads both: the migration section and
153
+ * the by-major row in `BREAKING_CHANGES.md`. Checking only the first at cut
154
+ * time while the lint checks both would let a cut create the exact state the
155
+ * lint then reds `main` over — the gate arriving one merge too late, which is
156
+ * the shape `pendingMajorFinding` exists to avoid in the first place.
157
+ *
151
158
  * @param migrationReader Seam for the file read, so a test can drive the
152
159
  * refusal without mutating a tracked file.
160
+ * @param indexReader The same seam for the breaking-changes index.
153
161
  */
154
162
  export function assert_major_migration_section(
155
163
  target: string,
@@ -157,18 +165,23 @@ export function assert_major_migration_section(
157
165
  opts: { previewOnly?: boolean } = {},
158
166
  migrationReader: () => string = () =>
159
167
  fs.readFileSync(path.join(REPO_ROOT, MAJOR_MIGRATION_PATH), 'utf-8'),
168
+ indexReader: () => string = () =>
169
+ fs.readFileSync(path.join(REPO_ROOT, BREAKING_INDEX_PATH), 'utf-8'),
160
170
  ): void {
161
171
  let migration: string;
172
+ let index: string;
162
173
  try {
163
174
  migration = migrationReader();
175
+ index = indexReader();
164
176
  } catch (exc) {
165
177
  die(
166
- `refusing the ${target} cut: cannot read ${MAJOR_MIGRATION_PATH} ` +
178
+ `refusing the ${target} cut: cannot read ${MAJOR_MIGRATION_PATH} or ` +
179
+ `${BREAKING_INDEX_PATH} ` +
167
180
  `(${exc instanceof Error ? exc.message : String(exc)}). That is an environment ` +
168
181
  'failure, not a finding — fix the checkout, then re-run.',
169
182
  );
170
183
  }
171
- const finding = pendingMajorFinding(target, changelog_entry, migration);
184
+ const finding = pendingMajorFinding(target, changelog_entry, migration, index);
172
185
  if (finding === null) {
173
186
  return;
174
187
  }
@@ -180,5 +193,8 @@ export function assert_major_migration_section(
180
193
  );
181
194
  return;
182
195
  }
183
- die(`refusing the ${target} cut: ${MAJOR_MIGRATION_PATH} has no section for ${target}.`);
196
+ die(
197
+ `refusing the ${target} cut: ${MAJOR_MIGRATION_PATH} or ${BREAKING_INDEX_PATH} ` +
198
+ `does not name ${target}.`,
199
+ );
184
200
  }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * The reserved-name sweep over flat Claude Code command files.
3
+ *
4
+ * A flat command whose slug shadows a Claude Code built-in never ships on the
5
+ * claude-code anchor — the suite complements the host, it does not overlay its
6
+ * built-ins. The sweep that enforces this used to delete EVERY builtin-named
7
+ * `.md` in the anchor's `commands/` directory, including one another agent
8
+ * package or the consumer had put there. The consumer's own `/review` command
9
+ * disappeared at install time with no message, because the sweep's only
10
+ * question was the filename.
11
+ *
12
+ * The question it asks now is ownership: a file is removed when this package
13
+ * wrote it — the current deploy's own written set, or a path a previous
14
+ * install recorded in the installed-tools manifest. Anything else is FOREIGN:
15
+ * it stays on disk and is reported, so the consumer learns that a built-in
16
+ * name is shadowed by someone and can decide, rather than finding their file
17
+ * gone.
18
+ *
19
+ * Both halves of the sweep's original purpose survive: ours never ships under
20
+ * a reserved name, and the suite still never overlays a built-in with its own
21
+ * file. What it no longer does is enforce that on a file that is not its own.
22
+ */
23
+
24
+ import * as fs from 'node:fs';
25
+ import * as path from 'node:path';
26
+
27
+ export interface ReservedSweepResult {
28
+ /** Slugs of OUR files removed because the name is a host built-in. */
29
+ reserved: string[];
30
+ /** Slugs left in place because nothing proves this package wrote them. */
31
+ foreign: string[];
32
+ }
33
+
34
+ /**
35
+ * Remove our builtin-named flat commands from `commandsDir`; keep foreign ones.
36
+ *
37
+ * Both ownership sets are anchor-relative, exactly as the deploy inventory
38
+ * records them. `currentFiles` is this deploy's written set — the live half,
39
+ * and the only one that exists on a first install. `recordedFiles` is what a
40
+ * previous deploy recorded under the same anchor, so a builtin-named file of
41
+ * ours left behind by an older version is still reaped rather than becoming
42
+ * permanently unprovable. A removed entry is dropped from `currentFiles` so
43
+ * the inventory record stays consistent with the tree, exactly as before.
44
+ */
45
+ export function sweepReservedNames(
46
+ commandsDir: string,
47
+ currentFiles: Set<string>,
48
+ isBuiltinName: (slug: string) => boolean,
49
+ recordedFiles: ReadonlySet<string>,
50
+ ): ReservedSweepResult {
51
+ const reserved: string[] = [];
52
+ const foreign: string[] = [];
53
+ let entries: string[] = [];
54
+ try {
55
+ entries = fs.readdirSync(commandsDir).filter((f) => f.endsWith('.md'));
56
+ } catch {
57
+ return { reserved, foreign };
58
+ }
59
+ for (const fname of entries.sort()) {
60
+ const slug = fname.slice(0, -'.md'.length);
61
+ if (!isBuiltinName(slug)) continue;
62
+ const rel = `commands/${fname}`;
63
+ const ours = currentFiles.has(rel) || recordedFiles.has(rel);
64
+ if (!ours) {
65
+ foreign.push(slug);
66
+ continue;
67
+ }
68
+ fs.rmSync(path.join(commandsDir, fname), { force: true });
69
+ currentFiles.delete(rel);
70
+ reserved.push(slug);
71
+ }
72
+ return { reserved, foreign };
73
+ }
@@ -16,26 +16,58 @@
16
16
  * Codepoint classes are shared with `lint_hidden_unicode` (one source of truth
17
17
  * for what counts as a hidden-instruction vector).
18
18
  *
19
- * WHERE IT ACTUALLY RUNS — measured end-to-end, not asserted. Keep this list
20
- * honest: an earlier version of this header named surfaces by intent, and the
21
- * legacy-envelope gap below went unnoticed for exactly that reason. Every
22
- * claim here is backed by a probe row in
23
- * `agents/evidence/reports/sanitize-floor-wiring.md`:
19
+ * WHERE IT ACTUALLY RUNS — read the table, which is GENERATED:
24
20
  *
25
- * - `retrieve_v1()` — yes (`memory_lookup.ts` calls `sanitize_entry`)
26
- * - `memory_get_v1()` — yes (same)
27
- * - MCP `memory_lookup` / `memory_get` tools — inherited from the two above
28
- * - `retrieve()` / `retrieve_with_meta()` — yes, since the S0.0 wiring fix;
29
- * before it they emitted every vector intact, and so did the CLI default
30
- * (`--envelope legacy`), which is the path the rules document
31
- * - inter-agent channels (`ai_team` / `ai_council` model replies) — the
32
- * inbound parse choke point only; the subagent boundary itself is a HOST
33
- * primitive this package cannot reach (see the report, § S0.0b)
21
+ * docs/contracts/retrieval-read-surfaces.md
34
22
  *
35
- * Anything not on that list is uncovered. Do not widen the list without a
36
- * probe row to back it.
23
+ * This header used to carry that list inline, and the list was wrong in BOTH
24
+ * directions: a path that reaches the outside world and IS sanitized was
25
+ * absent from it, and two paths carrying fetched bytes toward a model-facing
26
+ * surface were neither listed nor covered. An earlier version had already
27
+ * failed the same way — it named surfaces by intent, and the legacy-envelope
28
+ * gap went unnoticed for exactly that reason. Twice is a property of the
29
+ * mechanism, not of the entries, which is why the list is now derived from the
30
+ * import graph by `check_read_surface_coverage` and this header points at it
31
+ * instead of copying it. A divergence between the two FAILS that gate; two
32
+ * copies is how it went stale.
33
+ *
34
+ * Anything absent from the table is uncovered, and a module the generator
35
+ * cannot classify appears there as an `unclassified` ROW rather than being
36
+ * omitted — a missing row would read as no surface at all.
37
+ *
38
+ * One boundary the table cannot move: the subagent boundary itself is a HOST
39
+ * primitive this package cannot reach, so the inter-agent channels are covered
40
+ * at the inbound parse choke point and nowhere else.
41
+ *
42
+ * loss_class: ephemeral-lossy
43
+ *
44
+ * `sanitize_text` drops hidden-instruction codepoints, control-char noise and
45
+ * invisible fillers, and caps the result at MAX_FIELD_CHARS. None of that is
46
+ * reconstructible from the output, and for the dropped vectors the
47
+ * unrecoverability IS the guarantee — a retrieval path that could hand back
48
+ * the vector it stripped would not be a floor. So the class is
49
+ * `ephemeral-lossy` for the module, even though `sanitize_markup` below
50
+ * returns structured removals for the layer it composes: a class names what a
51
+ * caller can recover from the output, and `sanitize_text` returns a string.
52
+ *
53
+ * THE STRUCTURAL LAYER IS A SEPARATE MODULE. Everything below is a CODEPOINT
54
+ * floor. Fetched markup also hides content STRUCTURALLY — an HTML comment, a
55
+ * `<template>` block, a `style="display:none"` span — which no codepoint
56
+ * predicate can see. That class is covered by `_lib/structural_hiding.ts`,
57
+ * composed with this floor by `sanitize_markup` below, and it is covered for
58
+ * fetched MARKUP only: a caller holding plain text needs nothing from it.
59
+ *
60
+ * WHAT THAT LAYER STILL DOES NOT SEE is a register in its own file —
61
+ * `STRUCTURAL_HIDING_GAPS` — and every surface claiming the coverage cites the
62
+ * register alongside the claim, because a detector cited without its gaps is
63
+ * how the claim becomes a false green. No recall or coverage percentage is
64
+ * published for it anywhere; a rate needs a frozen corpus and none exists.
65
+ * `aria-hidden` is deliberately NOT one of its channels
66
+ * (`STRUCTURAL_HIDING_NON_CHANNELS` says why).
37
67
  */
38
68
  import { _classify } from '../lint_hidden_unicode.js';
69
+ import { strip_structural_hiding } from './structural_hiding.js';
70
+ import type { StructuralRemoval } from './structural_hiding.js';
39
71
  import { TOKEN_RE, classifyToken } from './confusables.js';
40
72
 
41
73
  /** Hard per-field length cap — bounds a runaway/adversarial body. */
@@ -85,6 +117,35 @@ export function sanitize_text(s: string): string {
85
117
  return out.length > MAX_FIELD_CHARS ? out.slice(0, MAX_FIELD_CHARS) : out;
86
118
  }
87
119
 
120
+ /**
121
+ * The fetched-markup floor: structural pre-pass, then the codepoint floor.
122
+ *
123
+ * ORDER IS LOAD-BEARING. The structural pass runs FIRST, because a codepoint
124
+ * floor applied first would sanitize text that is about to be discarded and,
125
+ * worse, would leave a hidden subtree looking clean. Running it second means
126
+ * every byte that survives the structural pass still clears the codepoint
127
+ * floor — including the text that was only reachable once markup was removed.
128
+ *
129
+ * Use this for fetched MARKUP. For plain text `sanitize_text` is the whole
130
+ * floor and this adds nothing but a parse.
131
+ *
132
+ * The removals are RETURNED, not logged and not swallowed: a caller debugging
133
+ * a corrupted result needs to know what went and where it was. See the removal
134
+ * policy in `structural_hiding.ts`.
135
+ */
136
+ export function sanitize_markup(markup: string): {
137
+ text: string;
138
+ removals: readonly StructuralRemoval[];
139
+ truncated: boolean;
140
+ } {
141
+ const stripped = strip_structural_hiding(markup);
142
+ return {
143
+ text: sanitize_text(stripped.text),
144
+ removals: stripped.removals,
145
+ truncated: stripped.truncated,
146
+ };
147
+ }
148
+
88
149
  /**
89
150
  * Report the INVISIBLE layer without removing it.
90
151
  *
@@ -0,0 +1,134 @@
1
+ /**
2
+ * How much of a release the self-review actually read, stated where the record
3
+ * is read.
4
+ *
5
+ * `self_review_gate` writes a `coverage` block — `{chunks, filesReviewed,
6
+ * filesTotal, unreviewed[]}` — into the findings artifact, `--ingest` carries it
7
+ * into the per-release ledger named by {@link LEDGER_DIR}, and from there NOBODY
8
+ * reads `filesReviewed` back. The 16.2.0 ledger records `filesReviewed: 65,
9
+ * filesTotal: 678`: the review saw under a tenth of the change. Every consumer
10
+ * of that record — the disposition gate's success line, the release-highlights
11
+ * gate, a human opening the file — saw output that said nothing about it.
12
+ *
13
+ * A finding count over 9.6 % of a diff and the same count over all of it are
14
+ * different claims, and the record spelled them identically.
15
+ *
16
+ * A LABEL, NEVER A FLOOR, and the distinction is the decision.
17
+ *
18
+ * Nothing here refuses. `coverageLabel` returns a string or `null`; no caller
19
+ * turns it into an exit code, and none may. Raising what a review reads costs
20
+ * one more paid model request per chunk per cut, which is a spend decision
21
+ * belonging to the owner. A gate that failed a cut on partial coverage would
22
+ * force that decision through the back door — the operator would either pay or
23
+ * be unable to release — which is exactly the move the roadmap's decision D1
24
+ * records as rejected.
25
+ *
26
+ * The honest cost of that choice, stated rather than left to be discovered: a
27
+ * release can ship with 9.6 % coverage and this module will only have said so.
28
+ * Saying so is the whole claim.
29
+ *
30
+ * It lives in its own module because two consumers read it — `check_finding_dispositions` on the ledger and
31
+ * `check_release_highlights` beside the Known-limitations field — and a label
32
+ * the two spell differently is a label a reader cannot compare across the two
33
+ * places they meet it. One definition is also the seam the unit tests use, so
34
+ * the arithmetic is checked without either CLI in the loop.
35
+ */
36
+ import * as fs from 'node:fs';
37
+ import * as path from 'node:path';
38
+
39
+ /** Where the per-release ledgers live, relative to the repository root. */
40
+ export const LEDGER_DIR = path.join('agents', 'evidence', 'release-findings');
41
+
42
+ /**
43
+ * The coverage block as the gate writes it. Every field optional: this type
44
+ * describes an artifact read back off disk, which may be from an older writer
45
+ * or hand-edited, so the reader's job is to decide whether it can answer rather
46
+ * than to assume it can.
47
+ */
48
+ export interface ReviewCoverage {
49
+ readonly chunks?: unknown;
50
+ readonly filesReviewed?: unknown;
51
+ readonly filesTotal?: unknown;
52
+ readonly unreviewed?: unknown;
53
+ }
54
+
55
+ function _finite(v: unknown): number | null {
56
+ return typeof v === 'number' && Number.isFinite(v) ? v : null;
57
+ }
58
+
59
+ /**
60
+ * The one sentence both gates print, or `null` when there is nothing to say.
61
+ *
62
+ * `null` covers three cases deliberately collapsed into one, because they lead
63
+ * to the same output: full coverage (nothing to warn about), an absent block (an
64
+ * older ledger, written before the gate recorded coverage), and a malformed one
65
+ * (a string where a number belongs, a zero total). A reader who sees no label
66
+ * learns "this record makes no partial-coverage claim" — which is true of all
67
+ * three — and never a fabricated percentage derived from a field that was not
68
+ * a number.
69
+ *
70
+ * `filesTotal === 0` is `null` rather than `0 of 0 (partial)`: a change set with
71
+ * no files was fully read by any definition, and dividing by it says nothing.
72
+ */
73
+ export function coverageLabel(coverage: unknown): string | null {
74
+ if (coverage === null || typeof coverage !== 'object') {
75
+ return null;
76
+ }
77
+ const c = coverage as ReviewCoverage;
78
+ const reviewed = _finite(c.filesReviewed);
79
+ const total = _finite(c.filesTotal);
80
+ if (reviewed === null || total === null || total <= 0 || reviewed >= total) {
81
+ return null;
82
+ }
83
+ return `self-review read ${String(reviewed)} of ${String(total)} changed files (partial)`;
84
+ }
85
+
86
+ /**
87
+ * The `coverage` block of a committed ledger, or `undefined`.
88
+ *
89
+ * Never throws. A missing ledger is the normal state of an in-flight release and
90
+ * a corrupt one is already the business of the gate that parses it properly —
91
+ * a label is not the place to discover either, and a reader that threw here
92
+ * would turn an informational line into a crash on a release branch.
93
+ */
94
+ export function readLedgerCoverage(root: string, release: string): unknown {
95
+ const file = path.join(root, LEDGER_DIR, `${release}.json`);
96
+ try {
97
+ const parsed: unknown = JSON.parse(fs.readFileSync(file, 'utf-8'));
98
+ if (parsed === null || typeof parsed !== 'object') {
99
+ return undefined;
100
+ }
101
+ return (parsed as Record<string, unknown>)['coverage'];
102
+ } catch {
103
+ return undefined;
104
+ }
105
+ }
106
+
107
+ /** `coverageLabel` over the committed ledger for `release`. */
108
+ export function ledgerCoverageLabel(root: string, release: string): string | null {
109
+ return coverageLabel(readLedgerCoverage(root, release));
110
+ }
111
+
112
+ /**
113
+ * The same label as a Known-limitations line, for the release-highlights gate.
114
+ *
115
+ * It carries the label plus the sentence that keeps a reader from mistaking it
116
+ * for a refusal, because the field it prints beside is one the gate CAN refuse
117
+ * on. Without that sentence the next person to read the output reasonably
118
+ * concludes the gate is about to start failing cuts on coverage, and the cheapest
119
+ * way to make the message go away becomes raising the ceiling — which is the
120
+ * owner's spend decision, taken by whoever happened to read the line.
121
+ *
122
+ * Returns `null` when there is nothing to say, so the caller prints nothing
123
+ * rather than a reassuring sentence about a number it does not have.
124
+ */
125
+ export function coverageLimitationNote(label: string | null): string | null {
126
+ if (label === null) {
127
+ return null;
128
+ }
129
+ return (
130
+ `ℹ️ ${label} — a limitation of the RECORD, not a verdict on the release. ` +
131
+ 'Stated, never enforced:\n what the review reads is a spend decision and this ' +
132
+ 'gate does not take it.'
133
+ );
134
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * The high-consequence rule class — one reader for the config, the projector
3
+ * and the test.
4
+ *
5
+ * The criterion itself is prose and lives where an author meets it: the
6
+ * `consequence_class` property of `src/scripts/schemas/rule.schema.json`. This
7
+ * module does not restate it. It reads the list the criterion produced
8
+ * (`src/config/rule-consequence-class.json`), joins it to what each rule file
9
+ * actually declares, and answers the one question `project_thin_rules` asks:
10
+ * may this rule's stub carry its own law, and if not, has that been declared?
11
+ *
12
+ * WHY A DECLARED `no_stub` SUBSET RATHER THAN A SHORTER CLASS. A member whose
13
+ * law section is missing or over the ceiling cannot ship as stub-plus-law —
14
+ * there is nothing short enough to copy. Two ways to handle that: drop it from
15
+ * the class, or keep it in the class and record why it cannot stand. Dropping
16
+ * it makes the class shrinkable by NOT writing a law, which is the incentive a
17
+ * criterion must not create. Keeping it leaves the obligation visible and costs
18
+ * only a full-bodied projection, which is what those rules get today anyway.
19
+ */
20
+ import * as fs from 'node:fs';
21
+ import * as path from 'node:path';
22
+
23
+ export const CLASS_CONFIG_REL = 'src/config/rule-consequence-class.json';
24
+
25
+ export const CLAUSES = ['irreversible-external', 'security-boundary', 'authority-bypass'] as const;
26
+ export type Clause = (typeof CLAUSES)[number];
27
+
28
+ export interface ClassMember {
29
+ clause: Clause;
30
+ /** What this rule's own law obligates, and what violating it costs. */
31
+ why: string;
32
+ }
33
+
34
+ export interface NoStubEntry extends ClassMember {
35
+ /** Why the law cannot stand in a stub today. */
36
+ reason: string;
37
+ }
38
+
39
+ export interface ConsequenceClassConfig {
40
+ criterion_ref: string;
41
+ members: Record<string, ClassMember>;
42
+ /** Subset of `members` that projects full-bodied, each with its reason. */
43
+ no_stub: Record<string, NoStubEntry>;
44
+ /** Near misses the criterion rejected, each with the reason it was rejected. */
45
+ excluded: Record<string, string>;
46
+ }
47
+
48
+ export function readConsequenceClass(repoRoot: string): ConsequenceClassConfig {
49
+ const raw = JSON.parse(fs.readFileSync(path.join(repoRoot, CLASS_CONFIG_REL), 'utf-8')) as Partial<
50
+ ConsequenceClassConfig
51
+ >;
52
+ return {
53
+ criterion_ref: raw.criterion_ref ?? '',
54
+ members: raw.members ?? {},
55
+ no_stub: raw.no_stub ?? {},
56
+ excluded: raw.excluded ?? {},
57
+ };
58
+ }
59
+
60
+ /** Ids whose stub carries their law — members minus the declared `no_stub` set. */
61
+ export function stubLawIds(cfg: ConsequenceClassConfig): Set<string> {
62
+ return new Set(Object.keys(cfg.members).filter((id) => cfg.no_stub[id] === undefined));
63
+ }
64
+
65
+ /** The `consequence_class:` value a rule file declares, or `null`. */
66
+ export function declaredClause(ruleText: string): Clause | null {
67
+ const m = /^consequence_class:\s*"?([a-z-]+)"?\s*$/m.exec(ruleText);
68
+ if (m === null) return null;
69
+ const v = m[1] as string;
70
+ return (CLAUSES as readonly string[]).includes(v) ? (v as Clause) : null;
71
+ }
@@ -72,8 +72,115 @@ export interface TierRuleMatch {
72
72
  /** Kinds of trigger a prompt alone can never fire. */
73
73
  export const PATH_TRIGGER_KINDS = ['path_prefix', 'file_pattern'] as const;
74
74
 
75
+ /**
76
+ * Set by `dispatch_hook` to its own resolved package root. Read here rather
77
+ * than threaded through every caller — see `ruleSourceDirs`.
78
+ */
79
+ export const PACKAGE_ROOT_ENV = 'AGENT_CONFIG_PACKAGE_ROOT';
80
+
81
+ function statKind(p: string): 'dir' | 'file' | null {
82
+ try {
83
+ const s = fs.statSync(p);
84
+ return s.isDirectory() ? 'dir' : s.isFile() ? 'file' : null;
85
+ } catch {
86
+ return null;
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Every tree a rule body may come from, highest precedence first.
92
+ *
93
+ * THE DEFECT THIS CLOSES, reproduced at `main` @ `9bc8cd4f2` and again on
94
+ * 2026-10-01. This module resolved bodies and the router under ONE root, and
95
+ * the carrier passed the envelope's workspace or `process.cwd()`. In this
96
+ * checkout those are the same directory and everything works. In a consumer
97
+ * project they are not: there is no `dist/` under the consumer's tree at all,
98
+ * so `loadRouter` threw, the carrier caught it and returned allow, and the
99
+ * concern delivered NOTHING while reporting no error. Every consumer runs it
100
+ * in someone else's project, so the shipped carrier was silent for every
101
+ * consumer and loud only for its author. `dispatch_hook.ts:722` has passed
102
+ * `AGENT_CONFIG_PACKAGE_ROOT` to every concern since the ADR-020 global-only
103
+ * install landed — the fix was one environment read away and nothing read it.
104
+ *
105
+ * THE ORDER IS THE CONTRACT:
106
+ *
107
+ * 1. `<root>/agents/overrides/<id>.md` — the developer's own layer.
108
+ * `agents_overlay.ts` already makes `overrides/` the one cascade kind
109
+ * that is both project- and user-global-eligible, and a consumer who has
110
+ * overridden a rule means it. It wins, which is what step 1.1's "with
111
+ * `agents/overrides/` keeping precedence" asks for.
112
+ * 2. `<root>/dist/agent-src/rules/<id>.md` — the maintainer checkout. Kept
113
+ * AHEAD of the package root and not behind it, so this repository's own
114
+ * behaviour is byte-identical to what it was before. A change that
115
+ * repairs consumers by moving the maintainer tree is one nobody can
116
+ * review against a known-good reading.
117
+ * 3. `<packageRoot>/dist/agent-src/rules/<id>.md` — the install. The only
118
+ * one of the three that exists in a foreign project.
119
+ *
120
+ * WHY THE ENVIRONMENT IS READ HERE rather than passed in. Nine call sites
121
+ * across the model, the shortlist, the arm experiment and two hooks pass a
122
+ * single `repoRoot`, and none of them has a second tree to offer. Threading a
123
+ * resolved source object through all of them would be a wide diff whose only
124
+ * real consumer is the carrier, and it costs runtime bytes in the composed
125
+ * hook bundle — which every hook event on every slot loads, under a hard
126
+ * ceiling (`src/config/hook-bundle-budget.json`). `roadmap_progress_hook`
127
+ * already reads this same variable this same way; this follows it rather than
128
+ * inventing a second convention. No `~` expansion: the one writer is
129
+ * `dispatch_hook`, which sets it from a `path.resolve` result.
130
+ */
131
+ export interface RuleSources {
132
+ /** Body directories, highest precedence first. */
133
+ readonly dirs: readonly string[];
134
+ /** The resolved package root, or `null` when the variable named nothing. */
135
+ readonly pkg: string | null;
136
+ /** The `dist/router.json` to route against, or `null`. */
137
+ readonly router: string | null;
138
+ /**
139
+ * One line naming why nothing resolved, or `null` when something did.
140
+ *
141
+ * A caller that found nothing must be able to SAY so. An empty delivery is
142
+ * indistinguishable from "no rule matched", which is exactly the silence
143
+ * this chain exists to end; reproducing it one layer up would be the whole
144
+ * defect again. The three wordings are distinguishable because the
145
+ * operator's next action differs: the variable was never set (a host or
146
+ * wrapper problem), it points somewhere that is gone (a move after
147
+ * install), or both resolved and the package carries no built corpus.
148
+ */
149
+ readonly gap: string | null;
150
+ }
151
+
152
+ /** Resolve the body dirs, the router and the gap wording in ONE filesystem pass. */
153
+ export function ruleSources(repoRoot: string): RuleSources {
154
+ const env = (process.env[PACKAGE_ROOT_ENV] ?? '').trim();
155
+ const pkg = env ? path.resolve(env) : null;
156
+ const dirs: string[] = [];
157
+ const add = (d: string): void => {
158
+ if (statKind(d) === 'dir' && !dirs.includes(d)) dirs.push(d);
159
+ };
160
+ add(path.join(repoRoot, 'agents', 'overrides'));
161
+ add(path.join(repoRoot, 'dist', 'agent-src', 'rules'));
162
+ if (pkg !== null) add(path.join(pkg, 'dist', 'agent-src', 'rules'));
163
+
164
+ const local = path.join(repoRoot, 'dist', 'router.json');
165
+ let router: string | null = statKind(local) === 'file' ? local : null;
166
+ if (router === null && pkg !== null) {
167
+ const shipped = path.join(pkg, 'dist', 'router.json');
168
+ if (statKind(shipped) === 'file') router = shipped;
169
+ }
170
+
171
+ let gap: string | null = null;
172
+ if (router === null || dirs.length === 0) {
173
+ const miss =
174
+ pkg === null
175
+ ? `${PACKAGE_ROOT_ENV} unset`
176
+ : `no ${router === null ? 'dist/router.json' : 'dist/agent-src/rules'} under ${repoRoot} or ${pkg}`;
177
+ gap = `rule-inject: no rule source — ${miss}`;
178
+ }
179
+ return { dirs, pkg, router, gap };
180
+ }
181
+
75
182
  export function loadRouter(repoRoot: string): Router {
76
- const p = path.join(repoRoot, 'dist', 'router.json');
183
+ const p = ruleSources(repoRoot).router ?? path.join(repoRoot, 'dist', 'router.json');
77
184
  return JSON.parse(fs.readFileSync(p, 'utf8')) as Router;
78
185
  }
79
186
 
@@ -163,16 +270,29 @@ export function matchTierRules(
163
270
  return out;
164
271
  }
165
272
 
166
- /** Where the projected body of a rule lives. */
167
- export function ruleBodyPath(repoRoot: string, id: string): string {
168
- return path.join(repoRoot, 'dist', 'agent-src', 'rules', `${id}.md`);
169
- }
170
-
171
- /** The projected body, or `null` when the rule has no projected file. */
273
+ /**
274
+ * The projected body from the highest-precedence tree carrying it, or `null`.
275
+ *
276
+ * `ruleBodyPath` used to sit in front of this and is gone: it returned the
277
+ * single-root path unconditionally, this diff changed its contract to "the
278
+ * first tree that has the file", and nothing outside this module ever called
279
+ * it. An exported helper whose last caller disappeared in the same diff is an
280
+ * own-orphan, and the composed hook bundle charges for it on every dispatch
281
+ * (`src/config/hook-bundle-budget.json`), so it is removed rather than left as
282
+ * a wrapper nobody uses.
283
+ */
172
284
  export function loadRuleBody(repoRoot: string, id: string): string | null {
173
- const p = ruleBodyPath(repoRoot, id);
174
- if (!fs.existsSync(p)) return null;
175
- return fs.readFileSync(p, 'utf8');
285
+ for (const dir of ruleSources(repoRoot).dirs) {
286
+ const p = path.join(dir, `${id}.md`);
287
+ if (statKind(p) === 'file') {
288
+ try {
289
+ return fs.readFileSync(p, 'utf8');
290
+ } catch {
291
+ return null;
292
+ }
293
+ }
294
+ }
295
+ return null;
176
296
  }
177
297
 
178
298
  /**