@event4u/agent-config 14.22.0 → 15.0.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 (557) 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 +333 -356
  5. package/README.md +1 -1
  6. package/dist/agent-src/commands/agent-handoff.md +8 -7
  7. package/dist/agent-src/commands/agents/init.md +1 -1
  8. package/dist/agent-src/commands/agents/user/accept.md +4 -4
  9. package/dist/agent-src/commands/agents/user/delete.md +2 -2
  10. package/dist/agent-src/commands/agents/user/init.md +3 -3
  11. package/dist/agent-src/commands/agents/user/review.md +3 -3
  12. package/dist/agent-src/commands/agents/user/show.md +3 -3
  13. package/dist/agent-src/commands/agents/user/update.md +2 -2
  14. package/dist/agent-src/commands/agents/user.md +6 -6
  15. package/dist/agent-src/commands/analytics/prune.md +1 -1
  16. package/dist/agent-src/commands/analytics/show.md +2 -2
  17. package/dist/agent-src/commands/analyze/decision.md +2 -2
  18. package/dist/agent-src/commands/analyze/inbox.md +5 -5
  19. package/dist/agent-src/commands/analyze/incident.md +3 -3
  20. package/dist/agent-src/commands/analyze/near-miss.md +3 -3
  21. package/dist/agent-src/commands/analyze/postmortem.md +4 -4
  22. package/dist/agent-src/commands/analyze/premortem.md +2 -2
  23. package/dist/agent-src/commands/analyze.md +2 -2
  24. package/dist/agent-src/commands/bug/fix.md +1 -1
  25. package/dist/agent-src/commands/bug/investigate.md +2 -2
  26. package/dist/agent-src/commands/cost/profile.md +3 -3
  27. package/dist/agent-src/commands/design.md +1 -1
  28. package/dist/agent-src/commands/feature/explore.md +1 -1
  29. package/dist/agent-src/commands/feature/plan.md +2 -2
  30. package/dist/agent-src/commands/feature/roadmap.md +2 -2
  31. package/dist/agent-src/commands/ghostwriter/fetch.md +4 -4
  32. package/dist/agent-src/commands/ghostwriter/list.md +1 -1
  33. package/dist/agent-src/commands/ghostwriter/show.md +1 -1
  34. package/dist/agent-src/commands/ghostwriter/write.md +9 -9
  35. package/dist/agent-src/commands/humanize.md +6 -6
  36. package/dist/agent-src/commands/jira-ticket.md +1 -1
  37. package/dist/agent-src/commands/judge/solo.md +1 -1
  38. package/dist/agent-src/commands/judge.md +1 -1
  39. package/dist/agent-src/commands/knowledge/cross-repo.md +1 -1
  40. package/dist/agent-src/commands/knowledge/forget.md +1 -1
  41. package/dist/agent-src/commands/knowledge/ingest.md +2 -2
  42. package/dist/agent-src/commands/knowledge/list.md +1 -1
  43. package/dist/agent-src/commands/memory/add.md +3 -3
  44. package/dist/agent-src/commands/memory/load.md +4 -4
  45. package/dist/agent-src/commands/memory/mine-session.md +1 -1
  46. package/dist/agent-src/commands/memory/promote.md +4 -4
  47. package/dist/agent-src/commands/memory/propose.md +2 -2
  48. package/dist/agent-src/commands/mode.md +5 -5
  49. package/dist/agent-src/commands/post-as/ghostwriter.md +3 -3
  50. package/dist/agent-src/commands/post-as/me.md +7 -7
  51. package/dist/agent-src/commands/pr/create.md +1 -1
  52. package/dist/agent-src/commands/pr/merge.md +48 -39
  53. package/dist/agent-src/commands/profile/activate.md +1 -1
  54. package/dist/agent-src/commands/profile/show.md +1 -1
  55. package/dist/agent-src/commands/research/deep.md +2 -2
  56. package/dist/agent-src/commands/research/report.md +2 -2
  57. package/dist/agent-src/commands/review/changes.md +1 -1
  58. package/dist/agent-src/commands/review/routing.md +1 -1
  59. package/dist/agent-src/commands/roadmap/create.md +1 -1
  60. package/dist/agent-src/commands/roadmap/materialize.md +2 -2
  61. package/dist/agent-src/commands/roadmap/next.md +9 -1
  62. package/dist/agent-src/commands/roadmap/process-full.md +2 -2
  63. package/dist/agent-src/commands/security-audit-config.md +3 -3
  64. package/dist/agent-src/commands/skill/preview.md +1 -1
  65. package/dist/agent-src/commands/skills/discover.md +1 -1
  66. package/dist/agent-src/commands/sync/agent-settings.md +2 -2
  67. package/dist/agent-src/commands/sync/gitignore/fix.md +1 -1
  68. package/dist/agent-src/commands/tests/create.md +1 -1
  69. package/dist/agent-src/commands/tests/e2e-heal.md +1 -1
  70. package/dist/agent-src/commands/tests/e2e-plan.md +1 -1
  71. package/dist/agent-src/contexts/authority/kernel-rule-edits.md +6 -6
  72. package/dist/agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +1 -2
  73. package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +2 -2
  74. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +88 -1
  75. package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +1 -1
  76. package/dist/agent-src/contexts/contracts/frugality-charter.md +1 -1
  77. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +1 -1
  78. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +1 -1
  79. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +13 -1
  80. package/dist/agent-src/contexts/execution/cheap-question-mechanics.md +1 -1
  81. package/dist/agent-src/contexts/execution/contract-decision-sheet.md +3 -3
  82. package/dist/agent-src/contexts/execution/mandated-lines.md +1 -1
  83. package/dist/agent-src/contexts/execution/non-interactive-contract.md +1 -1
  84. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -1
  85. package/dist/agent-src/contexts/execution/plan-confidence-gate.md +5 -5
  86. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +1 -1
  87. package/dist/agent-src/contexts/execution/subagent-modes-detail.md +1 -1
  88. package/dist/agent-src/contexts/execution/subagent-routing.md +2 -2
  89. package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +1 -1
  90. package/dist/agent-src/contexts/execution/user-memory-channels.md +3 -3
  91. package/dist/agent-src/contexts/execution/verification-mechanics.md +1 -1
  92. package/dist/agent-src/contexts/judges/persona-voice-rubric.md +2 -2
  93. package/dist/agent-src/guidelines/abstraction-thresholds.md +88 -0
  94. package/dist/agent-src/guidelines/agent-infra/5w2h-analysis.md +260 -0
  95. package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +99 -0
  96. package/dist/agent-src/guidelines/agent-infra/agent-interaction-and-decision-quality.md +325 -0
  97. package/dist/agent-src/guidelines/agent-infra/api-cost-levers.md +177 -0
  98. package/dist/agent-src/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +222 -0
  99. package/dist/agent-src/guidelines/agent-infra/ask-when-uncertain-demos.md +134 -0
  100. package/dist/agent-src/guidelines/agent-infra/asking-and-brevity-examples.md +198 -0
  101. package/dist/agent-src/guidelines/agent-infra/break-glass-usage.md +113 -0
  102. package/dist/agent-src/guidelines/agent-infra/carve-out-predicates.md +17 -0
  103. package/dist/agent-src/guidelines/agent-infra/comparison-matrix.md +179 -0
  104. package/dist/agent-src/guidelines/agent-infra/context-hygiene-mechanics.md +165 -0
  105. package/dist/agent-src/guidelines/agent-infra/corpus-grounding-authoring.md +91 -0
  106. package/dist/agent-src/guidelines/agent-infra/critical-thinking.md +156 -0
  107. package/dist/agent-src/guidelines/agent-infra/cross-source-consistency-mechanics.md +109 -0
  108. package/dist/agent-src/guidelines/agent-infra/developer-judgment.md +82 -0
  109. package/dist/agent-src/guidelines/agent-infra/direct-answers-demos.md +142 -0
  110. package/dist/agent-src/guidelines/agent-infra/domain-adoption-gates.md +112 -0
  111. package/dist/agent-src/guidelines/agent-infra/domain-eval-anti-pattern.md +53 -0
  112. package/dist/agent-src/guidelines/agent-infra/domain-pack-architecture.md +56 -0
  113. package/dist/agent-src/guidelines/agent-infra/downstream-changes-mechanics.md +91 -0
  114. package/dist/agent-src/guidelines/agent-infra/emphasis-budget.md +45 -0
  115. package/dist/agent-src/guidelines/agent-infra/engineering-memory-data-format.md +210 -0
  116. package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
  117. package/dist/agent-src/guidelines/agent-infra/existence-question-verdicts.md +80 -0
  118. package/dist/agent-src/guidelines/agent-infra/failure-signatures.md +70 -0
  119. package/dist/agent-src/guidelines/agent-infra/false-green.md +233 -0
  120. package/dist/agent-src/guidelines/agent-infra/first-principles.md +192 -0
  121. package/dist/agent-src/guidelines/agent-infra/framework-neutrality-patterns.md +66 -0
  122. package/dist/agent-src/guidelines/agent-infra/frontier-reasoning-operating-profile.md +169 -0
  123. package/dist/agent-src/guidelines/agent-infra/gate-authoring.md +177 -0
  124. package/dist/agent-src/guidelines/agent-infra/guarded-baseline.md +39 -0
  125. package/dist/agent-src/guidelines/agent-infra/installed-tools-manifest.md +142 -0
  126. package/dist/agent-src/guidelines/agent-infra/inversion-thinking.md +388 -0
  127. package/dist/agent-src/guidelines/agent-infra/ios-simulator-guide.md +378 -0
  128. package/dist/agent-src/guidelines/agent-infra/language-and-tone-examples.md +141 -0
  129. package/dist/agent-src/guidelines/agent-infra/layered-settings.md +317 -0
  130. package/dist/agent-src/guidelines/agent-infra/linked-projects-onboarding-gate.md +80 -0
  131. package/dist/agent-src/guidelines/agent-infra/mcp-request-signing.md +197 -0
  132. package/dist/agent-src/guidelines/agent-infra/memory-access.md +149 -0
  133. package/dist/agent-src/guidelines/agent-infra/mental-models.md +314 -0
  134. package/dist/agent-src/guidelines/agent-infra/minimal-safe-diff-mechanics.md +241 -0
  135. package/dist/agent-src/guidelines/agent-infra/missing-tool-handling.md +66 -0
  136. package/dist/agent-src/guidelines/agent-infra/model-recommendation.md +101 -0
  137. package/dist/agent-src/guidelines/agent-infra/naming.md +69 -0
  138. package/dist/agent-src/guidelines/agent-infra/notes-horizon-mechanics.md +90 -0
  139. package/dist/agent-src/guidelines/agent-infra/output-patterns.md +117 -0
  140. package/dist/agent-src/guidelines/agent-infra/recurring-criticism-mechanics.md +96 -0
  141. package/dist/agent-src/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
  142. package/dist/agent-src/guidelines/agent-infra/review-routing-data-format.md +143 -0
  143. package/dist/agent-src/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
  144. package/dist/agent-src/guidelines/agent-infra/roadmap-progress-mechanics.md +274 -0
  145. package/dist/agent-src/guidelines/agent-infra/role-contracts.md +209 -0
  146. package/dist/agent-src/guidelines/agent-infra/role-mode-router.md +89 -0
  147. package/dist/agent-src/guidelines/agent-infra/rule-body-migration-inventory.md +241 -0
  148. package/dist/agent-src/guidelines/agent-infra/rule-type-governance.md +73 -0
  149. package/dist/agent-src/guidelines/agent-infra/runtime-layer.md +89 -0
  150. package/dist/agent-src/guidelines/agent-infra/scqa-framework.md +526 -0
  151. package/dist/agent-src/guidelines/agent-infra/security-lint-containment.md +121 -0
  152. package/dist/agent-src/guidelines/agent-infra/self-improvement-pipeline.md +134 -0
  153. package/dist/agent-src/guidelines/agent-infra/simplicity-and-goal-demos.md +211 -0
  154. package/dist/agent-src/guidelines/agent-infra/six-hats.md +353 -0
  155. package/dist/agent-src/guidelines/agent-infra/size-and-scope.md +229 -0
  156. package/dist/agent-src/guidelines/agent-infra/skill-quality-checklist.md +157 -0
  157. package/dist/agent-src/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
  158. package/dist/agent-src/guidelines/agent-infra/symptom-driven-harvest-loop.md +104 -0
  159. package/dist/agent-src/guidelines/agent-infra/systems-thinking.md +220 -0
  160. package/dist/agent-src/guidelines/agent-infra/tool-description-as-policy.md +35 -0
  161. package/dist/agent-src/guidelines/agent-infra/tool-integration.md +73 -0
  162. package/dist/agent-src/guidelines/agent-infra/traceability-field-mechanics.md +50 -0
  163. package/dist/agent-src/guidelines/agent-infra/untrusted-input-spotlighting.md +166 -0
  164. package/dist/agent-src/guidelines/agent-infra/verify-before-complete-demos.md +128 -0
  165. package/dist/agent-src/guidelines/augment-portability-patterns.md +70 -0
  166. package/dist/agent-src/guidelines/code-clarity.md +350 -0
  167. package/dist/agent-src/guidelines/component-oriented-and-oop-development.md +189 -0
  168. package/dist/agent-src/guidelines/cross-role-handoff.md +127 -0
  169. package/dist/agent-src/guidelines/design-antipatterns-triggers.json +18 -0
  170. package/dist/agent-src/guidelines/design-antipatterns.md +327 -0
  171. package/dist/agent-src/guidelines/design-asset-discipline.md +38 -0
  172. package/dist/agent-src/guidelines/design-canon.md +63 -0
  173. package/dist/agent-src/guidelines/design-fidelity-mechanics.md +293 -0
  174. package/dist/agent-src/guidelines/design-fidelity-routing.md +78 -0
  175. package/dist/agent-src/guidelines/design-handover-extraction.md +117 -0
  176. package/dist/agent-src/guidelines/design-modes.md +143 -0
  177. package/dist/agent-src/guidelines/design-reconciliation.md +172 -0
  178. package/dist/agent-src/guidelines/docs/readme-size-and-splitting.md +209 -0
  179. package/dist/agent-src/guidelines/e2e/playwright.md +363 -0
  180. package/dist/agent-src/guidelines/gtm-handoff.md +114 -0
  181. package/dist/agent-src/guidelines/monorepo-antipatterns.md +141 -0
  182. package/dist/agent-src/guidelines/php/api-design.md +115 -0
  183. package/dist/agent-src/guidelines/php/artisan-commands.md +81 -0
  184. package/dist/agent-src/guidelines/php/blade-ui.md +78 -0
  185. package/dist/agent-src/guidelines/php/controllers.md +90 -0
  186. package/dist/agent-src/guidelines/php/database.md +194 -0
  187. package/dist/agent-src/guidelines/php/eloquent.md +208 -0
  188. package/dist/agent-src/guidelines/php/flux.md +80 -0
  189. package/dist/agent-src/guidelines/php/general.md +207 -0
  190. package/dist/agent-src/guidelines/php/git.md +164 -0
  191. package/dist/agent-src/guidelines/php/jobs.md +111 -0
  192. package/dist/agent-src/guidelines/php/livewire.md +71 -0
  193. package/dist/agent-src/guidelines/php/logging.md +79 -0
  194. package/dist/agent-src/guidelines/php/naming.md +89 -0
  195. package/dist/agent-src/guidelines/php/patterns/dependency-injection.md +57 -0
  196. package/dist/agent-src/guidelines/php/patterns/dtos.md +199 -0
  197. package/dist/agent-src/guidelines/php/patterns/events.md +67 -0
  198. package/dist/agent-src/guidelines/php/patterns/factory.md +53 -0
  199. package/dist/agent-src/guidelines/php/patterns/pipelines.md +66 -0
  200. package/dist/agent-src/guidelines/php/patterns/policies.md +66 -0
  201. package/dist/agent-src/guidelines/php/patterns/repositories.md +122 -0
  202. package/dist/agent-src/guidelines/php/patterns/service-layer.md +64 -0
  203. package/dist/agent-src/guidelines/php/patterns/strategy.md +247 -0
  204. package/dist/agent-src/guidelines/php/patterns.md +28 -0
  205. package/dist/agent-src/guidelines/php/performance.md +92 -0
  206. package/dist/agent-src/guidelines/php/php-coding-patterns.md +80 -0
  207. package/dist/agent-src/guidelines/php/resources.md +100 -0
  208. package/dist/agent-src/guidelines/php/security.md +110 -0
  209. package/dist/agent-src/guidelines/php/sql.md +97 -0
  210. package/dist/agent-src/guidelines/php/validations.md +119 -0
  211. package/dist/agent-src/guidelines/php/websocket.md +100 -0
  212. package/dist/agent-src/guidelines/prompt-templates.md +189 -0
  213. package/dist/agent-src/guidelines/redundancy-taxonomy.md +208 -0
  214. package/dist/agent-src/guidelines/wing4-handoff.md +127 -0
  215. package/dist/agent-src/personas/README.md +1 -1
  216. package/dist/agent-src/personas/_template-specialist/persona.md +1 -1
  217. package/dist/agent-src/personas/product-owner.md +1 -1
  218. package/dist/agent-src/rules/active-remediation.md +1 -1
  219. package/dist/agent-src/rules/architecture.md +2 -2
  220. package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
  221. package/dist/agent-src/rules/ask-when-uncertain.md +2 -2
  222. package/dist/agent-src/rules/brand-source-of-truth.md +9 -7
  223. package/dist/agent-src/rules/code-comment-discipline.md +2 -2
  224. package/dist/agent-src/rules/code-provenance.md +1 -1
  225. package/dist/agent-src/rules/content-quoting-floor.md +1 -1
  226. package/dist/agent-src/rules/context-hygiene.md +5 -5
  227. package/dist/agent-src/rules/cross-source-consistency.md +1 -1
  228. package/dist/agent-src/rules/design-fidelity.md +36 -46
  229. package/dist/agent-src/rules/direct-answers.md +2 -2
  230. package/dist/agent-src/rules/domain-adoption-policy.md +1 -1
  231. package/dist/agent-src/rules/evaluator-independence.md +1 -1
  232. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +1 -1
  233. package/dist/agent-src/rules/icon-consistency.md +5 -1
  234. package/dist/agent-src/rules/improve-before-implement.md +1 -1
  235. package/dist/agent-src/rules/language-and-tone.md +3 -3
  236. package/dist/agent-src/rules/minimal-safe-diff.md +1 -1
  237. package/dist/agent-src/rules/notes-first-reasoning.md +36 -25
  238. package/dist/agent-src/rules/recurring-criticism.md +1 -1
  239. package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
  240. package/dist/agent-src/rules/role-mode-adherence.md +2 -2
  241. package/dist/agent-src/rules/security-sensitive-stop.md +1 -1
  242. package/dist/agent-src/rules/size-enforcement.md +1 -1
  243. package/dist/agent-src/rules/source-confidentiality.md +2 -2
  244. package/dist/agent-src/rules/think-before-action.md +1 -1
  245. package/dist/agent-src/rules/token-efficiency.md +7 -5
  246. package/dist/agent-src/rules/ui-audit-gate.md +3 -2
  247. package/dist/agent-src/rules/untrusted-input-defense.md +3 -3
  248. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +106 -4
  249. package/dist/agent-src/skills/activation-design/SKILL.md +2 -2
  250. package/dist/agent-src/skills/adr-create/SKILL.md +5 -5
  251. package/dist/agent-src/skills/ai-council/SKILL.md +1 -1
  252. package/dist/agent-src/skills/ai-council/references/advanced-modes.md +1 -1
  253. package/dist/agent-src/skills/blade-ui/SKILL.md +1 -1
  254. package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +1 -1
  255. package/dist/agent-src/skills/brand-to-tokens/SKILL.md +24 -3
  256. package/dist/agent-src/skills/bug-analyzer/SKILL.md +1 -1
  257. package/dist/agent-src/skills/build-buy-partner/SKILL.md +1 -1
  258. package/dist/agent-src/skills/churn-prevention/SKILL.md +2 -2
  259. package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -1
  260. package/dist/agent-src/skills/code-refactoring/SKILL.md +3 -3
  261. package/dist/agent-src/skills/code-review/SKILL.md +3 -3
  262. package/dist/agent-src/skills/command-writing/SKILL.md +3 -3
  263. package/dist/agent-src/skills/comp-banding/SKILL.md +1 -1
  264. package/dist/agent-src/skills/competitive-moat-analysis/SKILL.md +1 -1
  265. package/dist/agent-src/skills/competitive-positioning/SKILL.md +2 -2
  266. package/dist/agent-src/skills/complexity-first-planning/SKILL.md +1 -1
  267. package/dist/agent-src/skills/condense-memory/SKILL.md +1 -1
  268. package/dist/agent-src/skills/content-funnel-design/SKILL.md +2 -2
  269. package/dist/agent-src/skills/contracts-cognition/SKILL.md +1 -1
  270. package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +2 -2
  271. package/dist/agent-src/skills/corpus-grounding/SKILL.md +2 -2
  272. package/dist/agent-src/skills/customer-research/SKILL.md +2 -2
  273. package/dist/agent-src/skills/dashboard-design/SKILL.md +1 -1
  274. package/dist/agent-src/skills/data-handling-judgment/SKILL.md +1 -1
  275. package/dist/agent-src/skills/deal-qualification-meddic/SKILL.md +2 -2
  276. package/dist/agent-src/skills/decision-record/SKILL.md +3 -3
  277. package/dist/agent-src/skills/decision-review/SKILL.md +8 -8
  278. package/dist/agent-src/skills/deep-reading-analyst/SKILL.md +22 -22
  279. package/dist/agent-src/skills/design-intelligence/SKILL.md +4 -4
  280. package/dist/agent-src/skills/design-intelligence/references/context-and-registers.md +2 -2
  281. package/dist/agent-src/skills/design-review/SKILL.md +4 -4
  282. package/dist/agent-src/skills/design-system-capture/references/design-system-json.md +20 -1
  283. package/dist/agent-src/skills/design-tokens/SKILL.md +17 -2
  284. package/dist/agent-src/skills/design-variations/SKILL.md +2 -2
  285. package/dist/agent-src/skills/developer-like-execution/SKILL.md +2 -2
  286. package/dist/agent-src/skills/discovery-interview/SKILL.md +2 -2
  287. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +3 -3
  288. package/dist/agent-src/skills/editorial-calendar/SKILL.md +2 -2
  289. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +44 -1
  290. package/dist/agent-src/skills/existing-ui-audit/references/anti-slop-cross-reference.md +2 -2
  291. package/dist/agent-src/skills/expansion-playbook/SKILL.md +2 -2
  292. package/dist/agent-src/skills/experiment-loop/SKILL.md +1 -1
  293. package/dist/agent-src/skills/experiment-loop/references/protocol.md +1 -1
  294. package/dist/agent-src/skills/fe-design/SKILL.md +3 -3
  295. package/dist/agent-src/skills/fe-design/references/design-patterns.md +1 -1
  296. package/dist/agent-src/skills/fe-design/references/design-read-and-memory.md +3 -3
  297. package/dist/agent-src/skills/fe-design/references/source-led-port.md +1 -1
  298. package/dist/agent-src/skills/feature-planning/SKILL.md +1 -1
  299. package/dist/agent-src/skills/flux/SKILL.md +1 -1
  300. package/dist/agent-src/skills/forecast-accuracy/SKILL.md +2 -2
  301. package/dist/agent-src/skills/forecasting/SKILL.md +2 -2
  302. package/dist/agent-src/skills/fundraising-narrative/SKILL.md +2 -2
  303. package/dist/agent-src/skills/funnel-analysis/SKILL.md +2 -2
  304. package/dist/agent-src/skills/git-workflow/references/push-closes-its-loop.md +9 -0
  305. package/dist/agent-src/skills/gtm-launch/SKILL.md +2 -2
  306. package/dist/agent-src/skills/hiring-loop-design/SKILL.md +1 -1
  307. package/dist/agent-src/skills/html-deck/SKILL.md +5 -5
  308. package/dist/agent-src/skills/humanizer/SKILL.md +1 -1
  309. package/dist/agent-src/skills/humanizer/data/patterns.md +1 -1
  310. package/dist/agent-src/skills/iconography/SKILL.md +3 -3
  311. package/dist/agent-src/skills/judge-synthesis/SKILL.md +1 -1
  312. package/dist/agent-src/skills/laravel-api-endpoint/SKILL.md +2 -2
  313. package/dist/agent-src/skills/launch-readiness/SKILL.md +3 -3
  314. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +6 -6
  315. package/dist/agent-src/skills/livewire/SKILL.md +1 -1
  316. package/dist/agent-src/skills/market-entry-analysis/SKILL.md +1 -1
  317. package/dist/agent-src/skills/mcp-builder/SKILL.md +1 -1
  318. package/dist/agent-src/skills/memory-consolidation/SKILL.md +3 -3
  319. package/dist/agent-src/skills/messaging-architecture/SKILL.md +2 -2
  320. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
  321. package/dist/agent-src/skills/onboarding-design/SKILL.md +2 -2
  322. package/dist/agent-src/skills/onboarding-program/SKILL.md +1 -1
  323. package/dist/agent-src/skills/one-on-one-cadence/SKILL.md +1 -1
  324. package/dist/agent-src/skills/org-design/SKILL.md +1 -1
  325. package/dist/agent-src/skills/overbuild-review-lens/SKILL.md +3 -3
  326. package/dist/agent-src/skills/override-management/SKILL.md +1 -1
  327. package/dist/agent-src/skills/perf-feedback-craft/SKILL.md +1 -1
  328. package/dist/agent-src/skills/persona-writing/SKILL.md +1 -1
  329. package/dist/agent-src/skills/php-coder/SKILL.md +1 -1
  330. package/dist/agent-src/skills/pipeline-strategy/SKILL.md +2 -2
  331. package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -3
  332. package/dist/agent-src/skills/po-discovery/SKILL.md +1 -1
  333. package/dist/agent-src/skills/positioning-strategy/SKILL.md +2 -2
  334. package/dist/agent-src/skills/privacy-review/SKILL.md +1 -1
  335. package/dist/agent-src/skills/prompt-optimizer/SKILL.md +3 -3
  336. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  337. package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +2 -2
  338. package/dist/agent-src/skills/receiving-code-review/SKILL.md +1 -1
  339. package/dist/agent-src/skills/refine-ticket/SKILL.md +2 -2
  340. package/dist/agent-src/skills/release-comms/SKILL.md +2 -2
  341. package/dist/agent-src/skills/retention-loops/SKILL.md +2 -2
  342. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  343. package/dist/agent-src/skills/roadmap-management/SKILL.md +1 -1
  344. package/dist/agent-src/skills/roadmap-management/references/archival.md +1 -1
  345. package/dist/agent-src/skills/roadmap-writing/SKILL.md +5 -5
  346. package/dist/agent-src/skills/rule-writing/SKILL.md +6 -6
  347. package/dist/agent-src/skills/runway-cognition/SKILL.md +2 -2
  348. package/dist/agent-src/skills/scenario-modeling/SKILL.md +2 -2
  349. package/dist/agent-src/skills/skill-writing/SKILL.md +2 -2
  350. package/dist/agent-src/skills/skill-writing/references/procedure.md +1 -1
  351. package/dist/agent-src/skills/skill-writing/references/section-patterns.md +3 -3
  352. package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +1 -1
  353. package/dist/agent-src/skills/stakeholder-tradeoff/SKILL.md +3 -3
  354. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
  355. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +1 -1
  356. package/dist/agent-src/skills/systematic-debugging/SKILL.md +2 -2
  357. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +60 -4
  358. package/dist/agent-src/skills/throughput-vs-morale-tradeoff/SKILL.md +1 -1
  359. package/dist/agent-src/skills/token-optimizer/SKILL.md +1 -1
  360. package/dist/agent-src/skills/typography-system/SKILL.md +2 -2
  361. package/dist/agent-src/skills/ui-component-architect/SKILL.md +28 -8
  362. package/dist/agent-src/skills/unit-economics-modeling/SKILL.md +2 -2
  363. package/dist/agent-src/skills/upstream-contribute/SKILL.md +1 -1
  364. package/dist/agent-src/skills/validate-feature-fit/SKILL.md +2 -2
  365. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +2 -2
  366. package/dist/agent-src/skills/vision-articulation/SKILL.md +1 -1
  367. package/dist/agent-src/skills/voc-extract/SKILL.md +2 -2
  368. package/dist/agent-src/skills/voice-and-tone-design/SKILL.md +2 -2
  369. package/dist/agent-src/skills/wireframe/SKILL.md +1 -1
  370. package/dist/agent-src/skills/workspace-link/SKILL.md +1 -1
  371. package/dist/agent-src/templates/agent-settings.md +6 -6
  372. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  373. package/dist/agent-src/templates/contexts/knowledge-pages.md +2 -3
  374. package/dist/agent-src/templates/copilot-instructions.md +1 -1
  375. package/dist/agent-src/templates/roadmaps.md +1 -1
  376. package/dist/agent-src/templates/scripts/README.md +2 -2
  377. package/dist/agent-src/user-types/_template/user-type.md +1 -1
  378. package/dist/cli/registry.js +1 -1
  379. package/dist/cli-delegate/archive_completed_roadmaps.js +52 -4
  380. package/dist/cli-delegate/check_update_banner.js +12 -1
  381. package/dist/cli-delegate/{chunk-TGIPZBCW.js → chunk-2KKXJW25.js} +22 -8
  382. package/dist/cli-delegate/{chunk-NLP54U3J.js → chunk-2XY7ILBT.js} +13 -1
  383. package/dist/cli-delegate/{chunk-4FS4WRXP.js → chunk-3FKR64R5.js} +34 -6
  384. package/dist/cli-delegate/{chunk-J3RFNKG4.js → chunk-55ACLDUE.js} +2 -2
  385. package/dist/cli-delegate/{chunk-PKOBQADP.js → chunk-57PN4GYJ.js} +1 -1
  386. package/dist/cli-delegate/{chunk-BIXEDQPZ.js → chunk-AK6HODNQ.js} +4 -4
  387. package/dist/cli-delegate/{chunk-2FTMENJL.js → chunk-GYC3VRYN.js} +1 -1
  388. package/dist/cli-delegate/{chunk-LWTYTX6F.js → chunk-HZ52BRGG.js} +24 -18
  389. package/dist/cli-delegate/{chunk-6RJA2F5A.js → chunk-IVBPRCQO.js} +1 -1
  390. package/dist/cli-delegate/{chunk-I6RHFQEG.js → chunk-YUM5KURG.js} +17 -1
  391. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  392. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  393. package/dist/cli-delegate/cmd_conformance.js +3 -3
  394. package/dist/cli-delegate/cmd_doctor.js +3 -3
  395. package/dist/cli-delegate/cmd_explain.js +2 -2
  396. package/dist/cli-delegate/cmd_export.js +4 -4
  397. package/dist/cli-delegate/cmd_handoff.js +24 -16
  398. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  399. package/dist/cli-delegate/cmd_memory_get.js +1 -1
  400. package/dist/cli-delegate/cmd_migrate.js +2 -2
  401. package/dist/cli-delegate/cmd_packs_active.js +2 -2
  402. package/dist/cli-delegate/cmd_prune.js +4 -4
  403. package/dist/cli-delegate/cmd_route_audit.js +3 -3
  404. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  405. package/dist/cli-delegate/cmd_session_recycle.js +4 -14
  406. package/dist/cli-delegate/cmd_settings_get.js +15 -9
  407. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  408. package/dist/cli-delegate/cmd_settings_set.js +41 -11
  409. package/dist/cli-delegate/cmd_sync.js +4 -4
  410. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  411. package/dist/cli-delegate/cmd_update.js +1 -1
  412. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  413. package/dist/cli-delegate/cmd_validate.js +4 -4
  414. package/dist/cli-delegate/cmd_versions.js +1 -1
  415. package/dist/discovery/deprecation-report.md +1 -1
  416. package/dist/discovery/discovery-manifest.json +27 -80
  417. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  418. package/dist/discovery/discovery-manifest.summary.md +3 -3
  419. package/dist/discovery/dormancy-report.md +1 -1
  420. package/dist/discovery/orphan-report.md +1 -1
  421. package/dist/discovery/packs.json +5 -7
  422. package/dist/discovery/trust-report.md +2 -2
  423. package/dist/discovery/workspaces.json +4 -6
  424. package/dist/hooks/dispatch.js +9249 -8981
  425. package/dist/install/install.mjs +47 -8
  426. package/dist/mcp/registry-manifest.json +3 -3
  427. package/dist/mcp/server.json +2 -2
  428. package/dist/mcp/server.mjs +5496 -2400
  429. package/dist/router.json +1 -1
  430. package/dist/scripts/_lib/agent_settings.js +73 -0
  431. package/dist/scripts/_lib/agent_src.js +20 -0
  432. package/dist/scripts/_lib/guidelines_lane.js +158 -0
  433. package/dist/scripts/_lib/lean_projection_mode.js +108 -0
  434. package/dist/scripts/_lib/router_match.js +243 -0
  435. package/dist/scripts/_lib/rule_injection.js +216 -0
  436. package/dist/scripts/condense.js +22 -25
  437. package/dist/scripts/project_thin_rules.js +139 -19
  438. package/dist/server/io/yamlIO.js +125 -17
  439. package/dist/server/schemas/settings.js +32 -5
  440. package/dist/shared/settingsSurface.js +6 -1
  441. package/docs/MIGRATION.md +56 -0
  442. package/docs/contracts/settings-classes.md +48 -7
  443. package/docs/guidelines/abstraction-thresholds.md +35 -0
  444. package/docs/guidelines/agent-infra/active-remediation-mechanics.md +3 -3
  445. package/docs/guidelines/agent-infra/false-green.md +2 -2
  446. package/docs/guidelines/agent-infra/notes-horizon-mechanics.md +90 -0
  447. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  448. package/docs/guidelines/agent-infra/skill-quality-checklist.md +1 -1
  449. package/docs/guidelines/design-fidelity-mechanics.md +4 -0
  450. package/docs/guidelines/design-fidelity-routing.md +78 -0
  451. package/docs/guidelines/design-reconciliation.md +172 -0
  452. package/docs/guidelines/gtm-handoff.md +2 -2
  453. package/docs/guidelines/wing4-handoff.md +2 -2
  454. package/llms.txt +1 -1
  455. package/package.json +7 -3
  456. package/src/agent-src/scripts/archive_completed_roadmaps.ts +106 -4
  457. package/src/config/agent-settings.template.yml +94 -1
  458. package/src/config/ci-local-parity.yml +34 -0
  459. package/src/config/continuity-surface.json +8 -29
  460. package/src/config/evaluator-budgets.json +4 -4
  461. package/src/config/gate-coverage.yml +31 -8
  462. package/src/config/gate-reachability-exemptions.json +1 -0
  463. package/src/config/gate-violation-baselines.json +3 -3
  464. package/src/config/hook-token-budget.json +8 -7
  465. package/src/config/host-injection-effect.json +2 -2
  466. package/src/config/pack-size-budget.json +55 -4
  467. package/src/config/packed-binary-manifest.json +1 -1
  468. package/src/config/platform-anchor.json +47 -0
  469. package/src/config/preamble-payload-budget.json +2 -3
  470. package/src/config/publish-surface.json +4 -2
  471. package/src/config/ratification-policy.json +7 -0
  472. package/src/config/routing-coverage-seed.json +9 -2
  473. package/src/config/rule-stub-ceilings.json +16 -9
  474. package/src/scripts/_cli/cmd_session_recycle.ts +2 -25
  475. package/src/scripts/_cli/cmd_settings_get.ts +22 -7
  476. package/src/scripts/_cli/handoff_sessions.ts +14 -44
  477. package/src/scripts/_lib/agent_settings.ts +85 -0
  478. package/src/scripts/_lib/agent_src.ts +21 -0
  479. package/src/scripts/_lib/artifact_maturity.ts +242 -0
  480. package/src/scripts/_lib/conformance_report.ts +403 -0
  481. package/src/scripts/_lib/continuity_slot.ts +295 -0
  482. package/src/scripts/_lib/continuity_writer.ts +312 -0
  483. package/src/scripts/_lib/design_system_import.ts +20 -0
  484. package/src/scripts/_lib/design_tolerance.ts +281 -0
  485. package/src/scripts/_lib/guidelines_lane.ts +164 -0
  486. package/src/scripts/_lib/hook_settings.ts +85 -0
  487. package/src/scripts/_lib/lean_projection_mode.ts +127 -0
  488. package/src/scripts/_lib/obligation_frequency.ts +2 -3
  489. package/src/scripts/_lib/packed_binary_predicate.ts +37 -0
  490. package/src/scripts/_lib/platform_anchor.ts +1053 -0
  491. package/src/scripts/_lib/ratification_artifact.ts +278 -0
  492. package/src/scripts/_lib/recycle_envelope_paths.ts +109 -21
  493. package/src/scripts/_lib/regression_neighbourhood.ts +159 -22
  494. package/src/scripts/_lib/security_lint.ts +23 -2
  495. package/src/scripts/_lib/self_repair.ts +21 -0
  496. package/src/scripts/_lib/session_eol.ts +44 -0
  497. package/src/scripts/_lib/session_index_trust.ts +387 -0
  498. package/src/scripts/_lib/standing_bound_ratchet.ts +220 -0
  499. package/src/scripts/_lib/tolerance_shadow.ts +177 -0
  500. package/src/scripts/_lib/vendored_grammar_upstream.ts +280 -0
  501. package/src/scripts/ai_council/redact_low_impact_entry.ts +8 -0
  502. package/src/scripts/audit_mcp_tools.ts +69 -25
  503. package/src/scripts/autonomy_friction_traffic.ts +379 -0
  504. package/src/scripts/build_mcp_catalog.ts +24 -1
  505. package/src/scripts/check_host_tree_parity.ts +291 -0
  506. package/src/scripts/check_kernel_edit_ratified.ts +462 -0
  507. package/src/scripts/check_loss_class_declared.ts +793 -46
  508. package/src/scripts/check_platform_anchor.ts +390 -0
  509. package/src/scripts/check_preamble_payload_budget.ts +424 -7
  510. package/src/scripts/check_projected_rule_routes.ts +395 -0
  511. package/src/scripts/check_rule_projection_integrity.ts +102 -2
  512. package/src/scripts/ci_settle.ts +205 -5
  513. package/src/scripts/code_graph/build.ts +79 -0
  514. package/src/scripts/code_graph/cli.ts +264 -7
  515. package/src/scripts/code_graph/detect.ts +38 -0
  516. package/src/scripts/code_graph/query.ts +25 -2
  517. package/src/scripts/code_graph/sqlite_store.ts +16 -1
  518. package/src/scripts/code_graph/types.ts +52 -3
  519. package/src/scripts/code_graph/validate.ts +3 -1
  520. package/src/scripts/code_graph/verbs.ts +590 -0
  521. package/src/scripts/condense.ts +22 -26
  522. package/src/scripts/generate_host_cost_table.ts +354 -0
  523. package/src/scripts/handoff_context_hook.ts +39 -1
  524. package/src/scripts/hook_manifest.json +1 -1
  525. package/src/scripts/hook_manifest.yaml +59 -28
  526. package/src/scripts/hooks/block_speaking_inbox_dir.ts +182 -16
  527. package/src/scripts/hooks/category_a.ts +1 -1
  528. package/src/scripts/hooks/chain_nudge_hook.ts +311 -25
  529. package/src/scripts/hooks/code_graph_context_hook.ts +7 -18
  530. package/src/scripts/hooks/push_settle_hook.ts +3 -2
  531. package/src/scripts/hooks/rule_inject_hook.ts +107 -20
  532. package/src/scripts/hooks/session_eol_hook.ts +177 -145
  533. package/src/scripts/hooks/source_first_gate_hook.ts +12 -0
  534. package/src/scripts/hooks/ui_route_nudge_hook.ts +52 -15
  535. package/src/scripts/hot_context_hook.ts +103 -408
  536. package/src/scripts/lint_evidence_artifacts.ts +1 -0
  537. package/src/scripts/lint_knowledge_scale.ts +0 -26
  538. package/src/scripts/lint_roadmap_blockers.ts +164 -1
  539. package/src/scripts/mcp_server/consumer_tool_catalog.json +152 -2
  540. package/src/scripts/mcp_server/graph_tools.ts +294 -0
  541. package/src/scripts/mcp_server/path_util.ts +31 -0
  542. package/src/scripts/mcp_server/tool_catalog_source.ts +7 -1
  543. package/src/scripts/mcp_server/tools.ts +3 -13
  544. package/src/scripts/memory_lookup.ts +9 -9
  545. package/src/scripts/model_rule_injection.ts +61 -4
  546. package/src/scripts/project_thin_rules.ts +149 -16
  547. package/src/scripts/report_standing_payload_by_host.ts +650 -0
  548. package/src/scripts/schemas/agent-settings.schema.json +7 -1
  549. package/src/scripts/session_memory_index.ts +86 -8
  550. package/src/scripts/sync_agent_settings.ts +270 -10
  551. package/src/server/io/yamlIO.ts +127 -17
  552. package/src/server/schemas/settings.ts +45 -6
  553. package/src/shared/settingsSurface.ts +13 -2
  554. package/src/templates/compact-instructions.md +8 -3
  555. package/src/vendor/grammars/README.md +27 -2
  556. package/dist/agent-src/commands/chat-history/import.md +0 -170
  557. package/dist/agent-src/commands/chat-history.md +0 -63
@@ -18,11 +18,37 @@
18
18
  * a shape that cannot be written as an allowlist pattern at all. That class
19
19
  * shrinks only by not writing it.
20
20
  *
21
+ * THE SECOND CLASS, AND WHY IT BELONGS HERE. A Bash command that writes a
22
+ * file — `sed -i`, `cat > f`, `tee f`, `perl -i`, a `python3 -c` that opens a
23
+ * path for writing — costs a confirmation for a reason no allowlist entry
24
+ * fixes: a write-shaped Bash grant does NOT persist. The host's own
25
+ * permission documentation records that "don't ask again" saves a permanent
26
+ * rule for read-only and pre-approved commands and that write-shaped ones
27
+ * last until session end, so the same shape is confirmed again next session.
28
+ * The Edit and Write tools carry no such expiry for a path inside the working
29
+ * directory. That makes the substitution a strictly cheaper primitive rather
30
+ * than a style preference, which is why the concern that already reads
31
+ * `tool_input.command` carries it instead of a second concern reading the
32
+ * same field. Measured on 2026-09-10 over 7,569 distinct real Bash calls in
33
+ * 39 transcripts on the maintainer's machine: 306 (4.0 %) wrote a file
34
+ * through the shell — 216 `cat >`, 66 `sed -i`, 16 `python3 -c` with a
35
+ * write-mode `open`, 7 `perl -i`, 1 `tee`. Recompute with
36
+ * `./scripts-run src/scripts/autonomy_friction_traffic`, which shares these
37
+ * detectors; every figure in this change comes from that one run.
38
+ *
39
+ * THE COUNT IS A FLOOR, and the five rules are why. `echo >`, `printf >`,
40
+ * `jq >`, `awk >`, `git show >` and `cp` all fill a file and none is matched:
41
+ * the list is positive by design, and a generic redirect scanner would fire on
42
+ * `grep x f > out.txt`, where the shell is not the thing doing the writing.
43
+ * A heredoc whose BODY performs the write is invisible for the same reason the
44
+ * body is stripped at all. Read 4.0 % as "at least".
45
+ *
21
46
  * WHAT IT DOES NOT FLAG, DELIBERATELY. A pipe of ordinary filters
22
47
  * (`grep foo file | head`) is one command with a filter, not two work steps.
23
- * A redirect has its target checked against the file rules on its own. A
24
- * heredoc is a command with input. Flagging any of those would make the
25
- * nudge noise, and a nudge that fires on correct usage is worse than none.
48
+ * A redirect whose target is not a file the shell is filling with content —
49
+ * `2>&1`, `> /dev/null` — is not a write. A heredoc is a command with input.
50
+ * Flagging any of those would make the nudge noise, and a nudge that fires on
51
+ * correct usage is worse than none.
26
52
  *
27
53
  * NEVER BLOCKS. The dispatcher contract is 0 allow · 2 warn, and a warn on
28
54
  * `pre_tool_use` with `severity: advisory` is an injection, not a deny — the
@@ -30,10 +56,23 @@
30
56
  * failure path returns allow: unreadable stdin, malformed JSON, unwritable
31
57
  * latch. A token optimisation must never break a tool call.
32
58
  *
33
- * ONCE PER SESSION. A latch keyed by session id, in the state directory
34
- * `code-graph-nudge.json` already occupies. The rule body reaches the model
35
- * once, early, on the first chained call — repeating it every call would be
36
- * the nagging this codebase refuses elsewhere.
59
+ * ONCE PER SHAPE CLASS PER SESSION. A latch keyed by session id, in the state
60
+ * directory `code-graph-nudge.json` already occupies. Each class reaches the
61
+ * model once, early, on the first call carrying it — so a session sees at most
62
+ * two lines, never one line for two different mistakes.
63
+ *
64
+ * That is a per-CLASS latch, not a per-CALL one, and the distinction is the
65
+ * whole reason it is allowed to change: the recorded decision this file
66
+ * carried refuses "repeating it every call", which is the nagging this
67
+ * codebase refuses elsewhere, and a second class firing once is a different
68
+ * mechanism from a first class firing twice. The single-boolean latch was
69
+ * written when there was one class; with two, it would have let whichever
70
+ * shape came first silence the other for the rest of the session.
71
+ *
72
+ * A latch file written by the single-class version holds `true` rather than an
73
+ * object. That is read as "the chain class has fired", which is what it meant,
74
+ * so an in-flight session upgrades without losing its latch and without
75
+ * replaying a line it already showed.
37
76
  *
38
77
  * ON BY DEFAULT, WITH AN OPT-OUT. Unlike `code-graph-nudge`, which gates on a
39
78
  * project capability that may not exist, the fact this nudge carries is a
@@ -137,14 +176,208 @@ export function stripLiterals(cmd: string): string {
137
176
  return out;
138
177
  }
139
178
 
179
+ /**
180
+ * Heredoc BODIES removed, the command line they sit on kept.
181
+ *
182
+ * `stripLiterals` runs from `<<` to the closing tag and so deletes the redirect
183
+ * that shares the command line; leaving the body in instead let a heredoc that
184
+ * merely MENTIONS a write shape fire the nudge and spend the session's one
185
+ * write line. Neither view is right for the write rules, so this is the third:
186
+ * the marker and the rest of the command line survive, the body does not.
187
+ *
188
+ * Consequence, stated because it is a real false negative: a heredoc whose BODY
189
+ * performs the write — `python3 - <<PY` opening a path — is invisible here. The
190
+ * class is a floor, and this is one of the reasons.
191
+ */
192
+ export function stripHeredocBodies(cmd: string): string {
193
+ const marker = /<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/g;
194
+ let out = '';
195
+ let cursor = 0;
196
+ let m: RegExpExecArray | null;
197
+ while ((m = marker.exec(cmd)) !== null) {
198
+ const tag = m[2] as string;
199
+ const nl = cmd.indexOf('\n', m.index + m[0].length);
200
+ if (nl === -1) break;
201
+ const close = cmd.indexOf(`\n${tag}`, nl);
202
+ const end = close === -1 ? cmd.length : close + tag.length + 1;
203
+ out += cmd.slice(cursor, m.index) + '<<' + cmd.slice(m.index + m[0].length, nl);
204
+ cursor = end;
205
+ marker.lastIndex = end;
206
+ }
207
+ return out + cmd.slice(cursor);
208
+ }
209
+
210
+ /**
211
+ * Quoted spans removed, heredoc bodies LEFT IN PLACE.
212
+ *
213
+ * The sibling of `stripLiterals` for the write rules. That one must consume a
214
+ * heredoc, because an operator in its body is not chaining; this one must not,
215
+ * because the heredoc marker and the redirect share a command line and
216
+ * consuming to the closing tag takes the redirect with it.
217
+ */
218
+ export function stripQuoted(cmd: string): string {
219
+ let out = '';
220
+ let i = 0;
221
+ let quote: string | null = null;
222
+ while (i < cmd.length) {
223
+ const c = cmd[i] as string;
224
+ if (quote) {
225
+ if (c === '\\' && quote === '"') {
226
+ i += 2;
227
+ continue;
228
+ }
229
+ if (c === quote) quote = null;
230
+ i += 1;
231
+ continue;
232
+ }
233
+ if (c === '\\') {
234
+ i += 2;
235
+ continue;
236
+ }
237
+ if (c === '"' || c === "'") {
238
+ quote = c;
239
+ i += 1;
240
+ continue;
241
+ }
242
+ out += c;
243
+ i += 1;
244
+ }
245
+ return out;
246
+ }
247
+
140
248
  /** What the nudge saw, or null when the command is not chained work. */
141
249
  export function detectChaining(command: string): string | null {
142
- const bare = stripLiterals(command);
250
+ return _detectChaining(stripLiterals(command));
251
+ }
252
+
253
+ function _detectChaining(bare: string): string | null {
143
254
  if (/^\s*[A-Za-z_][A-Za-z0-9_]*=/.test(bare) && /[;\n]/.test(bare)) {
144
255
  return 'a leading `VAR=…` assignment carrying state into a later segment';
145
256
  }
146
257
  if (/&&|\|\|/.test(bare)) return 'work steps chained with `&&` / `||`';
147
258
  if (/;\s*\S/.test(bare)) return 'work steps chained with `;`';
259
+ // The header names newlines among the host's split points and this rule did
260
+ // not read them, so `git status\ngit diff` — two work steps by any reading —
261
+ // was silent. Heredoc bodies are already gone from this view, so a
262
+ // multi-line heredoc command does not reach here.
263
+ if (/\n\s*\S/.test(bare)) return 'work steps separated by a newline';
264
+ return null;
265
+ }
266
+
267
+ /**
268
+ * The five shapes that fill a file's content from the shell, each matched on
269
+ * the literal-stripped command so a quoted mention cannot fire it.
270
+ *
271
+ * A positive list, not a redirect scan: `>` alone is a redirect and the header
272
+ * says a redirect is not flagged. What is flagged is a command whose named
273
+ * operation IS "put this content in that path", which is the operation Edit
274
+ * and Write perform without an expiring grant. `/dev/null` and an fd
275
+ * duplication (`2>&1`) are excluded because neither names a file being filled.
276
+ */
277
+ const EDIT_BY_SHELL: ReadonlyArray<{ re: RegExp; seen: string }> = [
278
+ // `-i` may ride inside a flag cluster (`-ri`, `-Ei`) or carry a backup
279
+ // suffix (`-i.bak`), so the letter is matched inside the cluster rather
280
+ // than as a token. `sed -n 2,8p` and `sed -e s/a/b/ f` have no `i` in any
281
+ // flag and stay silent; `--expression=…` cannot match because the class
282
+ // admits letters only after the single leading dash.
283
+ {
284
+ re: /(^|[\s;&|(])sed\s+(?:-\S+\s+)*-(?:i|[nersuzE]*i[nersuzE]*|-in-place)(?:\.\S+)?(?=\s|$)/,
285
+ seen: '`sed -i` edits a file in place',
286
+ },
287
+ // The letter set is closed on purpose. Matching an `i` ANYWHERE in a flag
288
+ // cluster made `perl -Mstrict`, `perl -MList::Util` and `perl -Ilib` all
289
+ // report an in-place edit — the letters after `-M` and `-I` are a module
290
+ // name and a directory, not switches. Only perl's own one-letter switches
291
+ // may share the cluster with `i`.
292
+ {
293
+ re: /(^|[\s;&|(])perl\s+(?:-\S+\s+)*-(?:i|[pnlaw]*i[pnlaw]*)(?:\.\S+)?(?=\s|$)/,
294
+ seen: '`perl -i` edits a file in place',
295
+ },
296
+ // `[^\n]*` between the head and the redirect, so `cat <<'EOF' > out.txt`
297
+ // and `cat a b > merged` both land, while `> /dev/null` and an fd
298
+ // duplication (`2>&1`) are excluded by the lookahead at every position the
299
+ // engine tries.
300
+ // `[^\n|;&]*` — the redirect must belong to the SAME simple command. With
301
+ // `[^\n]*` this rule was a general redirect scanner for any cat-headed
302
+ // pipeline, so `cat f | grep x > out.txt` fired while the identical
303
+ // `grep x f > out.txt` stayed silent, which its own "positive list, not a
304
+ // redirect scan" comment forbids.
305
+ { re: /(^|[\s;&|(])cat\b[^\n|;&]*>{1,2}\s*(?!&|\/dev\/null)\S/, seen: '`cat >` fills a file from the shell' },
306
+ // A flag cluster before the path is normal (`tee -a out.txt`), and the path
307
+ // is REQUIRED. Dropping the original `(?!-)` lookahead to admit the flagged
308
+ // form turned a false negative into a false-positive class: `tee -a`,
309
+ // `foo | tee | wc -l`, `foo | tee -` and `tee -a /dev/null` all fired. The
310
+ // path token is therefore matched explicitly — not a flag, not a shell
311
+ // operator, not the null device.
312
+ {
313
+ re: /(^|[\s;&|(])tee\s+(?:-[A-Za-z]+\s+)*(?!\/dev\/null)[^-\s;&|<>][^\s;&|<>]*/,
314
+ seen: '`tee` writes its input to a file',
315
+ },
316
+ ];
317
+
318
+ /** The interpreter form, split across the two views for the reason below. */
319
+ const PY_AT_COMMAND_POSITION = /(^|[\s;&|(])python3?\s+-c\b/;
320
+ const PY_OPENS_FOR_WRITING = /\bopen\s*\([^)]*['"][wax]\+?['"]/;
321
+
322
+ /**
323
+ * What the write-shaped detector saw, or null when the call writes no file.
324
+ *
325
+ * `stripQuoted` rather than `stripLiterals` for the redirect rules: the
326
+ * heredoc branch of `stripLiterals` runs to the closing tag and swallows the
327
+ * command line with it, so `cat <<'EOF' > out.txt` lost its own redirect and
328
+ * the largest measured write shape went undetected in its most common spelling.
329
+ *
330
+ * The interpreter rule reads BOTH views, and needs to. Its program is a quoted
331
+ * argument, so the write mode is only visible in the raw string; but matching
332
+ * the raw string alone fires on any command that merely QUOTES the shape —
333
+ * `git commit -m "use python3 -c open(p,'w')"` did, and this change ships that
334
+ * exact string in a substitution table. So the interpreter must sit at a
335
+ * command position in the STRIPPED text, where a quoted mention has already
336
+ * been removed, and the write mode must be named in the RAW text.
337
+ */
338
+ export function detectEditByShell(command: string): string | null {
339
+ return _detectEditByShell(command, writeView(command));
340
+ }
341
+
342
+ /** The view the write rules read: no heredoc bodies, no quoted spans. */
343
+ export function writeView(command: string): string {
344
+ return stripQuoted(stripHeredocBodies(command));
345
+ }
346
+
347
+ function _detectEditByShell(command: string, quotesStripped: string): string | null {
348
+ for (const shape of EDIT_BY_SHELL) {
349
+ if (shape.re.test(quotesStripped)) return shape.seen;
350
+ }
351
+ if (PY_AT_COMMAND_POSITION.test(quotesStripped) && PY_OPENS_FOR_WRITING.test(command)) {
352
+ return 'a `python3 -c` one-liner opens a path for writing';
353
+ }
354
+ return null;
355
+ }
356
+
357
+ /** The two shape classes this concern carries. */
358
+ export type NudgeClass = 'edit-by-shell' | 'chain';
359
+
360
+ /** One finding: which class fired, and what it saw. */
361
+ export interface NudgeFinding {
362
+ klass: NudgeClass;
363
+ seen: string;
364
+ }
365
+
366
+ /**
367
+ * The finding for this command, or null.
368
+ *
369
+ * `edit-by-shell` is tested first, and on a call that is both — `cd d && sed
370
+ * -i … f` is — it wins: its line names a primitive that costs no confirmation
371
+ * at all, while the chain line only explains why this one did.
372
+ */
373
+ export function detectShape(command: string): NudgeFinding | null {
374
+ // Each view is built once. This runs on every shell tool call and the
375
+ // header documents 26 ms p95 as load-bearing, so calling the two exported
376
+ // wrappers here would strip the same string twice per call for nothing.
377
+ const write = _detectEditByShell(command, writeView(command));
378
+ if (write) return { klass: 'edit-by-shell', seen: write };
379
+ const chained = _detectChaining(stripLiterals(command));
380
+ if (chained) return { klass: 'chain', seen: chained };
148
381
  return null;
149
382
  }
150
383
 
@@ -190,25 +423,59 @@ function latchFile(root: string): string {
190
423
  return path.join(root, 'agents', 'runtime', 'state', 'chain-nudge.json');
191
424
  }
192
425
 
193
- function alreadyNudged(root: string, session: string): boolean {
426
+ /** One session's latch: the object form, or the pre-two-class `true`. */
427
+ type LatchEntry = boolean | Record<string, boolean>;
428
+
429
+ /**
430
+ * Has `klass` already fired for this session?
431
+ *
432
+ * A legacy `true` is read as the chain class having fired, which is what the
433
+ * single-class version wrote it to mean. The write class is then unlatched in
434
+ * that session and gets its first line — correct, because it never had one.
435
+ */
436
+ export function classAlreadyNudged(entry: LatchEntry | undefined, klass: NudgeClass): boolean {
437
+ if (entry === true) return klass === 'chain';
438
+ if (isObject(entry)) return entry[klass] === true;
439
+ return false;
440
+ }
441
+
442
+ /** `klass` recorded on top of whatever the entry already held. */
443
+ export function withClassLatched(entry: LatchEntry | undefined, klass: NudgeClass): Record<string, boolean> {
444
+ const next: Record<string, boolean> = entry === true ? { chain: true } : isObject(entry) ? { ...(entry as Record<string, boolean>) } : {};
445
+ next[klass] = true;
446
+ return next;
447
+ }
448
+
449
+ /**
450
+ * The latch state, or `{}` for anything that is not a JSON object.
451
+ *
452
+ * The shape check is not decoration. `JSON.parse` returns `null` for a latch
453
+ * file holding `null` and a number for one holding `7`, neither of which throws
454
+ * — so the try/catch alone let a corrupted file reach the caller as a non-object
455
+ * and crash the property read. The helper this replaced guarded that by reading
456
+ * the property inside its own try; consolidating the read dropped the guard, and
457
+ * the header's "every failure path returns allow" stopped being true.
458
+ */
459
+ function readLatch(root: string): Record<string, LatchEntry> {
194
460
  try {
195
- const state = JSON.parse(fs.readFileSync(latchFile(root), 'utf-8')) as Record<string, boolean>;
196
- return state[session] === true;
461
+ const parsed: unknown = JSON.parse(fs.readFileSync(latchFile(root), 'utf-8'));
462
+ return isObject(parsed as JsonValue) ? (parsed as Record<string, LatchEntry>) : {};
197
463
  } catch {
198
- return false;
464
+ return {};
199
465
  }
200
466
  }
201
467
 
202
- function latch(root: string, session: string): void {
468
+ /**
469
+ * Record `klass` into an ALREADY-READ state and persist it.
470
+ *
471
+ * The state is passed in rather than re-read: the caller has just consulted it
472
+ * to decide whether to fire, and reading the same file twice per firing call is
473
+ * the kind of hot-path waste this file's own ordering comment exists to avoid.
474
+ */
475
+ function latch(root: string, session: string, klass: NudgeClass, state: Record<string, LatchEntry>): void {
203
476
  try {
204
477
  const p = latchFile(root);
205
- let state: Record<string, boolean> = {};
206
- try {
207
- state = JSON.parse(fs.readFileSync(p, 'utf-8')) as Record<string, boolean>;
208
- } catch {
209
- /* fresh */
210
- }
211
- state[session] = true;
478
+ state[session] = withClassLatched(state[session], klass);
212
479
  fs.mkdirSync(path.dirname(p), { recursive: true });
213
480
  fs.writeFileSync(p, JSON.stringify(state));
214
481
  } catch {
@@ -216,6 +483,24 @@ function latch(root: string, session: string): void {
216
483
  }
217
484
  }
218
485
 
486
+ /** The write-shape line — names the expiry, then the primitive without one. */
487
+ export function editByShellReason(seen: string): string {
488
+ return (
489
+ `This Bash call writes a file through the shell: ${seen}. A write-shaped ` +
490
+ 'Bash grant does not persist — the host saves a permanent rule for ' +
491
+ 'read-only commands, while a write-shaped one lasts until session end, so ' +
492
+ 'this same shape costs another confirmation next session. Edit and Write ' +
493
+ 'carry no such expiry inside the working directory: Edit for a targeted ' +
494
+ 'change, Write for a new file, the shell for reads. ' +
495
+ 'See `token-efficiency` § One command per Bash call.'
496
+ );
497
+ }
498
+
499
+ /** The line for a finding, dispatched on its class. */
500
+ export function reasonFor(finding: NudgeFinding): string {
501
+ return finding.klass === 'edit-by-shell' ? editByShellReason(finding.seen) : nudgeReason(finding.seen);
502
+ }
503
+
219
504
  /** The nudge line — one line, names what was seen and what to do instead. */
220
505
  export function nudgeReason(seen: string): string {
221
506
  return (
@@ -247,8 +532,8 @@ export function main(): number {
247
532
  const command = bashCommand(envelope);
248
533
  if (!command) return EXIT_ALLOW;
249
534
 
250
- const seen = detectChaining(command);
251
- if (!seen) return EXIT_ALLOW;
535
+ const finding = detectShape(command);
536
+ if (!finding) return EXIT_ALLOW;
252
537
 
253
538
  const cwd = envelope['cwd'];
254
539
  const pr = envelope['workspace_root'] ?? envelope['project_root'];
@@ -256,10 +541,11 @@ export function main(): number {
256
541
  if (!enabled(root)) return EXIT_ALLOW;
257
542
 
258
543
  const session = sessionId(envelope);
259
- if (alreadyNudged(root, session)) return EXIT_ALLOW;
544
+ const state = readLatch(root);
545
+ if (classAlreadyNudged(state[session], finding.klass)) return EXIT_ALLOW;
260
546
 
261
- latch(root, session);
262
- process.stdout.write(`${JSON.stringify({ decision: 'warn', reason: nudgeReason(seen) })}\n`);
547
+ latch(root, session, finding.klass, state);
548
+ process.stdout.write(`${JSON.stringify({ decision: 'warn', reason: reasonFor(finding) })}\n`);
263
549
  return EXIT_WARN;
264
550
  }
265
551
 
@@ -39,7 +39,7 @@ import fs from 'node:fs';
39
39
  import path from 'node:path';
40
40
  import { fileURLToPath, pathToFileURL } from 'node:url';
41
41
 
42
- import { detectSources, pickSource } from '../code_graph/detect.js';
42
+ import { type GraphState, graphState } from '../code_graph/detect.js';
43
43
  import { readHookStdin } from './hook_stdin.js';
44
44
 
45
45
  const EXIT_ALLOW = 0;
@@ -114,26 +114,15 @@ function latch(root: string, session: string): void {
114
114
  }
115
115
  }
116
116
 
117
- const NATIVE_CACHE = path.join('agents', 'runtime', 'state', 'code-graph-v1.json');
118
-
119
- /** The three-state staleness token this hook reports. */
120
- export type GraphState = 'absent' | 'fresh' | `behind:${number}`;
121
-
122
117
  /**
123
- * Resolve the graph's state for `root`.
118
+ * The three-state staleness token this hook reports.
124
119
  *
125
- * `absent` means no source at all — the silent case. A picked source whose
126
- * staleness is UNKNOWN reads as `fresh`, mirroring `computeVerdict`'s own
127
- * `picked.stale ? STALE : FRESH`: unknown is not treated as stale, because
128
- * inventing a commit count would be worse than reporting none.
120
+ * Re-exported, not defined here: Phase 3's verbs must print the same token, and
121
+ * an engine module importing this hook to learn it would invert the dependency
122
+ * direction D9 measures. The definition lives in `code_graph/detect.ts`; this
123
+ * re-export keeps every existing importer of the hook working unchanged.
129
124
  */
130
- export function graphState(root: string): GraphState {
131
- const picked = pickSource(detectSources(root, path.join(root, NATIVE_CACHE)));
132
- if (!picked) return 'absent';
133
- if (picked.stale !== true) return 'fresh';
134
- const behind = picked.commits_behind;
135
- return `behind:${typeof behind === 'number' ? behind : 0}`;
136
- }
125
+ export { type GraphState, graphState };
137
126
 
138
127
  /**
139
128
  * The one line, ≤ ~45 tokens.
@@ -191,8 +191,9 @@ export function buildReminder(branch: string, pr: number | null): { reason: stri
191
191
  `own exit code.\n\n` +
192
192
  `Before this turn ends:\n` +
193
193
  ` 1. Settle it:\n ${settle}\n` +
194
- ` Exit 0 = settled green · 1 = settled, something failed · 2 = NOT a verdict ` +
195
- `(timed out or unreadable — never report 2 as green).\n` +
194
+ ` Exit 0 = settled green, and the line names the head it is about · 1 = settled, ` +
195
+ `something failed · 2 = NOT a verdict (timed out, unreadable, or the PR is merged / ` +
196
+ `closed / head-diverged — never report 2 as green).\n` +
196
197
  ` 2. Red? Read only the failing part:\n` +
197
198
  ` gh run view --job <id> --log-failed | grep -E '×|FAIL|Error'\n` +
198
199
  ` then fix it and push again (fix-what-you-see: the author is irrelevant).\n` +
@@ -11,12 +11,23 @@
11
11
  * the 36.2 %-against-48 % run at `docs/CLAIMS.md:188-189`. Whatever that
12
12
  * instrument's flaws — and ADR-202 closed it — it points one way.
13
13
  *
14
- * DEFAULT OFF, AND OFF MEANS ZERO BYTES. The concern registers on two slots but
15
- * returns before reading the router unless `lean_projection.mode: delivery` is
16
- * set. Under every shipped default it emits nothing, costs no injection budget,
17
- * and leaves the standing corpus exactly as it is today. That is why its
18
- * `hook-token-budget.json` row is registered against the per-prompt cap rather
19
- * than a measured emission: there is no measured emission to register yet.
14
+ * SHIPPED ON FOR CLAUDE CODE SINCE ADR-265 — corrected 2026-09-08 (R2 finding
15
+ * 4), because this paragraph read "DEFAULT OFF, AND OFF MEANS ZERO BYTES …
16
+ * under every shipped default it emits nothing … there is no measured emission
17
+ * to register yet" and all four clauses became false in the same change that
18
+ * edited the paragraph below it. The shipped template carries
19
+ * `lean_projection.mode: delivery` with `hosts: [claude-code]`
20
+ * (`src/config/agent-settings.template.yml`), `gateOpen` returns true on that
21
+ * pair, and the emission IS measured: p50 6,674 B, p90 16,188 B, max 20,406 B
22
+ * over 318 gate-open fires on the frozen corpus, which is the distribution the
23
+ * `user_prompt_submit` slot raise in `src/config/hook-token-budget.json` is
24
+ * derived from.
25
+ *
26
+ * OFF STILL MEANS ZERO BYTES, and that half is unchanged: the concern returns
27
+ * before reading the router unless the resolved (mode, hosts) pair actually
28
+ * thins THIS host — see `gateOpen`, which checks both, because the projector
29
+ * does. On any other host, and on a `lean_projection.mode: eager-all` rollback,
30
+ * it emits nothing.
20
31
  *
21
32
  * ONE MATCHER, SHARED WITH THE OFFLINE MODEL. Everything about selection,
22
33
  * ordering, capping and body loading comes from `_lib/rule_injection.ts`, which
@@ -31,6 +42,29 @@
31
42
  * uses. State lives under `agents/runtime/state/`, the class
32
43
  * `context-hygiene.json` already occupies; no new state convention is created.
33
44
  *
45
+ * WHAT IS RE-DELIVERED AFTER A COMPACTION, EXACTLY
46
+ * (road-to-delivery-for-every-host 2.4 — stated because a rule lost at a
47
+ * compaction boundary is lost for the rest of the session, and "re-armed" alone
48
+ * does not say what a reader may rely on):
49
+ *
50
+ * · `pre_compact` clears the WHOLE seen-set for that session, not the rules
51
+ * matched on the compacted turn. There is no per-rule bookkeeping to be
52
+ * partially wrong about.
53
+ * · Nothing is delivered BY the compaction itself. The slot emits zero bytes
54
+ * and exits allow; re-arming is silent.
55
+ * · A rule's body returns on the NEXT turn whose trigger matches it — which
56
+ * means a rule whose trigger does not fire again is NOT restored. Delivery
57
+ * is trigger-driven on both sides of the boundary; compaction resets the
58
+ * de-duplication, it does not replay a transcript.
59
+ * · The seen-set is per session, so a compaction in one session re-arms only
60
+ * that session.
61
+ *
62
+ * Held by three fixtures in `tests/scripts/rule_inject_hook.test.ts` under
63
+ * "once per session per rule, re-armed on compaction": the dedup case, the
64
+ * matched-rule → compaction → matching-turn → body-present case, and the
65
+ * per-session case. All three predate this roadmap; 2.4 adds the contract
66
+ * above, not the coverage, and says so rather than claiming new tests.
67
+ *
34
68
  * NEVER BLOCKS. Every failure path returns 0: unreadable stdin, malformed JSON,
35
69
  * missing router, unreadable body, unwritable state. The one non-zero exit is
36
70
  * the host's advisory context channel (exit 2 + `decision: "warn"`), the same
@@ -54,8 +88,12 @@ import * as path from 'node:path';
54
88
  import process from 'node:process';
55
89
  import { fileURLToPath, pathToFileURL } from 'node:url';
56
90
 
57
- import { hookSectionEnabled, leanProjectionModeRaw } from '../_lib/hook_settings.js';
58
- import { deliversBodies, normalizeLeanProjectionMode } from '../_lib/lean_projection_mode.js';
91
+ import { hookSectionEnabled, leanProjectionHostsRaw, leanProjectionModeRaw } from '../_lib/hook_settings.js';
92
+ import {
93
+ deliversBodies,
94
+ normalizeLeanProjectionMode,
95
+ resolveLeanProjectionHosts,
96
+ } from '../_lib/lean_projection_mode.js';
59
97
  import {
60
98
  loadRuleBody,
61
99
  loadRouter,
@@ -81,15 +119,38 @@ const EXIT_WARN = 2;
81
119
  * slot, for a concern that is default-OFF and emits nothing. Measured: 202 ms
82
120
  * -> 196 ms on the `pre_tool_use` p95 when the concern is unbound entirely, and
83
121
  * the CI latency gate went red on the branch that introduced it while passing
84
- * on main. So the runtime cap is the same bound in the unit
122
+ * on main. So the runtime cap is stated in the unit
85
123
  * `hook-token-budget.json` already enforces — 5,000 tok at the ~4 bytes/token
86
- * this corpus measures is 20,480 B, which is exactly this concern's registered
87
- * row. Cap and budget row are now one number instead of two units.
124
+ * this corpus measures was 20,480 B, and that WAS this concern's registered
125
+ * row until 2026-09-08. It matched the concern row and not the slot row; see
126
+ * the correction below.
127
+ *
128
+ * LOWERED 20480 -> 16384 on 2026-09-08 (R2 finding 3), and the paragraphs above
129
+ * are kept because they record how the retired number was derived. The defect
130
+ * was that the derivation above and the one behind the
131
+ * `user_prompt_submit` slot row were TWO STATISTICS IN TWO UNITS: this cap was
132
+ * the p90 of the matched-body TOKEN distribution, converted at ~4 B/tok; the
133
+ * slot row is the p90 gate-open FIRE SIZE in bytes, which is the activation
134
+ * charge owner ruling E2 specifies. They disagreed by 25 %, in the direction
135
+ * that licensed ONE concern to emit more than the whole slot — carrying 12
136
+ * other concerns — is registered for. Reconciled downward onto the slot row,
137
+ * because that is the owner-specified charge; the cost is measured and recorded
138
+ * in `hook-token-budget.json`'s own `rule-inject_reason` (33 -> 45 fires
139
+ * truncated, 63 -> 88 bodies withheld over 330 corpus fires).
140
+ *
141
+ * WHAT THIS CAP DOES, precisely: `selectForInjection` drops whole bodies to
142
+ * stay under it, so a fire is TRUNCATED and never over-emitted. It is the only
143
+ * number that acts on a single fire — the per-slot sums are an authoring-time
144
+ * control read by `bench_hook_injection`, and the runtime dispatcher enforces
145
+ * only `per_turn_aggregate_bytes.ceiling_bytes`.
88
146
  *
89
147
  * Re-run that command if the corpus or the bodies move; a cap copied from a
90
- * stale measurement is worse than no cap, because it looks derived.
148
+ * stale measurement is worse than no cap, because it looks derived. The
149
+ * tripwire in `tests/scripts/rule_inject_hook.test.ts` holds this equal to the
150
+ * registered concern row and at or below the slot sum, so the two units cannot
151
+ * drift apart again unnoticed.
91
152
  */
92
- export const CAP_BYTES = 20480;
153
+ export const CAP_BYTES = 16384;
93
154
 
94
155
  /** Tools whose input names a file this concern can match path triggers against. */
95
156
  export const FILE_TOOLS = new Set(['Write', 'Edit', 'NotebookEdit', 'Read', 'MultiEdit']);
@@ -216,18 +277,44 @@ export function buildInjection(
216
277
 
217
278
  // ── main ─────────────────────────────────────────────────────────────────
218
279
 
280
+ /**
281
+ * The one host this concern is bound on.
282
+ *
283
+ * The manifest binds `rule-inject` under `claude` alone, so the host axis
284
+ * `gateOpen` has to consult is a constant here rather than something read off
285
+ * the envelope — the envelope carries no host id, and inventing one from the
286
+ * process environment would be a guess where the manifest is a fact.
287
+ */
288
+ export const DELIVERY_HOST = 'claude-code';
289
+
219
290
  /**
220
291
  * Whether the settings gate applies.
221
292
  *
222
- * Through the dispatcher the gate is absolute: no `lean_projection.mode:
223
- * delivery`, no bytes. A DIRECT CLI invocation is a probe by definition — an
224
- * operator piping an envelope into this file is asking to see what it would
225
- * deliver — so there the mode defaults to on. `AGENT_CONFIG_REPLAY` re-imposes
226
- * the gate, which is what keeps `bench_hook_injection` measuring the shipped
227
- * default (zero bytes) rather than the probe.
293
+ * BOTH AXES, because the projector reads both. Until 2026-09-08 this keyed on
294
+ * `lean_projection.mode` alone while `condense` gates stub-writing on
295
+ * `thinsHost(mode, hosts, host)` (R2 finding 5). The two disagreed in exactly
296
+ * the states the host axis exists for: `mode: delivery` with a `hosts:` list
297
+ * that does not resolve to `claude-code` — the documented "thin no host"
298
+ * state, which a fully typo'd list also produces — left this host with a
299
+ * FULL-BODIED tree while the hook kept injecting on a match, so every matched
300
+ * rule was delivered twice. `hosts: [cursor]` was the same defect with a
301
+ * second half: cursor received stubs with no bound slot to deliver them back.
302
+ *
303
+ * `deliversBodies` is checked separately from the host list rather than via
304
+ * `thinsHost`, which is true for `thin` as well: `thin` writes the same stubs
305
+ * and binds NO delivery concern, so it must never open this gate.
306
+ *
307
+ * An explicit `hooks.rule_inject` opt-in still opens it — that is an operator
308
+ * asking for the concern by name, independent of the projection mode. A DIRECT
309
+ * CLI invocation is a probe by definition — an operator piping an envelope into
310
+ * this file is asking to see what it would deliver — so there the gate defaults
311
+ * to open. `AGENT_CONFIG_REPLAY` re-imposes it, which is what keeps
312
+ * `bench_hook_injection` measuring the configured tree rather than the probe.
228
313
  */
229
314
  export function gateOpen(root: string, cliEntry: boolean): boolean {
230
- if (deliversBodies(normalizeLeanProjectionMode(leanProjectionModeRaw(root)))) return true;
315
+ const mode = normalizeLeanProjectionMode(leanProjectionModeRaw(root));
316
+ const hosts = resolveLeanProjectionHosts(leanProjectionHostsRaw(root)).hosts;
317
+ if (deliversBodies(mode) && hosts.includes(DELIVERY_HOST)) return true;
231
318
  if (hookSectionEnabled(root, 'rule_inject')) return true;
232
319
  return cliEntry && process.env['AGENT_CONFIG_REPLAY'] !== '1';
233
320
  }