@event4u/agent-config 9.9.0 → 9.10.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 (384) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +153 -194
  3. package/README.md +1 -1
  4. package/dist/agent-src/commands/agent-status.md +12 -11
  5. package/dist/agent-src/commands/agents/user/accept.md +115 -30
  6. package/dist/agent-src/commands/agents/user/delete.md +147 -0
  7. package/dist/agent-src/commands/agents/user/review.md +65 -28
  8. package/dist/agent-src/commands/agents/user/show.md +82 -29
  9. package/dist/agent-src/commands/agents/user/update.md +2 -2
  10. package/dist/agent-src/commands/agents/user.md +16 -3
  11. package/dist/agent-src/commands/check-current-md.md +0 -10
  12. package/dist/agent-src/commands/condense.md +28 -97
  13. package/dist/agent-src/commands/cost/report.md +7 -0
  14. package/dist/agent-src/commands/fix/portability.md +0 -8
  15. package/dist/agent-src/commands/fix/refs.md +0 -8
  16. package/dist/agent-src/commands/humanize.md +2 -2
  17. package/dist/agent-src/commands/jira-ticket.md +1 -1
  18. package/dist/agent-src/commands/memory/load.md +11 -0
  19. package/dist/agent-src/commands/optimize/skills.md +1 -1
  20. package/dist/agent-src/commands/pr/create.md +4 -4
  21. package/dist/agent-src/commands/profile/show.md +3 -3
  22. package/dist/agent-src/commands/rule-compliance-audit.md +5 -4
  23. package/dist/agent-src/commands/security-audit-config.md +1 -1
  24. package/dist/agent-src/commands/sync/gitignore/fix.md +1 -1
  25. package/dist/agent-src/commands/tdd.md +21 -0
  26. package/dist/agent-src/commands/team/delegate.md +2 -2
  27. package/dist/agent-src/commands/team-knowledge/bootstrap.md +9 -8
  28. package/dist/agent-src/commands/team-knowledge/consolidate.md +8 -7
  29. package/dist/agent-src/commands/team.md +4 -1
  30. package/dist/agent-src/commands/upstream-contribute.md +0 -1
  31. package/dist/agent-src/contexts/authority/commit-mechanics.md +7 -0
  32. package/dist/agent-src/contexts/authority/destructive-mechanics.md +16 -0
  33. package/dist/agent-src/contexts/authority/scope-mechanics.md +61 -0
  34. package/dist/agent-src/contexts/communication/rules-auto/reply-close-mechanics.md +20 -18
  35. package/dist/agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +1 -1
  36. package/dist/agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +1 -1
  37. package/dist/agent-src/contexts/communication/rules-auto/source-of-truth-mechanics.md +9 -10
  38. package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +1 -1
  39. package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +11 -0
  40. package/dist/agent-src/contexts/contracts/artifact-engagement-flow.md +26 -15
  41. package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +3 -0
  42. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +67 -37
  43. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +1 -1
  44. package/dist/agent-src/contexts/execution/autonomy-examples.md +1 -1
  45. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +7 -6
  46. package/dist/agent-src/contexts/execution/evidence-discipline.md +92 -77
  47. package/dist/agent-src/contexts/execution/orchestration-benchmark-gate.md +22 -21
  48. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +24 -0
  49. package/dist/agent-src/contexts/execution/project-intelligence.md +122 -103
  50. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +23 -21
  51. package/dist/agent-src/contexts/execution/subagent-response-contract.md +5 -5
  52. package/dist/agent-src/contexts/execution/subagent-routing.md +11 -0
  53. package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +13 -13
  54. package/dist/agent-src/contexts/execution/subagent-steering.md +36 -34
  55. package/dist/agent-src/contexts/execution/toolchain-resolver.md +1 -1
  56. package/dist/agent-src/contexts/execution/user-memory-channels.md +189 -0
  57. package/dist/agent-src/contexts/execution/verification-mechanics.md +9 -0
  58. package/dist/agent-src/contexts/model-recommendations.md +3 -2
  59. package/dist/agent-src/contexts/subagent-configuration.md +3 -3
  60. package/dist/agent-src/ghostwriter/README.md +2 -2
  61. package/dist/agent-src/packs/README.md +1 -1
  62. package/dist/agent-src/personas/README.md +5 -5
  63. package/dist/agent-src/personas/_template-specialist/persona.md +3 -3
  64. package/dist/agent-src/personas/backend-architect.md +24 -23
  65. package/dist/agent-src/personas/eloquent-tamer.md +30 -30
  66. package/dist/agent-src/personas/frontend-engineer.md +30 -30
  67. package/dist/agent-src/personas/product-owner.md +41 -38
  68. package/dist/agent-src/personas/qa.md +13 -13
  69. package/dist/agent-src/personas/security-engineer.md +22 -22
  70. package/dist/agent-src/presets/README.md +3 -3
  71. package/dist/agent-src/profiles/README.md +3 -3
  72. package/dist/agent-src/rules/active-remediation.md +2 -2
  73. package/dist/agent-src/rules/artifact-engagement-recording.md +4 -4
  74. package/dist/agent-src/rules/ask-when-uncertain.md +0 -4
  75. package/dist/agent-src/rules/augment-edit-discipline.md +1 -1
  76. package/dist/agent-src/rules/broken-access-control.md +4 -4
  77. package/dist/agent-src/rules/code-comment-discipline.md +1 -1
  78. package/dist/agent-src/rules/code-provenance.md +2 -2
  79. package/dist/agent-src/rules/commit-policy.md +4 -9
  80. package/dist/agent-src/rules/communication-through-line.md +5 -5
  81. package/dist/agent-src/rules/decision-revisit-gate.md +1 -1
  82. package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -1
  83. package/dist/agent-src/rules/domain-adoption-policy.md +1 -1
  84. package/dist/agent-src/rules/domain-safety-pii.md +1 -1
  85. package/dist/agent-src/rules/external-code-graph-interop.md +1 -1
  86. package/dist/agent-src/rules/fast-path-marker-visibility.md +43 -7
  87. package/dist/agent-src/rules/finance-safety-floor.md +1 -1
  88. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +3 -3
  89. package/dist/agent-src/rules/history-discipline.md +1 -1
  90. package/dist/agent-src/rules/legal-safety-floor.md +1 -1
  91. package/dist/agent-src/rules/lethal-trifecta-guard.md +5 -5
  92. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +10 -8
  93. package/dist/agent-src/rules/media-governance-routing.md +13 -13
  94. package/dist/agent-src/rules/media-sync-ground-truth.md +29 -11
  95. package/dist/agent-src/rules/no-cheap-questions.md +7 -7
  96. package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +29 -18
  97. package/dist/agent-src/rules/non-destructive-by-default.md +5 -23
  98. package/dist/agent-src/rules/onboarding-gate.md +14 -4
  99. package/dist/agent-src/rules/persona-governance.md +2 -2
  100. package/dist/agent-src/rules/prefer-enums-over-literals.md +9 -9
  101. package/dist/agent-src/rules/preservation-guard.md +10 -2
  102. package/dist/agent-src/rules/question-not-instruction.md +1 -1
  103. package/dist/agent-src/rules/roadmap-progress-sync.md +6 -6
  104. package/dist/agent-src/rules/rule-type-governance.md +1 -1
  105. package/dist/agent-src/rules/scale-discipline.md +1 -1
  106. package/dist/agent-src/rules/scope-control.md +1 -1
  107. package/dist/agent-src/rules/secret-vcs-guard.md +1 -1
  108. package/dist/agent-src/rules/security-sensitive-stop.md +17 -11
  109. package/dist/agent-src/rules/senior-engineering-discipline.md +17 -17
  110. package/dist/agent-src/rules/session-canary.md +1 -1
  111. package/dist/agent-src/rules/skill-quality.md +1 -1
  112. package/dist/agent-src/rules/source-confidentiality.md +21 -19
  113. package/dist/agent-src/rules/source-of-truth.md +6 -5
  114. package/dist/agent-src/rules/spreadsheet-source-quality.md +2 -2
  115. package/dist/agent-src/rules/strategy-safety-floor.md +1 -1
  116. package/dist/agent-src/rules/think-before-action.md +5 -5
  117. package/dist/agent-src/rules/token-budget-discipline.md +5 -3
  118. package/dist/agent-src/rules/token-efficiency.md +2 -2
  119. package/dist/agent-src/rules/untrusted-input-defense.md +4 -4
  120. package/dist/agent-src/rules/user-interaction.md +12 -0
  121. package/dist/agent-src/rules/verify-before-complete.md +4 -24
  122. package/dist/agent-src/skills/adversarial-review/SKILL.md +2 -2
  123. package/dist/agent-src/skills/agent-security-review/SKILL.md +52 -45
  124. package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +2 -2
  125. package/dist/agent-src/skills/ai-code-blindspots/SKILL.md +20 -20
  126. package/dist/agent-src/skills/ai-council/SKILL.md +185 -128
  127. package/dist/agent-src/skills/analysis-skill-router/SKILL.md +3 -3
  128. package/dist/agent-src/skills/api-endpoint/SKILL.md +2 -2
  129. package/dist/agent-src/skills/artisan-commands/SKILL.md +2 -2
  130. package/dist/agent-src/skills/async-python-patterns/SKILL.md +8 -7
  131. package/dist/agent-src/skills/authz-review/SKILL.md +16 -15
  132. package/dist/agent-src/skills/aws-infrastructure/SKILL.md +5 -5
  133. package/dist/agent-src/skills/blade-ui/SKILL.md +1 -1
  134. package/dist/agent-src/skills/bug-analyzer/SKILL.md +30 -12
  135. package/dist/agent-src/skills/code-intelligence/SKILL.md +0 -1
  136. package/dist/agent-src/skills/code-intelligence/evals/triggers.json +52 -0
  137. package/dist/agent-src/skills/code-review/SKILL.md +6 -6
  138. package/dist/agent-src/skills/command-routing/SKILL.md +5 -4
  139. package/dist/agent-src/skills/composer-packages/SKILL.md +2 -2
  140. package/dist/agent-src/skills/condense-memory/SKILL.md +43 -41
  141. package/dist/agent-src/skills/context-document/SKILL.md +23 -21
  142. package/dist/agent-src/skills/copilot-config/SKILL.md +6 -1
  143. package/dist/agent-src/skills/decision-record/SKILL.md +20 -18
  144. package/dist/agent-src/skills/design-intelligence/SKILL.md +4 -4
  145. package/dist/agent-src/skills/design-review/SKILL.md +15 -14
  146. package/dist/agent-src/skills/design-system-capture/reference/design-system-json.md +28 -25
  147. package/dist/agent-src/skills/devcontainer/SKILL.md +2 -2
  148. package/dist/agent-src/skills/docker/SKILL.md +1 -1
  149. package/dist/agent-src/skills/docx-authoring/evals/triggers.json +52 -0
  150. package/dist/agent-src/skills/emit-tickets/SKILL.md +2 -2
  151. package/dist/agent-src/skills/error-handling-patterns/SKILL.md +1 -1
  152. package/dist/agent-src/skills/estimate-ticket/SKILL.md +2 -2
  153. package/dist/agent-src/skills/evaluate-llm-feature/SKILL.md +0 -1
  154. package/dist/agent-src/skills/evaluate-llm-feature/evals/triggers.json +52 -0
  155. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +6 -5
  156. package/dist/agent-src/skills/feature-planning/SKILL.md +2 -2
  157. package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +3 -3
  158. package/dist/agent-src/skills/flux/SKILL.md +1 -1
  159. package/dist/agent-src/skills/frontend-render-security/SKILL.md +13 -13
  160. package/dist/agent-src/skills/git-workflow/SKILL.md +33 -33
  161. package/dist/agent-src/skills/grafana/SKILL.md +5 -0
  162. package/dist/agent-src/skills/humanizer/SKILL.md +83 -66
  163. package/dist/agent-src/skills/humanizer/data/patterns.md +14 -14
  164. package/dist/agent-src/skills/humanizer/references/anti-aiisms.md +4 -4
  165. package/dist/agent-src/skills/judge-artifact-completeness/SKILL.md +82 -37
  166. package/dist/agent-src/skills/judge-bug-hunter/SKILL.md +17 -5
  167. package/dist/agent-src/skills/judge-injection-defense/SKILL.md +63 -25
  168. package/dist/agent-src/skills/judge-security-auditor/SKILL.md +2 -0
  169. package/dist/agent-src/skills/judge-synthesis/SKILL.md +72 -28
  170. package/dist/agent-src/skills/laravel-horizon/SKILL.md +5 -0
  171. package/dist/agent-src/skills/laravel-mail/SKILL.md +5 -4
  172. package/dist/agent-src/skills/laravel-middleware/SKILL.md +5 -4
  173. package/dist/agent-src/skills/laravel-notifications/SKILL.md +10 -9
  174. package/dist/agent-src/skills/laravel-pennant/SKILL.md +1 -1
  175. package/dist/agent-src/skills/laravel-pulse/SKILL.md +9 -8
  176. package/dist/agent-src/skills/laravel-reverb/SKILL.md +6 -5
  177. package/dist/agent-src/skills/laravel-scheduling/SKILL.md +6 -1
  178. package/dist/agent-src/skills/laravel-validation/SKILL.md +12 -0
  179. package/dist/agent-src/skills/launch-readiness/SKILL.md +1 -1
  180. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +7 -7
  181. package/dist/agent-src/skills/learning-tutor/SKILL.md +44 -43
  182. package/dist/agent-src/skills/learning-tutor/evals/triggers.json +52 -0
  183. package/dist/agent-src/skills/license-compliance-audit/SKILL.md +7 -7
  184. package/dist/agent-src/skills/license-compliance-borrow-check/SKILL.md +3 -3
  185. package/dist/agent-src/skills/license-compliance-credits/SKILL.md +4 -4
  186. package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +0 -1
  187. package/dist/agent-src/skills/memory-consolidation/SKILL.md +69 -64
  188. package/dist/agent-src/skills/motion-choreographer/SKILL.md +6 -6
  189. package/dist/agent-src/skills/pdf-tools/evals/triggers.json +52 -0
  190. package/dist/agent-src/skills/performance-analysis/SKILL.md +7 -3
  191. package/dist/agent-src/skills/persona-improvement/SKILL.md +0 -2
  192. package/dist/agent-src/skills/persona-improvement/evals/triggers.json +52 -0
  193. package/dist/agent-src/skills/php-coder/SKILL.md +10 -0
  194. package/dist/agent-src/skills/prediction-pool-optimizer/SKILL.md +129 -120
  195. package/dist/agent-src/skills/prediction-pool-optimizer/reference/ev-fixtures.md +36 -35
  196. package/dist/agent-src/skills/prediction-pool-optimizer/reference/odds-and-bonus.md +45 -41
  197. package/dist/agent-src/skills/project-analysis-core/SKILL.md +4 -4
  198. package/dist/agent-src/skills/project-analysis-hypothesis-driven/SKILL.md +3 -3
  199. package/dist/agent-src/skills/project-analysis-react/SKILL.md +1 -1
  200. package/dist/agent-src/skills/project-analysis-symfony/SKILL.md +1 -1
  201. package/dist/agent-src/skills/project-analysis-zend-laminas/SKILL.md +2 -2
  202. package/dist/agent-src/skills/prompt-engineering-patterns/SKILL.md +1 -1
  203. package/dist/agent-src/skills/prompt-validator/SKILL.md +39 -39
  204. package/dist/agent-src/skills/quality-tools/SKILL.md +15 -15
  205. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +55 -19
  206. package/dist/agent-src/skills/react-shadcn-ui/reference/registry.md +29 -27
  207. package/dist/agent-src/skills/readme-writing-package/SKILL.md +2 -2
  208. package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +25 -25
  209. package/dist/agent-src/skills/recursive-verification/SKILL.md +6 -5
  210. package/dist/agent-src/skills/refine-prompt/SKILL.md +1 -1
  211. package/dist/agent-src/skills/refine-ticket/SKILL.md +20 -2
  212. package/dist/agent-src/skills/repomix-packer/SKILL.md +1 -1
  213. package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
  214. package/dist/agent-src/skills/roadmap-management/SKILL.md +80 -66
  215. package/dist/agent-src/skills/roadmap-writing/SKILL.md +84 -77
  216. package/dist/agent-src/skills/rule-refactor/SKILL.md +1 -1
  217. package/dist/agent-src/skills/screenshot-hygiene/evals/triggers.json +52 -0
  218. package/dist/agent-src/skills/security-audit/SKILL.md +26 -9
  219. package/dist/agent-src/skills/security-maturity-assessment/SKILL.md +38 -16
  220. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +14 -11
  221. package/dist/agent-src/skills/skill-writing/SKILL.md +9 -8
  222. package/dist/agent-src/skills/song-to-script/SKILL.md +93 -85
  223. package/dist/agent-src/skills/sql-writing/SKILL.md +2 -2
  224. package/dist/agent-src/skills/stakeholder-tradeoff/SKILL.md +4 -3
  225. package/dist/agent-src/skills/standards-from-config/SKILL.md +61 -43
  226. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +22 -8
  227. package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +28 -2
  228. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +13 -13
  229. package/dist/agent-src/skills/systematic-debugging/SKILL.md +22 -21
  230. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
  231. package/dist/agent-src/skills/technical-specification/SKILL.md +5 -0
  232. package/dist/agent-src/skills/terraform/SKILL.md +2 -2
  233. package/dist/agent-src/skills/terragrunt/SKILL.md +8 -8
  234. package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +1 -1
  235. package/dist/agent-src/skills/threat-modeling/SKILL.md +19 -13
  236. package/dist/agent-src/skills/universal-project-analysis/SKILL.md +1 -1
  237. package/dist/agent-src/skills/upstream-contribute/SKILL.md +0 -1
  238. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +9 -9
  239. package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -1
  240. package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +4 -6
  241. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +67 -61
  242. package/dist/agent-src/skills/video-director/SKILL.md +7 -7
  243. package/dist/agent-src/skills/worktree-lifecycle/SKILL.md +3 -3
  244. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  245. package/dist/agent-src/templates/contexts/knowledge-pages.md +47 -45
  246. package/dist/agent-src/templates/contexts/lesson-card.md +2 -2
  247. package/dist/agent-src/templates/contexts/tenant-boundaries.md +2 -2
  248. package/dist/agent-src/templates/contexts.md +1 -1
  249. package/dist/agent-src/templates/features.md +1 -1
  250. package/dist/agent-src/templates/roadmaps.md +125 -116
  251. package/dist/agent-src/templates/rule.md +2 -1
  252. package/dist/agent-src/templates/scripts/pr_risk_review.ts +0 -0
  253. package/dist/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
  254. package/dist/agent-src/templates/scripts/tier_usage_report.ts +2 -2
  255. package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -2
  256. package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +1 -1
  257. package/dist/agent-src/user-types/README.md +8 -8
  258. package/dist/agent-src/user-types/galabau-field-crew.md +34 -33
  259. package/dist/agent-src/user-types/metalworking-shop.md +35 -34
  260. package/dist/agent-src/user-types/truck-driver.md +22 -20
  261. package/dist/cli/python/workspace_roles.js +2 -2
  262. package/dist/cli/python/workspace_roles.js.map +1 -1
  263. package/dist/discovery/deprecation-report.md +1 -1
  264. package/dist/discovery/discovery-manifest.json +88 -62
  265. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  266. package/dist/discovery/discovery-manifest.summary.md +3 -3
  267. package/dist/discovery/orphan-report.md +1 -1
  268. package/dist/discovery/packs.json +6 -5
  269. package/dist/discovery/trust-report.md +2 -2
  270. package/dist/discovery/workspaces.json +5 -4
  271. package/dist/hooks/dispatch.js +186 -12
  272. package/dist/install/install.mjs +8 -0
  273. package/dist/mcp/registry-manifest.json +3 -3
  274. package/dist/mcp/server.json +2 -2
  275. package/dist/mcp/server.mjs +1199 -857
  276. package/dist/router.json +1 -1
  277. package/dist/scripts/_lib/compile_time_toggles.js +48 -0
  278. package/dist/scripts/_lib/compile_time_toggles.js.map +1 -0
  279. package/dist/scripts/condense.js +234 -217
  280. package/dist/scripts/condense.js.map +1 -1
  281. package/dist/server/schemas/settings.js +4 -0
  282. package/dist/server/schemas/settings.js.map +1 -1
  283. package/dist/shared/userMd/utils.js +30 -0
  284. package/dist/shared/userMd/utils.js.map +1 -1
  285. package/dist/ui/assets/index-BpSQt5vm.js.map +1 -1
  286. package/docs/guidelines/agent-infra/api-cost-levers.md +56 -5
  287. package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +93 -33
  288. package/package.json +1 -1
  289. package/src/agent-src/templates/scripts/pr_risk_review.ts +0 -0
  290. package/src/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
  291. package/src/agent-src/templates/scripts/tier_usage_report.ts +2 -2
  292. package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -2
  293. package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +1 -1
  294. package/src/config/agent-settings.template.yml +32 -2
  295. package/src/config/ci-local-parity.yml +142 -0
  296. package/src/config/gate-coverage.yml +127 -0
  297. package/src/config/preamble-payload-budget.json +44 -0
  298. package/src/scripts/_cli/cmd_doctor.ts +78 -2
  299. package/src/scripts/_lib/agent_user_profile.ts +381 -0
  300. package/src/scripts/_lib/agents_overlay.ts +9 -0
  301. package/src/scripts/_lib/anchor_eval.ts +311 -0
  302. package/src/scripts/_lib/cc_transcript.ts +316 -0
  303. package/src/scripts/_lib/compile_time_toggles.ts +79 -0
  304. package/src/scripts/_lib/confusables.ts +101 -0
  305. package/src/scripts/_lib/duplicate_scope_census.ts +77 -0
  306. package/src/scripts/_lib/managed_agents_folder.ts +181 -0
  307. package/src/scripts/_lib/payload_hash_drift.ts +126 -0
  308. package/src/scripts/_lib/preservation_migration.ts +291 -0
  309. package/src/scripts/_lib/retrieval_sanitize.ts +166 -2
  310. package/src/scripts/_lib/scan_scope.ts +115 -0
  311. package/src/scripts/_lib/user_global_memory_audit.ts +187 -0
  312. package/src/scripts/_lib/user_global_observations.ts +830 -0
  313. package/src/scripts/_lib/user_global_revocations.ts +110 -0
  314. package/src/scripts/_lib/user_memory_gate_counters.ts +291 -0
  315. package/src/scripts/ai_council/blind_review.ts +0 -0
  316. package/src/scripts/ai_council/budget_guard.ts +90 -11
  317. package/src/scripts/ai_council/bundler.ts +2 -2
  318. package/src/scripts/ai_council/clients.ts +59 -3
  319. package/src/scripts/ai_council/config.ts +38 -0
  320. package/src/scripts/ai_council/orchestrator.ts +54 -9
  321. package/src/scripts/ai_team/team_dispatch.ts +17 -6
  322. package/src/scripts/anchor_eval_falsify.ts +198 -0
  323. package/src/scripts/anchor_scoring_run.ts +239 -0
  324. package/src/scripts/annotate_discovery.ts +1 -65
  325. package/src/scripts/bench_quality_run.ts +168 -4
  326. package/src/scripts/cache_realization_report.ts +782 -0
  327. package/src/scripts/check_artefact_count_messaging.ts +5 -1
  328. package/src/scripts/check_augment_description_cap.ts +15 -4
  329. package/src/scripts/check_ci_local_parity.ts +317 -0
  330. package/src/scripts/check_condensation.ts +96 -191
  331. package/src/scripts/check_context_paths.ts +38 -9
  332. package/src/scripts/check_gate_coverage.ts +299 -0
  333. package/src/scripts/check_iron_law_prominence.ts +22 -1
  334. package/src/scripts/check_kernel_prefix_stability.ts +0 -0
  335. package/src/scripts/check_no_new_legacy_path.ts +16 -6
  336. package/src/scripts/check_no_roadmap_refs.ts +22 -9
  337. package/src/scripts/check_originality_freshness.ts +167 -0
  338. package/src/scripts/check_preamble_payload_budget.ts +130 -0
  339. package/src/scripts/check_proposal.ts +0 -0
  340. package/src/scripts/check_references.ts +0 -1
  341. package/src/scripts/check_safety_floor_untouched.ts +171 -24
  342. package/src/scripts/check_site_links.ts +62 -3
  343. package/src/scripts/ci_status.ts +0 -0
  344. package/src/scripts/cluster_near_miss_patterns.ts +0 -0
  345. package/src/scripts/code_graph/build.ts +0 -0
  346. package/src/scripts/command_suggester/types.ts +0 -0
  347. package/src/scripts/compile_router.ts +10 -14
  348. package/src/scripts/condense.sh +3 -4
  349. package/src/scripts/condense.ts +247 -228
  350. package/src/scripts/cost/track.mjs +168 -33
  351. package/src/scripts/cost_summary.ts +33 -1
  352. package/src/scripts/council_cli.ts +45 -3
  353. package/src/scripts/discovery_graph.ts +0 -0
  354. package/src/scripts/encoding_corpus.ts +500 -0
  355. package/src/scripts/encoding_corpus_report.ts +216 -0
  356. package/src/scripts/generate_index.ts +19 -2
  357. package/src/scripts/install-hooks.sh +2 -2
  358. package/src/scripts/learning_sidecar.ts +0 -0
  359. package/src/scripts/lint_confusables.ts +10 -72
  360. package/src/scripts/lint_featured_skills.ts +0 -0
  361. package/src/scripts/lint_hidden_unicode.ts +208 -0
  362. package/src/scripts/lint_load_context.ts +17 -5
  363. package/src/scripts/lint_new_skill_gate.ts +9 -3
  364. package/src/scripts/lint_no_python_twin_rationale.ts +17 -2
  365. package/src/scripts/lint_originality.ts +1 -1
  366. package/src/scripts/lint_skill_originality.ts +1 -1
  367. package/src/scripts/lint_ticket_buildable.ts +1 -1
  368. package/src/scripts/mcp_server/tools.ts +4 -4
  369. package/src/scripts/measure_scope_dedup.ts +224 -0
  370. package/src/scripts/memory_lookup.ts +0 -0
  371. package/src/scripts/mine_session.ts +98 -0
  372. package/src/scripts/orchestration_payload_hash_drift.ts +145 -0
  373. package/src/scripts/preamble_byte_census.ts +574 -0
  374. package/src/scripts/probe_skill_registration.ts +2 -2
  375. package/src/scripts/redact_hook_capture.ts +13 -0
  376. package/src/scripts/release.ts +65 -10
  377. package/src/scripts/router_telemetry.ts +1 -1
  378. package/src/scripts/second_brain_retrieval.ts +14 -4
  379. package/src/scripts/skill_linter.ts +5 -0
  380. package/src/scripts/surface-tiers.yml +2 -0
  381. package/src/scripts/validate_pack_yaml.ts +0 -0
  382. package/src/server/schemas/settings.ts +8 -0
  383. package/src/shared/userMd/utils.ts +31 -0
  384. package/dist/agent-src/rules/telegraph-speak.md +0 -87
@@ -105,9 +105,15 @@ function _skill_roots(): string[] {
105
105
  }
106
106
  }
107
107
  }
108
- const legacy = path.join(ROOT, '.agent-src.uncondensed', 'skills');
109
- if (roots.length === 0 && _isDir(legacy)) {
110
- roots = [legacy];
108
+ // ADR-051 moved skill authoring to `src/skills`; a later commit deleted
109
+ // `packages/` entirely. Until 2026-07-29 the only fallback was the retired
110
+ // container, so this resolved to [] and the overlap gate silently passed
111
+ // every new skill.
112
+ if (roots.length === 0) {
113
+ const cand = path.join(ROOT, 'src', 'skills');
114
+ if (_isDir(cand)) {
115
+ roots = [cand];
116
+ }
111
117
  }
112
118
  return roots;
113
119
  }
@@ -26,9 +26,24 @@ const _HERE = fileURLToPath(import.meta.url);
26
26
  export const ROOT = path.resolve(path.dirname(_HERE), '..', '..');
27
27
  const SCOPE = path.join(ROOT, 'src', 'scripts');
28
28
 
29
- /** Banned rationale shapes (case-insensitive). */
29
+ /**
30
+ * Banned rationale shapes (case-insensitive).
31
+ *
32
+ * `twin-of` is qualified with a Python signal on purpose. The bare `/\btwin of\b/`
33
+ * it replaced banned an English word rather than a claim shape, and produced 6 false
34
+ * positives out of 7 findings: a CLI twin of an MCP tool, a sync twin of an async
35
+ * probe in the same file, a debate twin of a sibling function, a SQLite twin of a
36
+ * JSON cache. None of those rationalise anything by fidelity to a deleted Python
37
+ * original — which is the only thing this gate exists to stop — and rewording correct
38
+ * comments to dodge a word would have been the tail wagging the dog.
39
+ *
40
+ * The narrowing does not weaken the gate: every shape it targets names Python by
41
+ * construction ("TypeScript twin of the Python original", "twin of the retired
42
+ * .py"), so the qualifier is satisfied precisely when the claim is the banned one.
43
+ * The other three patterns already carry their own Python signal.
44
+ */
30
45
  export const BANNED: ReadonlyArray<[string, RegExp]> = [
31
- ['twin-of', /\btwin of\b/i],
46
+ ['twin-of', /\btwin of\b[^\n]*\b(?:python|py2ts|\.py)\b|\b(?:python|py2ts|\.py)\b[^\n]*\btwin of\b/i],
32
47
  ['latent-quirks', /latent (?:python )?(?:quirks|bugs) replicated/i],
33
48
  ['byte-identical-python', /byte-identical to the python/i],
34
49
  ['python-original', /\bthe python original\b/i],
@@ -373,7 +373,7 @@ function _changed(files: string[]): { pairs: Pair[]; fails: number } {
373
373
  const seen = new Set<string>();
374
374
  const record = (a: Artifact, b: Artifact): void => {
375
375
  if (a.relpath === b.relpath) return;
376
- const key = [a.relpath, b.relpath].sort().join('');
376
+ const key = [a.relpath, b.relpath].sort().join('\0');
377
377
  if (seen.has(key)) return;
378
378
  const o = overlap(a, b);
379
379
  if (o >= WARN) {
@@ -351,7 +351,7 @@ function _sortedSkillMds(root: string): string[] {
351
351
 
352
352
  /** frozenset((a, b)) — order-independent membership key. */
353
353
  function _frozenKey(a: string, b: string): string {
354
- return a <= b ? `${a}${b}` : `${b}${a}`;
354
+ return a <= b ? `${a}\0${b}` : `${b}\0${a}`;
355
355
  }
356
356
 
357
357
  /** sorted(a & b) — codepoint-sorted intersection. */
@@ -838,7 +838,7 @@ function lint(): number {
838
838
  } else {
839
839
  // fm.get("id") is None → set contains None; an id-less ticket
840
840
  // file. Represent the Python None membership separately.
841
- file_ids.add('__none__');
841
+ file_ids.add('\0__none__');
842
842
  }
843
843
  }
844
844
  }
@@ -97,10 +97,10 @@ export type ToolSideEffect = 'ro' | 'fs-write' | 'shell';
97
97
  * each `tools/call`. `handler` is an async function that receives the
98
98
  * validated arguments + the resolved `consumer_root` path.
99
99
  *
100
- * Mirrors the Python frozen dataclass `BuiltinTool` (field order
101
- * preserved). `side_effect` is a TS-only addition (Phase 3 of
102
- * road-to-credible-install) — the Python original predates the generated
103
- * catalog and had no analogous field.
100
+ * Shape is pinned by `consumer_tool_catalog.json`: `build_mcp_catalog` derives
101
+ * the catalog from `ALLOWLIST` here, and `build_mcp_catalog --strict` fails CI
102
+ * on any drift (`.github/workflows/tests.yml`). `side_effect` is consumed by that
103
+ * generator, so adding or reordering a field means regenerating the catalog.
104
104
  */
105
105
  export interface BuiltinTool {
106
106
  readonly name: string;
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * C-3 measurement harness — scope de-duplication of the rule projection.
4
+ *
5
+ * Pre-registered in `road-to-cache-economy.md` § "C-3
6
+ * pre-registration" BEFORE this script produced a number. Metric, threshold and
7
+ * honest-null consequence are fixed there; this file only measures.
8
+ *
9
+ * What it does, deterministically and without touching the real HOME:
10
+ *
11
+ * 1. Builds a two-scope FIXTURE: a temp home whose `.claude/rules/` is a
12
+ * byte-identical copy of the projected rule source. That is the condition
13
+ * the reduction targets — a consumer carrying the same package version at
14
+ * user scope and project scope. (On a maintainer machine the two scopes
15
+ * hold different releases, so the dedup is correctly inert; that case is
16
+ * measured too, as the control.)
17
+ * 2. Censuses the payload with the dedup OFF, then ON.
18
+ * 3. Reports the delta against BOTH denominators: the measured median
19
+ * cold-start (what a spawn actually pays) and the file-measurable subtotal.
20
+ *
21
+ * It never writes into `~`, never regenerates the repo's own projection, and
22
+ * makes no network call.
23
+ */
24
+ import * as fs from 'node:fs';
25
+ import * as os from 'node:os';
26
+ import * as path from 'node:path';
27
+
28
+ import { censusRuleDir } from './preamble_byte_census.js';
29
+
30
+ const REPO_ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', '..');
31
+ const RULES_SOURCE = path.join(REPO_ROOT, 'dist', 'agent-src', 'rules');
32
+
33
+ /** Estimated tokens, the same chars/4 basis the census uses. */
34
+ function tokens(chars: number): number {
35
+ return Math.round(chars / 4);
36
+ }
37
+
38
+ interface ScopeSnapshot {
39
+ files: number;
40
+ chars: number;
41
+ tokens: number;
42
+ }
43
+
44
+ function snapshot(dir: string): ScopeSnapshot {
45
+ const c = censusRuleDir(dir);
46
+ return { files: c.files, chars: c.chars, tokens: tokens(c.chars) };
47
+ }
48
+
49
+ /** Copy every `*.md` byte-for-byte — the fixture must be byte-identical to matter. */
50
+ function copyRules(from: string, to: string): number {
51
+ fs.mkdirSync(to, { recursive: true });
52
+ let n = 0;
53
+ for (const entry of fs.readdirSync(from)) {
54
+ if (!entry.endsWith('.md')) continue;
55
+ fs.copyFileSync(path.join(from, entry), path.join(to, entry));
56
+ n += 1;
57
+ }
58
+ return n;
59
+ }
60
+
61
+ /**
62
+ * Which rules a byte-identity-gated dedup would skip at project scope. Mirrors
63
+ * `condense._dedupable_rules`'s predicate rather than importing it, so the
64
+ * measurement fails loudly if the two ever disagree instead of moving together.
65
+ */
66
+ function dedupableCount(userDir: string, sourceDir: string): { skipped: number; chars: number } {
67
+ let skipped = 0;
68
+ let chars = 0;
69
+ if (!fs.existsSync(userDir)) return { skipped, chars };
70
+ for (const entry of fs.readdirSync(sourceDir)) {
71
+ if (!entry.endsWith('.md')) continue;
72
+ const twin = path.join(userDir, entry);
73
+ const source = path.join(sourceDir, entry);
74
+ if (!fs.existsSync(twin)) continue;
75
+ const a = fs.readFileSync(twin);
76
+ const b = fs.readFileSync(source);
77
+ if (a.equals(b)) {
78
+ skipped += 1;
79
+ chars += b.byteLength;
80
+ }
81
+ }
82
+ return { skipped, chars };
83
+ }
84
+
85
+ /**
86
+ * Why the real user scope misses the fixture condition. Version drift is the
87
+ * benign half; the structural half is that `install.ts` stamps ownership
88
+ * frontmatter into every installed rule (`_set_key(fm_lines, 'package', …)` at
89
+ * install.ts:2723, `source_path` at install.ts:2725) while the in-repo
90
+ * projection stamps nothing — so a provenance-only difference survives even a
91
+ * perfect version alignment. Classifying the two apart is what turns "0/110"
92
+ * from a puzzle into an answer: `provenanceOnly == total` means aligning
93
+ * versions would buy exactly nothing.
94
+ */
95
+ const OWNERSHIP_KEYS = ['package', 'source_path'] as const;
96
+
97
+ function stripOwnershipKeys(buf: Buffer): string {
98
+ return buf
99
+ .toString('utf-8')
100
+ .split('\n')
101
+ .filter((line) => !OWNERSHIP_KEYS.some((k) => line.startsWith(`${k}:`)))
102
+ .join('\n');
103
+ }
104
+
105
+ interface ReachabilitySplit {
106
+ total: number;
107
+ identical: number;
108
+ provenanceOnly: number;
109
+ bodyDiff: number;
110
+ missing: number;
111
+ }
112
+
113
+ function classifyReachability(userDir: string, sourceDir: string): ReachabilitySplit {
114
+ const split: ReachabilitySplit = {
115
+ total: 0,
116
+ identical: 0,
117
+ provenanceOnly: 0,
118
+ bodyDiff: 0,
119
+ missing: 0,
120
+ };
121
+ for (const entry of fs.readdirSync(sourceDir)) {
122
+ if (!entry.endsWith('.md')) continue;
123
+ split.total += 1;
124
+ const twin = path.join(userDir, entry);
125
+ let a: Buffer;
126
+ try {
127
+ a = fs.readFileSync(twin);
128
+ } catch {
129
+ split.missing += 1;
130
+ continue;
131
+ }
132
+ const b = fs.readFileSync(path.join(sourceDir, entry));
133
+ if (a.equals(b)) split.identical += 1;
134
+ else if (stripOwnershipKeys(a) === stripOwnershipKeys(b)) split.provenanceOnly += 1;
135
+ else split.bodyDiff += 1;
136
+ }
137
+ return split;
138
+ }
139
+
140
+ function main(argv: readonly string[]): number {
141
+ const medianArg = argv.find((a) => a.startsWith('--measured-median='));
142
+ // The measured median cold-start payload, from the transcript census. Passed
143
+ // in rather than re-derived so this harness stays byte-only and offline.
144
+ const measuredMedian = medianArg ? Number(medianArg.split('=')[1]) : 230556;
145
+
146
+ const fixtureHome = fs.mkdtempSync(path.join(os.tmpdir(), 'scope-dedup-'));
147
+ const fixtureUserRules = path.join(fixtureHome, '.claude', 'rules');
148
+ const copied = copyRules(RULES_SOURCE, fixtureUserRules);
149
+
150
+ const source = snapshot(RULES_SOURCE);
151
+ const fixtureUser = snapshot(fixtureUserRules);
152
+
153
+ // --- the two conditions ---------------------------------------------------
154
+ const fixture = dedupableCount(fixtureUserRules, RULES_SOURCE);
155
+ const realUserRules = path.join(process.env['HOME'] ?? os.homedir(), '.claude', 'rules');
156
+ const control = dedupableCount(realUserRules, RULES_SOURCE);
157
+ const reach = fs.existsSync(realUserRules)
158
+ ? classifyReachability(realUserRules, RULES_SOURCE)
159
+ : { total: 0, identical: 0, provenanceOnly: 0, bodyDiff: 0, missing: 0 };
160
+
161
+ const before = fixtureUser.tokens + source.tokens; // both scopes load
162
+ const after = fixtureUser.tokens + (source.tokens - tokens(fixture.chars));
163
+ const removed = before - after;
164
+
165
+ const pct = (part: number, whole: number): string => `${((part / whole) * 100).toFixed(1)}%`;
166
+
167
+ const lines: string[] = [];
168
+ lines.push('C-3 measurement — scope de-duplication of the rule projection');
169
+ lines.push(` metric basis: chars/4 token estimate; rule source ${RULES_SOURCE}`);
170
+ lines.push('');
171
+ lines.push(`FIXTURE (consumer condition — same version at both scopes, ${copied} files copied)`);
172
+ lines.push(` user scope: ${fixtureUser.files} files, ${fixtureUser.tokens} tok`);
173
+ lines.push(` project scope: ${source.files} files, ${source.tokens} tok`);
174
+ lines.push(` byte-identical twins: ${fixture.skipped}/${source.files}`);
175
+ lines.push(` rules payload before: ${before} tok`);
176
+ lines.push(` rules payload after: ${after} tok`);
177
+ lines.push(` removed: ${removed} tok`);
178
+ lines.push('');
179
+ lines.push('REDUCTION vs the pre-registered denominators');
180
+ lines.push(` of measured median cold-start (${measuredMedian} tok): ${pct(removed, measuredMedian)}`);
181
+ lines.push(` of the two-scope rules payload (${before} tok): ${pct(removed, before)}`);
182
+ lines.push('');
183
+ lines.push('CONTROL (this machine — the dedup must be inert unless both scopes match)');
184
+ lines.push(` byte-identical twins: ${control.skipped}/${source.files}`);
185
+ lines.push(` removed: ${tokens(control.chars)} tok`);
186
+ lines.push('');
187
+ lines.push(`threshold: >= 15% of the measured median -> ${
188
+ removed / measuredMedian >= 0.15 ? 'MET' : 'NOT MET'
189
+ }`);
190
+ lines.push('');
191
+ lines.push('REACHABILITY of the fixture condition (why the control is not the fixture)');
192
+ lines.push(` identical: ${reach.identical}/${reach.total}`);
193
+ lines.push(` differ in body: ${reach.bodyDiff}/${reach.total} (closed by aligning versions)`);
194
+ lines.push(` differ ONLY in the ownership stamp: ${reach.provenanceOnly}/${reach.total}`);
195
+ lines.push(` absent at user scope: ${reach.missing}/${reach.total}`);
196
+ if (reach.identical === 0 && reach.bodyDiff + reach.provenanceOnly === reach.total) {
197
+ lines.push('');
198
+ lines.push(' -> Aligning versions would close the body diffs and leave the ownership');
199
+ lines.push(' stamp, so the reachable twin count is 0, NOT the fixture\'s figure.');
200
+ lines.push(' install.ts:2723/2725 stamp package:/source_path: into every installed');
201
+ lines.push(' rule unconditionally; the in-repo projection stamps nothing. Two');
202
+ lines.push(' writers, deliberately different output. Making this reachable was');
203
+ lines.push(' DECIDED AGAINST on 2026-07-31 (real install-path risk, empty recipient');
204
+ lines.push(' set) — see contexts/dedup-reachability-refusal.md for the analysis and');
205
+ lines.push(' the five reopen conditions. This 0 is expected, not a defect.');
206
+ lines.push(' Do NOT relax the byte predicate to make this number move: that');
207
+ lines.push(' predicate IS the content-neutrality argument.');
208
+ }
209
+ lines.push('');
210
+ lines.push('Content safety: only byte-identical twins are removed, so the host still');
211
+ lines.push('loads the same rule text in full — once instead of twice. No rule becomes');
212
+ lines.push('trigger-gated, which is what separates this from the disabled thin projection.');
213
+
214
+ process.stdout.write(lines.join('\n') + '\n');
215
+ fs.rmSync(fixtureHome, { recursive: true, force: true });
216
+ return 0;
217
+ }
218
+
219
+ if (process.argv[1] !== undefined && import.meta.url === `file://${process.argv[1]}`) {
220
+ process.exit(main(process.argv.slice(2)));
221
+ }
222
+
223
+ export { classifyReachability, dedupableCount, main };
224
+ export type { ReachabilitySplit };
Binary file
@@ -34,6 +34,8 @@ import * as os from 'node:os';
34
34
  import * as path from 'node:path';
35
35
  import { fileURLToPath, pathToFileURL } from 'node:url';
36
36
 
37
+ import { appendGlobalObservation, applySharedFactCap } from './_lib/user_global_observations.js';
38
+
37
39
  const _HERE = fileURLToPath(import.meta.url);
38
40
  // src/scripts/mine_session.py → parent.parent.parent == repo root.
39
41
  export const ROOT = path.resolve(path.dirname(_HERE), '..', '..');
@@ -296,6 +298,64 @@ function _nowIsoSeconds(): string {
296
298
  return new Date().toISOString().replace(/\.\d{3}Z$/, '+00:00');
297
299
  }
298
300
 
301
+ /** One candidate the user-scoped channel below may propose to the global observation buffer. */
302
+ export interface UserObservationSignal {
303
+ readonly ts: string;
304
+ readonly suggest: string;
305
+ readonly evidence: string;
306
+ }
307
+
308
+ /**
309
+ * The second, user-scoped channel (road-to-global-user-memory Phase 2).
310
+ * Scans the SAME entries `mine()` scans for the Preference family
311
+ * (`SIGNAL_FAMILIES`'s `'convention'` entry) and, for every match `mine()`
312
+ * would have silently discarded — because `_normalise` found no
313
+ * project-scoped path/symbol token, i.e. the match is about the USER, not
314
+ * the project — shapes a candidate observation instead of dropping it.
315
+ *
316
+ * Deliberately independent of `mine()`: it does not read or mutate `mine()`'s
317
+ * `facts` array, does not change `mine()`'s signature, return shape, or
318
+ * output, and does not touch disk. `mine()`'s byte-parity contract with the
319
+ * retired Python implementation is therefore untouched by this addition —
320
+ * this is a wholly new, additive export.
321
+ *
322
+ * The caller is responsible for the shared ≤5-per-cycle cap
323
+ * (`user_global_observations.applySharedFactCap`, counting THIS output
324
+ * together with `mine()`'s `facts.length`) and for guard evaluation +
325
+ * writing (`user_global_observations.appendGlobalObservation`) — this
326
+ * function only detects and shapes candidates.
327
+ */
328
+ export function mineUserObservationCandidates(
329
+ entries: Iterable<Record<string, Json>>,
330
+ since: Date,
331
+ ): UserObservationSignal[] {
332
+ const preferenceFamily = SIGNAL_FAMILIES.find(([tag]) => tag === 'convention')?.[1];
333
+ if (!preferenceFamily) {
334
+ return [];
335
+ }
336
+ const out: UserObservationSignal[] = [];
337
+ for (const turn of entries) {
338
+ const tsStr = _turnTs(turn);
339
+ if (!_withinWindow(tsStr, since)) {
340
+ continue;
341
+ }
342
+ const text = _turnText(turn);
343
+ if (!text || !_search(preferenceFamily, text)) {
344
+ continue;
345
+ }
346
+ // Project-scoped → mine()'s job, not this channel.
347
+ if (_search(PATH_TOKEN, text) || _search(SYMBOL_TOKEN, text)) {
348
+ continue;
349
+ }
350
+ const cleaned = _redact(text, []).replace(/\s+/g, ' ').trim().slice(0, 240);
351
+ if (!cleaned) {
352
+ continue;
353
+ }
354
+ out.push({ ts: tsStr || _nowIsoSeconds(), suggest: cleaned, evidence: cleaned });
355
+ }
356
+ return out;
357
+ }
358
+
299
359
  export function renderPreview(
300
360
  facts: Array<Record<string, Json>>,
301
361
  project: string,
@@ -619,6 +679,44 @@ export function main(argv: string[] | null = null): number {
619
679
  'files.\n Next: /memory promote to lift validated lines ' +
620
680
  'into curated YAML.\n',
621
681
  );
682
+ // Second channel (road-to-global-user-memory Phase 2): the preference
683
+ // signals `mine()` discards because they are about the USER, not the
684
+ // project, reach the global buffer instead of /dev/null. The ≤5 cap is
685
+ // SHARED — the project channel's facts are counted first, so this channel
686
+ // only ever uses the leftover headroom.
687
+ //
688
+ // `entries` is a consumed generator by now, so the source is re-read.
689
+ // Appending still goes through every capture guard and the redaction gate;
690
+ // nothing here can write `profile.md` — only a human `accept` does that.
691
+ const observationEntries =
692
+ kind === 'chat-history' ? _iterChatHistory(srcPath) : _iterClaudeCodeJsonl(srcPath);
693
+ const candidates = applySharedFactCap(
694
+ facts.length,
695
+ mineUserObservationCandidates(observationEntries, since),
696
+ );
697
+ let appended = 0;
698
+ const refused: string[] = [];
699
+ for (const candidate of candidates) {
700
+ const result = appendGlobalObservation({
701
+ ts: candidate.ts,
702
+ field: 'notes',
703
+ suggest: candidate.suggest,
704
+ source: 'mine_session',
705
+ evidence: candidate.evidence,
706
+ });
707
+ if (result.written) {
708
+ appended += 1;
709
+ } else if (result.category !== undefined) {
710
+ refused.push(result.category);
711
+ }
712
+ }
713
+ if (candidates.length > 0) {
714
+ const detail = refused.length > 0 ? ` (${refused.length} refused: ${refused.join(', ')})` : '';
715
+ process.stdout.write(
716
+ `✅ Appended ${appended} user observation(s) to the global buffer${detail}.\n` +
717
+ ' Next: /agents user review to accept or drop them.\n',
718
+ );
719
+ }
622
720
  return 0;
623
721
  }
624
722
 
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Payload-hash × cache-hit drift report — CLI.
4
+ *
5
+ * `road-to-cache-economy.md` Phase 3, steps 6-7. Reads the
6
+ * accumulated audit-log-v1 telemetry (reuses `readAuditLines` from
7
+ * `orchestration_savings_report.ts` — the same reader, not a reimplementation)
8
+ * and joins `orchestration.payload_hash` against `orchestration.cache_hit`
9
+ * per {@link aggregatePayloadHashDrift}'s cohort split, so prefix-stability
10
+ * drift becomes visible.
11
+ *
12
+ * REFUSAL (step 7 — report it, never act on it): `cache_hit` is a
13
+ * provider-reported proxy for HOST-controlled cache behaviour, not a metric
14
+ * this package causes or controls. Per ADR-118's automation threshold (§1:
15
+ * a direct measure, a low false-positive rate, and no unique human
16
+ * judgement required — all three, or it stays manual), a host-controlled
17
+ * proxy fails condition 1 outright. This report NEVER wires a measure→adjust
18
+ * step off these two fields — no default flip, no tier change, no dispatch
19
+ * throttle. It is read-only, always.
20
+ *
21
+ * Zero recorded lines with BOTH fields is the CURRENT expected state — both
22
+ * fields are lean-init extensions with no caller wiring a real value into
23
+ * them yet (per the roadmap's own defect list). This report says so
24
+ * explicitly rather than presenting empty input as a green result.
25
+ *
26
+ * Usage:
27
+ * ./scripts-run src/scripts/orchestration_payload_hash_drift [--dir <path>] [--format text|json]
28
+ *
29
+ * Default dir: agents/runtime/state/audit (the audit-log-v1 path, matching
30
+ * `orchestration_savings_report.ts`'s default).
31
+ */
32
+ import * as path from 'node:path';
33
+ import { pathToFileURL } from 'node:url';
34
+
35
+ import { aggregatePayloadHashDrift, type PayloadHashDriftReport, type PayloadHashLine } from './_lib/payload_hash_drift.js';
36
+ import { readAuditLines } from './orchestration_savings_report.js';
37
+
38
+ const DEFAULT_DIR = 'agents/runtime/state/audit';
39
+
40
+ export interface Options {
41
+ dir: string;
42
+ format: 'text' | 'json';
43
+ }
44
+
45
+ export function parseArgs(argv: string[]): Options {
46
+ const opts: Options = { dir: DEFAULT_DIR, format: 'text' };
47
+ for (let i = 0; i < argv.length; i++) {
48
+ const a = argv[i];
49
+ if (a === undefined) continue;
50
+ if (a === '--dir') opts.dir = argv[++i] ?? opts.dir;
51
+ else if (a.startsWith('--dir=')) opts.dir = a.slice('--dir='.length);
52
+ else if (a === '--format') opts.format = (argv[++i] as Options['format']) ?? opts.format;
53
+ else if (a.startsWith('--format=')) opts.format = a.slice('--format='.length) as Options['format'];
54
+ }
55
+ if (opts.format !== 'text' && opts.format !== 'json') opts.format = 'text';
56
+ return opts;
57
+ }
58
+
59
+ interface RawOrchestrationHashFields {
60
+ payload_hash?: unknown;
61
+ cache_hit?: unknown;
62
+ }
63
+ interface RawHashLine {
64
+ input_kind?: unknown;
65
+ orchestration?: RawOrchestrationHashFields;
66
+ }
67
+
68
+ /** Reads only the two fields this report needs, tolerant of any pre-extension line missing them. */
69
+ function toPayloadHashLine(raw: unknown): PayloadHashLine {
70
+ const line = (raw ?? {}) as RawHashLine;
71
+ if (line.input_kind !== 'orchestration' || !line.orchestration) {
72
+ return { payload_hash: null, cache_hit: null };
73
+ }
74
+ const hash = line.orchestration.payload_hash;
75
+ const hit = line.orchestration.cache_hit;
76
+ return {
77
+ payload_hash: typeof hash === 'string' && hash.length > 0 ? hash : null,
78
+ cache_hit: typeof hit === 'boolean' ? hit : null,
79
+ };
80
+ }
81
+
82
+ export function buildReport(dir: string): PayloadHashDriftReport {
83
+ const rawLines: unknown[] = readAuditLines(dir);
84
+ const lines = rawLines.map(toPayloadHashLine);
85
+ return aggregatePayloadHashDrift(lines);
86
+ }
87
+
88
+ function pct(v: number): string {
89
+ return `${(v * 100).toFixed(1)}%`;
90
+ }
91
+
92
+ export function renderText(r: PayloadHashDriftReport): string {
93
+ const out: string[] = [];
94
+ out.push('Payload-hash × cache-hit drift report');
95
+ out.push(` total audit-log-v1 lines seen: ${r.total_lines}`);
96
+ out.push(` lines carrying BOTH payload_hash and cache_hit: ${r.lines_with_data}`);
97
+ out.push('');
98
+
99
+ if (r.lines_with_data === 0) {
100
+ out.push(
101
+ 'No recorded lines carry both fields yet — this is the CURRENT expected state (both are lean-init',
102
+ );
103
+ out.push(
104
+ 'extensions; no caller wires a real value into them today). The reader works; there is nothing to',
105
+ );
106
+ out.push('report on. This is NOT presented as a green pass — it is an honest empty state.');
107
+ } else {
108
+ out.push(
109
+ `stable cohort (repeat occurrences of a hash — the prior write should already be cached): n=${r.stable_cohort.n} ` +
110
+ `hit_rate=${r.stable_cohort.hit_rate !== null ? pct(r.stable_cohort.hit_rate) : 'n/a'}`,
111
+ );
112
+ out.push(
113
+ `unstable cohort (hashes seen exactly once — a payload that never repeats): n=${r.unstable_cohort.n} ` +
114
+ `hit_rate=${r.unstable_cohort.hit_rate !== null ? pct(r.unstable_cohort.hit_rate) : 'n/a'}`,
115
+ );
116
+ out.push(`drift_visible (stable hit_rate > unstable hit_rate): ${r.drift_visible ? 'YES' : 'no'}`);
117
+ out.push('');
118
+ out.push('Per-hash breakdown (most-occurrences first):');
119
+ for (const g of r.groups) {
120
+ out.push(` ${g.payload_hash}: occurrences=${g.occurrences} hit_rate=${pct(g.hit_rate)}`);
121
+ }
122
+ }
123
+
124
+ out.push('');
125
+ out.push('REFUSAL (report, never act): cache_hit is a proxy for host-controlled cache behaviour, not a');
126
+ out.push('metric this package controls. Per ADR-118 §1, a host-controlled proxy fails the direct-measure');
127
+ out.push('condition outright — this report never wires a measure→adjust step off these two fields.');
128
+ return out.join('\n');
129
+ }
130
+
131
+ export function main(argv: string[] = process.argv.slice(2)): number {
132
+ const opts = parseArgs(argv);
133
+ const report = buildReport(opts.dir);
134
+ if (opts.format === 'json') {
135
+ process.stdout.write(JSON.stringify(report, null, 2) + '\n');
136
+ } else {
137
+ process.stdout.write(renderText(report) + '\n');
138
+ }
139
+ return 0;
140
+ }
141
+
142
+ if (process.argv[1] !== undefined) {
143
+ const invokedUrl = pathToFileURL(path.resolve(process.argv[1])).href;
144
+ if (import.meta.url === invokedUrl) process.exit(main());
145
+ }