@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
@@ -9,10 +9,15 @@
9
9
  *
10
10
  * 1. **No array indices.** Pointers MUST target named object keys only.
11
11
  * `/hooks/PostToolUse` is valid; `/hooks/PostToolUse/0` is not.
12
- * 2. **Arrays carry a `value_hash` discriminator.** A pointer that
13
- * targets a parent whose value is a list records the SHA-256 of the
14
- * JSON-serialised list contents the install wrote, so uninstall can
15
- * identify the owned elements by content rather than position.
12
+ * 2. **Arrays carry a discriminator, and which one depends on who owns
13
+ * the list.** A list this package owns outright records the SHA-256 of
14
+ * the contents the install wrote, so uninstall identifies the owned
15
+ * elements by content rather than position. A list it merely APPENDS to —
16
+ * a host's `hooks.<event>`, shared with every other agent package the
17
+ * consumer installed — records an `entry_signature` instead: uninstall
18
+ * then filters that list rather than claiming it. Recording a hash there
19
+ * was the defect; it made uninstall either delete a neighbour's entries
20
+ * or, once a neighbour had appended, refuse and leave ours behind.
16
21
  *
17
22
  * `value_hash` reproduces Python's canonical
18
23
  * `json.dumps(value, sort_keys=True, separators=(",", ":"))` output
@@ -22,6 +27,8 @@
22
27
 
23
28
  import { createHash } from "node:crypto";
24
29
 
30
+ import { HOOK_SIGNATURES, isManagedEntry } from "./host_hook_merge.js";
31
+
25
32
  type JsonValue =
26
33
  | null
27
34
  | boolean
@@ -172,6 +179,23 @@ export function value_hash(value: unknown): string {
172
179
  export interface PointerEntry {
173
180
  json_pointer: string;
174
181
  value_hash: string | null;
182
+ /**
183
+ * Set when the pointer targets a SHARED array this package appends to
184
+ * rather than owns — a host's `hooks.<event>` list.
185
+ *
186
+ * Recording `value_hash` for such an array claims the whole list, and both
187
+ * outcomes of that claim are wrong at uninstall: an untouched list is
188
+ * deleted wholesale, taking a neighbour's entries with it, and a list a
189
+ * neighbour appended to reports `drift` and leaves OUR entries behind. With
190
+ * a signature, subtraction filters the array instead: entries carrying the
191
+ * signature go, everything else stays, and the key is removed only once the
192
+ * list is empty.
193
+ *
194
+ * `value_hash` is null whenever this is set — the two are alternatives, and
195
+ * a hash of a list other packages may legitimately have changed is not a
196
+ * drift signal, it is a false one.
197
+ */
198
+ entry_signature?: string;
175
199
  }
176
200
 
177
201
  export interface MergeEntry extends PointerEntry {
@@ -187,6 +211,12 @@ function _is_plain_object(value: unknown): value is Record<string, unknown> {
187
211
  export interface CollectPointersOptions {
188
212
  prefix?: string;
189
213
  include_arrays?: boolean;
214
+ /**
215
+ * Content signature identifying this package's entries inside a shared
216
+ * array. When set, an array pointer records the signature instead of a
217
+ * whole-list hash (see `PointerEntry.entry_signature`).
218
+ */
219
+ entry_signature?: string;
190
220
  }
191
221
 
192
222
  /**
@@ -208,6 +238,7 @@ export function collect_pointers(
208
238
  ): PointerEntry[] {
209
239
  const prefix = options.prefix ?? "";
210
240
  const include_arrays = options.include_arrays ?? true;
241
+ const entry_signature = options.entry_signature ?? "";
211
242
  const entries: PointerEntry[] = [];
212
243
  for (const [key, value] of Object.entries(overlay)) {
213
244
  const pointer = `${prefix}/${_escape_segment(String(key))}`;
@@ -219,14 +250,29 @@ export function collect_pointers(
219
250
  entries.push({ json_pointer: pointer, value_hash: null });
220
251
  } else {
221
252
  entries.push(
222
- ...collect_pointers(value, { prefix: pointer, include_arrays }),
253
+ ...collect_pointers(value, {
254
+ prefix: pointer,
255
+ include_arrays,
256
+ entry_signature,
257
+ }),
223
258
  );
224
259
  }
225
260
  } else if (Array.isArray(value)) {
226
- entries.push({
227
- json_pointer: pointer,
228
- value_hash: include_arrays ? value_hash(value) : null,
229
- });
261
+ // Only the host's shared hook lists are appended to; every other array
262
+ // in the same overlay — `mcpServers.*.args`, for one — this package
263
+ // still owns outright and keeps hashing.
264
+ if (entry_signature !== "" && pointer.startsWith("/hooks/")) {
265
+ entries.push({
266
+ json_pointer: pointer,
267
+ value_hash: null,
268
+ entry_signature,
269
+ });
270
+ } else {
271
+ entries.push({
272
+ json_pointer: pointer,
273
+ value_hash: include_arrays ? value_hash(value) : null,
274
+ });
275
+ }
230
276
  } else {
231
277
  entries.push({ json_pointer: pointer, value_hash: null });
232
278
  }
@@ -252,11 +298,16 @@ export function build_merge_entries(
252
298
  file_label: string,
253
299
  overlay: Record<string, unknown>,
254
300
  ): MergeEntry[] {
255
- const pointers = collect_pointers(overlay);
301
+ const pointers = collect_pointers(overlay, {
302
+ entry_signature: HOOK_SIGNATURES[file_label] ?? "",
303
+ });
256
304
  return pointers.map((entry) => ({
257
305
  file: file_label,
258
306
  json_pointer: entry.json_pointer,
259
307
  value_hash: entry.value_hash,
308
+ ...(entry.entry_signature === undefined
309
+ ? {}
310
+ : { entry_signature: entry.entry_signature }),
260
311
  }));
261
312
  }
262
313
 
@@ -304,6 +355,8 @@ export interface SubtractWarning {
304
355
  export interface SubtractEntry {
305
356
  json_pointer: string;
306
357
  value_hash?: string | null;
358
+ /** See `PointerEntry.entry_signature` — filters a shared array in place. */
359
+ entry_signature?: string;
307
360
  }
308
361
 
309
362
  /**
@@ -354,7 +407,36 @@ export function subtract_pointers(
354
407
  continue;
355
408
  }
356
409
  const [parent, leaf] = nav;
357
- if (expected !== null) {
410
+ const signature = entry.entry_signature ?? "";
411
+ if (signature !== "") {
412
+ const current = parent[leaf];
413
+ if (!Array.isArray(current)) {
414
+ warnings.push({
415
+ pointer,
416
+ reason: "missing",
417
+ expected_hash: null,
418
+ actual_hash: null,
419
+ });
420
+ continue;
421
+ }
422
+ // A shared list: drop only the entries carrying our signature, keep a
423
+ // neighbour's in order and byte-identical, and remove the key only once
424
+ // nothing of ours is left in it.
425
+ const kept = current.filter((item) => !isManagedEntry(item, signature));
426
+ if (kept.length === current.length) {
427
+ warnings.push({
428
+ pointer,
429
+ reason: "missing",
430
+ expected_hash: null,
431
+ actual_hash: null,
432
+ });
433
+ continue;
434
+ }
435
+ if (kept.length > 0) {
436
+ parent[leaf] = kept;
437
+ continue;
438
+ }
439
+ } else if (expected !== null) {
358
440
  const actual = value_hash(parent[leaf]);
359
441
  if (actual !== expected) {
360
442
  warnings.push({
@@ -1,20 +1,65 @@
1
1
  /**
2
- * `lean_projection.mode` — ONE definition of what the three modes mean.
3
- *
4
- * The projector (`condense.ts`) resolves the value with a real YAML parse; the
5
- * delivery concern (`hooks/rule_inject_hook.ts`) resolves it with an
6
- * indentation-shaped read, because a hook must never fail a tool call because a
7
- * parser could not load. Two readers is unavoidable. Two *normalisations* is
8
- * not, and would be the defect worth preventing: a projector that writes thin
9
- * files while the concern believes the mode is off delivers pointers and no
10
- * bodies, which is exactly the 36.2 % arm the delivery mode exists to replace.
11
- *
12
- * So each side supplies the raw string from its own reader and this module
13
- * decides what it means. Anything unrecognised — absent key, typo, `null`,
14
- * a non-string — is `eager-all`: the parser fallback, which is NOT the value
15
- * the template ships (see the type below), because a mode nobody can spell
16
- * must never silently thin the standing corpus.
2
+ * `lean_projection.mode` — ONE definition of what the three modes mean, and
3
+ * since step 1.2 of `road-to-a-rule-carrier-that-works-outside-the-repo`, ONE
4
+ * reader that produces it.
5
+ *
6
+ * ── What this module used to be, and why that was not enough ──
7
+ *
8
+ * It owned the NORMALISATION and left each caller its own READER: the projector
9
+ * (`condense.ts`) resolved the value with a real YAML parse over the full
10
+ * settings cascade; the delivery concern (`hooks/rule_inject_hook.ts`) resolved
11
+ * it with an indentation-shaped read of `<cwd>/.agent-settings.yml` alone. The
12
+ * header argued that two readers were unavoidable and that two *normalisations*
13
+ * were the only thing worth preventing.
14
+ *
15
+ * Measured on 2026-10-02, that split was not a stylistic difference — it was a
16
+ * disagreement about WHICH FILE. The installer writes settings to
17
+ * `<root>/agents/settings/.agent-settings.yml` (`agent_settings.ts`'s canonical
18
+ * write target; `install.ts:4108`). The concern read `<root>/.agent-settings.yml`,
19
+ * the LEGACY location, and nothing else. On a normal install the concern
20
+ * therefore read a file that does not exist, got `''`, normalised it to
21
+ * `eager-all`, and closed its own gate — while the projector, reading the
22
+ * canonical file, had written thin stubs. That is the pointer arm the delivery
23
+ * mode exists to replace, reached by configuration rather than by choice, and
24
+ * it is a SECOND independent cause of the silence step 1.1 repaired: a consumer
25
+ * that fixed the package root alone would still have received nothing.
26
+ *
27
+ * The user-global layer was invisible to the concern for the same reason, which
28
+ * matters more than it sounds: ADR-020 installs are global-only, so for those
29
+ * consumers the ONLY layer carrying a mode is one the concern never opened.
30
+ *
31
+ * ── D3: one resolver, not a parity test between three ──
32
+ *
33
+ * The roadmap's D3 records the choice and the reason — a parity test keeps
34
+ * three readers that can drift again, and this module already existed to be the
35
+ * one. `resolveLeanProjection` below is that resolver. It reads the layers in
36
+ * the order `load_agent_settings` defines (template base, user-global,
37
+ * project), through `project_settings_path`, which prefers the canonical file
38
+ * and falls back to the legacy one, so a hand-edited root file still works.
39
+ *
40
+ * ── Why the template path is passed in rather than resolved ──
41
+ *
42
+ * `agent_settings.default_template_path()` derives the package root from
43
+ * `import.meta.url` three directories up. That is correct for a module at
44
+ * `<pkg>/src/scripts/_lib/`; inside the composed hook bundle `import.meta.url`
45
+ * is `<pkg>/dist/hooks/dispatch.js`, so the same arithmetic yields the PARENT
46
+ * of the package and the template read misses. Verified in the built bundle,
47
+ * not inferred. With no template the base layer is `{}` and an unconfigured
48
+ * consumer resolves to `eager-all` — the silence again, one layer lower. So a
49
+ * caller that knows the real package root (the carrier does: the dispatcher
50
+ * passes it) hands it over, and the resolver reads the template from there.
51
+ *
52
+ * ── What has NOT changed ──
53
+ *
54
+ * Anything unrecognised — absent key, typo, `null`, a non-string — is still
55
+ * `eager-all`: the parser fallback, which is NOT the value the template ships
56
+ * (see the type below), because a mode nobody can spell must never silently
57
+ * thin the standing corpus. That fallback now fires only when no layer carried
58
+ * a value at all, rather than whenever the concern looked in the wrong place.
17
59
  */
60
+ import * as path from 'node:path';
61
+
62
+ import { load_agent_settings } from './agent_settings.js';
18
63
 
19
64
  /**
20
65
  * The three projection shapes, and the two different defaults they answer to.
@@ -180,3 +225,218 @@ export function describeDroppedHosts(res: LeanProjectionHosts): string[] {
180
225
  export function thinsHost(mode: LeanProjectionMode, hosts: readonly string[], hostId: string): boolean {
181
226
  return writesThinFiles(mode) && hosts.includes(hostId);
182
227
  }
228
+
229
+ export interface ResolvedLeanProjection {
230
+ readonly mode: LeanProjectionMode;
231
+ readonly hosts: LeanProjectionHosts;
232
+ /**
233
+ * Was `lean_projection.mode` set on a layer the USER controls — user-global,
234
+ * project, or project-local — rather than inherited from the shipped
235
+ * template?
236
+ *
237
+ * THE DISTINCTION IS NOT A REFINEMENT, IT IS A SAFETY BOUNDARY, and it is
238
+ * the one `road-to-an-installed-layer-that-is-thinned` names in its Context:
239
+ * the shipped template already says `mode: delivery`
240
+ * (`src/config/agent-settings.template.yml:212-214`), so the moment the
241
+ * INSTALLER resolves the mode through this resolver, the template value
242
+ * alone would thin every consumer's `~/.claude/rules` — a default flip
243
+ * arriving as a side effect of wiring a reader, with nobody deciding it.
244
+ *
245
+ * Whether that default flips is owner-reserved (that roadmap's blocker
246
+ * `default-flip-of-the-installed-layer`, decision D4). So the installer must
247
+ * be able to ask a question `mode` cannot answer: not "what is the mode" but
248
+ * "did a human ask for this". That is this flag, and it is why it reports
249
+ * provenance rather than a value.
250
+ *
251
+ * `false` whenever no layer the user controls carries the key — including
252
+ * when `mode` reads `delivery` from the template, which is exactly the case
253
+ * that must NOT be read as consent.
254
+ */
255
+ readonly modeExplicit: boolean;
256
+ }
257
+
258
+ export interface ResolveOptions {
259
+ /** Project tree whose settings cascade is read. */
260
+ readonly projectRoot?: string | null;
261
+ /** Explicit settings file, overriding `projectRoot`. Tests and `condense` pin this. */
262
+ readonly settingsPath?: string | null;
263
+ /** Install root carrying `src/config/agent-settings.template.yml`. */
264
+ readonly packageRoot?: string | null;
265
+ }
266
+
267
+ /**
268
+ * THE resolver. Every surface that asks "which delivery mode" calls this.
269
+ *
270
+ * Tolerant like everything else on a hook path: `load_agent_settings` answers
271
+ * with defaults on an unreadable or malformed file and never throws, and the
272
+ * normalisers above turn anything unrecognised into the safe value. A caller
273
+ * on a hot path pays ONE cascade read per prompt; `modeExplicit` is a lazy
274
+ * getter, so the second, template-isolated read happens only for a caller that
275
+ * actually reads provenance — which today is the installer and nothing else.
276
+ */
277
+ export function resolveLeanProjection(opts: ResolveOptions = {}): ResolvedLeanProjection {
278
+ // The LEGACY root path, deliberately, and not `project_settings_path`'s
279
+ // either-or pick. `load_agent_settings` expands whatever it is given into
280
+ // `[the file, <its dir>/agents/settings/.agent-settings.yml, <its dir>/
281
+ // agents/settings/.agent-settings.local.yml]` and merges them deepest-wins,
282
+ // so handing it the root path reads BOTH the legacy and the canonical file
283
+ // — which is strictly more than picking one, and is what a tree carrying
284
+ // both should resolve to. It also keeps one export out of this module's
285
+ // import list, which is runtime bytes in the composed hook bundle.
286
+ const file =
287
+ opts.settingsPath ?? path.join(opts.projectRoot ?? process.cwd(), '.agent-settings.yml');
288
+ const tpl =
289
+ opts.packageRoot == null
290
+ ? null
291
+ : path.join(opts.packageRoot, 'src', 'config', 'agent-settings.template.yml');
292
+ let lean: unknown;
293
+ try {
294
+ lean = load_agent_settings(
295
+ tpl === null ? { project_path: file } : { project_path: file, template_path: tpl },
296
+ )['lean_projection'];
297
+ } catch {
298
+ /* a settings layer nothing can read must never fail a turn */
299
+ }
300
+ const obj = typeof lean === 'object' && lean !== null && !Array.isArray(lean) ? lean : {};
301
+ const o = obj as Record<string, unknown>;
302
+ return {
303
+ mode: normalizeLeanProjectionMode(o['mode'] ?? ''),
304
+ hosts: resolveLeanProjectionHosts(o['hosts']),
305
+ // LAZY, and the hot path is the reason. Provenance needs a SECOND,
306
+ // template-isolated cascade, and only the installer reads it — the
307
+ // delivery concern on `user_prompt_submit` destructures `{ mode, hosts }`
308
+ // and discards this field, so computing it eagerly doubled the per-prompt
309
+ // settings read for an answer nobody asked for. A getter keeps the
310
+ // field's shape (`readonly modeExplicit: boolean`) and charges only the
311
+ // caller that touches it.
312
+ get modeExplicit(): boolean {
313
+ return rawExplicitLeanProjectionMode(opts) !== '';
314
+ },
315
+ };
316
+ }
317
+
318
+ /**
319
+ * A path no tree contains, so `template_defaults` contributes nothing.
320
+ *
321
+ * This is the mechanism `load_agent_settings` documents for the purpose —
322
+ * "a test or tool that pins every other input can pin the defaults base too,
323
+ * and point it at a nonexistent file to isolate the cascade" — used here for a
324
+ * tool rather than a test. It is a reserved device filename on every platform
325
+ * this package runs on and is never created, so the read fails and the loader's
326
+ * own tolerance turns it into `{}`.
327
+ *
328
+ * The alternative — re-reading the YAML layers by hand — was rejected because
329
+ * it would be a SECOND reader of the same key, which is the precise defect step
330
+ * 1.2 of the carrier roadmap existed to remove. Isolating the base keeps one
331
+ * reader and changes only which layers it is given.
332
+ */
333
+ const NO_TEMPLATE_LAYER = path.join(path.sep, 'dev', 'null', 'agent-config-absent-template.yml');
334
+
335
+ /**
336
+ * The RAW `lean_projection.mode` string from the user-controlled layers only,
337
+ * or `''` when no such layer carries it.
338
+ *
339
+ * Raw and un-normalised on purpose: {@link normalizeLeanProjectionMode} maps
340
+ * everything unrecognised — `''` included — onto `eager-all`, so a normalised
341
+ * answer cannot tell "the user chose eager-all" from "the user chose nothing".
342
+ * Provenance needs exactly that distinction, so it has to be read before the
343
+ * normaliser runs.
344
+ */
345
+ export function rawExplicitLeanProjectionMode(opts: ResolveOptions = {}): string {
346
+ const file =
347
+ opts.settingsPath ?? path.join(opts.projectRoot ?? process.cwd(), '.agent-settings.yml');
348
+ let lean: unknown;
349
+ try {
350
+ lean = load_agent_settings({ project_path: file, template_path: NO_TEMPLATE_LAYER })[
351
+ 'lean_projection'
352
+ ];
353
+ } catch {
354
+ return ''; // a layer nothing can read states no preference
355
+ }
356
+ if (typeof lean !== 'object' || lean === null || Array.isArray(lean)) return '';
357
+ const m = (lean as Record<string, unknown>)['mode'];
358
+ return typeof m === 'string' ? m.trim() : '';
359
+ }
360
+
361
+ /**
362
+ * Did a human ask for this mode, and is it the one the caller is gated on?
363
+ *
364
+ * The question an installer actually has. `modeExplicit` alone is not enough —
365
+ * a consumer who explicitly set `eager-all` has set the key explicitly and must
366
+ * NOT be thinned — so the two conditions are folded here rather than left to
367
+ * every caller to remember to combine.
368
+ */
369
+ export function leanProjectionModeChosen(
370
+ mode: LeanProjectionMode,
371
+ opts: ResolveOptions = {},
372
+ ): boolean {
373
+ const raw = rawExplicitLeanProjectionMode(opts);
374
+ return raw !== '' && normalizeLeanProjectionMode(raw) === mode;
375
+ }
376
+
377
+ /**
378
+ * May the INSTALLER thin this host's rule tree?
379
+ *
380
+ * The host-aware sibling of {@link leanProjectionModeChosen}, and the predicate
381
+ * `road-to-an-installed-layer-that-is-thinned` step 1.1 keys on. It folds the
382
+ * three conditions that must hold together, once, so no caller has to remember
383
+ * to combine them:
384
+ *
385
+ * 1. **A human asked.** `modeExplicit` — false whenever the only layer carrying
386
+ * the key is the shipped template, which already says `delivery`. Reading the
387
+ * template as consent would thin every consumer's `~/.claude/rules` as a side
388
+ * effect of wiring a reader, which is the owner-reserved default flip (that
389
+ * roadmap's blocker, decision D4).
390
+ * 2. **The chosen mode actually writes stubs.** A consumer who explicitly chose
391
+ * `eager-all` has set the key and must NOT be thinned on the strength of
392
+ * having an opinion.
393
+ * 3. **This host is in scope.** The same `hosts:` list the projector honours, so
394
+ * installer and projector cannot disagree about which trees are thinned.
395
+ *
396
+ * ONE `resolveLeanProjection` call, which is why this is not two
397
+ * {@link leanProjectionModeChosen} calls: that one answers "is the chosen mode
398
+ * exactly X" and knows nothing about `hosts`, so a caller combining it with a
399
+ * host check by hand would re-create the fold this function exists to own.
400
+ *
401
+ * That is one CALL and two cascade READS here, because reading `modeExplicit`
402
+ * triggers its lazy getter and a second, template-isolated load. The installer
403
+ * runs once per deploy and does not care; the cost is named rather than rounded
404
+ * down because the same resolver serves the per-prompt delivery concern, which
405
+ * does NOT read provenance and therefore does not pay it.
406
+ */
407
+ export function installerThinsHost(hostId: string, opts: ResolveOptions = {}): boolean {
408
+ const { mode, hosts, modeExplicit } = resolveLeanProjection({
409
+ ...opts,
410
+ settingsPath: opts.settingsPath ?? NO_PROJECT_LAYER,
411
+ });
412
+ return modeExplicit && thinsHost(mode, hosts.hosts, hostId);
413
+ }
414
+
415
+ /**
416
+ * A path no tree contains, so the PROJECT cascade contributes nothing.
417
+ *
418
+ * The same device {@link NO_TEMPLATE_LAYER} uses, pointed at the other end of
419
+ * the cascade, and the reason is scope rather than isolation: the thing
420
+ * {@link installerThinsHost} gates is a mutation of `~/.claude/rules`, which
421
+ * belongs to the MACHINE. A per-checkout value must not decide it, in either
422
+ * direction — a project saying `delivery` would thin the layer every other
423
+ * project on that machine reads, and a project saying `eager-all` would
424
+ * suppress an opt-in the user wrote user-globally, because the project cascade
425
+ * merges last and wins.
426
+ *
427
+ * `load_agent_settings` reads `user_global_settings_paths()` regardless of what
428
+ * `project_path` it is given, so pointing the project layer at nothing leaves
429
+ * exactly the machine-global layers — which is the scope the installer's
430
+ * sibling `_resolve_global_rule_scope` already resolves for the same deploy.
431
+ * A caller may still pass an explicit `settingsPath` (tests pin one). A
432
+ * `projectRoot` handed to {@link installerThinsHost} is DISCARDED — the `??`
433
+ * chain terminates at `settingsPath` before `projectRoot` is consulted — which
434
+ * is the intended behaviour and is stated here because a caller passing it and
435
+ * expecting it honoured would otherwise get no signal.
436
+ */
437
+ const NO_PROJECT_LAYER = path.join(
438
+ path.sep,
439
+ 'dev',
440
+ 'null',
441
+ 'agent-config-absent-project-settings.yml',
442
+ );
@@ -37,6 +37,7 @@
37
37
  */
38
38
 
39
39
  import { load_anthropic_key } from '../ai_council/clients.js';
40
+ import { sanitize_text } from './retrieval_sanitize.js';
40
41
  import type {
41
42
  GenerationRequest,
42
43
  GenerationResult,
@@ -140,10 +141,19 @@ export function anthropicGenerator(keyPath: string | null = null): TextGenerator
140
141
  );
141
142
  }
142
143
  const data = (await resp.json()) as AnthropicResponse;
143
- const text = (data.content ?? [])
144
- .filter((b) => b.type === 'text')
145
- .map((b) => b.text ?? '')
146
- .join('');
144
+ // Sanitize AT THE TRANSPORT, which is the choke point and one call site.
145
+ // A flag every caller has to remember is the instruction-only
146
+ // enforcement this package diagnoses in itself, and a partially
147
+ // sanitized world — some callers filtered, some not — is worse than
148
+ // either end state. The floor is a no-op on ordinary text, so what
149
+ // changes here is only a response that carries a hidden-instruction
150
+ // vector; see `docs/contracts/retrieval-read-surfaces.md`.
151
+ const text = sanitize_text(
152
+ (data.content ?? [])
153
+ .filter((b) => b.type === 'text')
154
+ .map((b) => b.text ?? '')
155
+ .join(''),
156
+ );
147
157
  // An empty body is returned AS an empty body rather than repaired here.
148
158
  // The arm's own output contract refuses it and classifies the refusal;
149
159
  // repairing it in the transport would move a decision into the layer
@@ -12,9 +12,11 @@
12
12
  * a property of the `user_prompt_submit` SLOT, not of any one concern: the host
13
13
  * delivers a background task notification on the same slot as a typed prompt,
14
14
  * so every concern that consumes or replaces per-turn state has the same defect.
15
- * Two are known — the git-authorization ledger with its pending-refusal record,
16
- * and the suggestion-capture latch. A predicate private to one of them would
17
- * have repaired one and left the other, which is risk 4 of
15
+ * Three are known — the git-authorization ledger with its pending-refusal
16
+ * record, the suggestion-capture latch, and `language_mirror_hook`'s reply
17
+ * pin, which does not consult this predicate at all and so pins a language
18
+ * from a frame nobody typed. A predicate private to one of them would have
19
+ * repaired one and left the others, which is risk 4 of
18
20
  * `road-to-turn-bound-authorization-integrity`.
19
21
  *
20
22
  * **The discriminator, quoted from a captured payload rather than from
@@ -26,6 +28,16 @@
26
28
  * `<task-id>`, `<tool-use-id>`, `<status>` and `<summary>` children. A typed
27
29
  * turn carries none of them.
28
30
  *
31
+ * **The third shape, added 2026-10-03, found the same way.** A subagent
32
+ * hand-back arrives on this slot as `<agent-message from="…">`, and 12 of the
33
+ * 153 hook-sourced user records in the capture open with it — every one on
34
+ * `hook:claude:UserPromptSubmit`. It was found because one landed 13 seconds
35
+ * after a merge and rewrote the git-authorization ledger to
36
+ * `prompt_chars: 5599`, the length of the injected frame rather than of any
37
+ * sentence a human sent. Its prefix stops before the `>` because the element
38
+ * carries an attribute; that is a shorter literal than the other two, not a
39
+ * substring match — it is still anchored at position zero.
40
+ *
29
41
  * **Prefix, not substring, and that is the whole care in this file.** A
30
42
  * notification is a synthetic turn the host constructs, so the element opens it.
31
43
  * Matching anywhere in the text would make the question "why did this
@@ -37,6 +49,7 @@
37
49
  export const MACHINE_WAKE_PREFIXES: readonly string[] = [
38
50
  '<task-notification>',
39
51
  '<system-reminder>',
52
+ '<agent-message',
40
53
  ];
41
54
 
42
55
  /** @see MACHINE_WAKE_PREFIXES — unknown shapes answer `true`, deliberately. */