@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
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Measure the encoding floor against the FROZEN corpus
4
+ * (road-to-runtime-encoding-hardening Phase 4).
5
+ *
6
+ * Renders the numbers from the corpus — never hand-typed — and evaluates them
7
+ * against the thresholds the roadmap pre-registered BEFORE the detector existed:
8
+ *
9
+ * recall on in-scope positives >= 0.95
10
+ * recall on unambiguous classes >= 0.99
11
+ * (zero-width, bidi, variation-selector)
12
+ * false-positive rate on clean negatives <= 0.005
13
+ * added runtime model spend == 0 (structural: no model call)
14
+ * added latency < 2 ms p95 per message
15
+ *
16
+ * A positive counts as DETECTED when the floor either strips its signal
17
+ * (`sanitize_text` changed the value) or reports it (`scan_encoding_findings`
18
+ * returned a finding). Both are "the vector did not reach the model unnoticed",
19
+ * which is the property under test.
20
+ *
21
+ * Usage:
22
+ * encoding_corpus_report # human summary + exit 1 if a gate fails
23
+ * encoding_corpus_report --json # machine payload
24
+ */
25
+ import * as fs from 'node:fs';
26
+ import * as path from 'node:path';
27
+ import { fileURLToPath, pathToFileURL } from 'node:url';
28
+
29
+ import { OUT_DIR, type CorpusEntry } from './encoding_corpus.js';
30
+ import { sanitize_text, scan_encoding_findings } from './_lib/retrieval_sanitize.js';
31
+
32
+ /** Pre-registered acceptance thresholds — do not edit to make a run pass. */
33
+ export const THRESHOLDS = {
34
+ recall_all: 0.95,
35
+ recall_unambiguous: 0.99,
36
+ fp_rate_max: 0.005,
37
+ latency_p95_ms_max: 2,
38
+ } as const;
39
+
40
+ /** Classes the roadmap singled out as unambiguous → higher recall bar. */
41
+ export const UNAMBIGUOUS_CHANNELS: readonly string[] = [
42
+ 'zero-width',
43
+ 'zero-width-joiner-bom',
44
+ 'bidi-control',
45
+ 'variation-selector-run',
46
+ ];
47
+
48
+ function _readJsonl(name: string): CorpusEntry[] {
49
+ return fs
50
+ .readFileSync(path.join(OUT_DIR, name), 'utf-8')
51
+ .split('\n')
52
+ .filter((l) => l !== '')
53
+ .map((l) => JSON.parse(l) as CorpusEntry);
54
+ }
55
+
56
+ /** True when the floor either stripped or reported the entry's signal. */
57
+ export function detected(text: string): { hit: boolean; stripped: boolean; flagged: boolean } {
58
+ const stripped = sanitize_text(text) !== text;
59
+ const flagged = scan_encoding_findings(text).length > 0;
60
+ return { hit: stripped || flagged, stripped, flagged };
61
+ }
62
+
63
+ export interface Report {
64
+ readonly corpus: { positives: number; negatives: number };
65
+ readonly recall_all: number;
66
+ readonly recall_unambiguous: number;
67
+ readonly fp_rate: number;
68
+ readonly per_channel: Record<string, { n: number; detected: number; recall: number }>;
69
+ readonly false_positives: readonly string[];
70
+ readonly latency_p95_ms: number;
71
+ readonly model_calls: 0;
72
+ readonly gates: Record<string, { value: number; threshold: number; pass: boolean }>;
73
+ readonly verdict: 'ADOPT' | 'DETECT-AND-FLAG-ONLY' | 'FAIL';
74
+ }
75
+
76
+ function _p95(samples: readonly number[]): number {
77
+ const sorted = [...samples].sort((a, b) => a - b);
78
+ const idx = Math.min(sorted.length - 1, Math.floor(sorted.length * 0.95));
79
+ return sorted[idx] ?? 0;
80
+ }
81
+
82
+ export function measure(): Report {
83
+ const positives = _readJsonl('positives.jsonl');
84
+ const negatives = _readJsonl('negatives.jsonl');
85
+
86
+ const perChannel: Record<string, { n: number; detected: number; recall: number }> = {};
87
+ const latencies: number[] = [];
88
+ let hits = 0;
89
+ for (const e of positives) {
90
+ const t0 = process.hrtime.bigint();
91
+ const d = detected(e.text);
92
+ latencies.push(Number(process.hrtime.bigint() - t0) / 1e6);
93
+ const slot = perChannel[e.channel] ?? { n: 0, detected: 0, recall: 0 };
94
+ slot.n += 1;
95
+ if (d.hit) {
96
+ slot.detected += 1;
97
+ hits += 1;
98
+ }
99
+ slot.recall = slot.detected / slot.n;
100
+ perChannel[e.channel] = slot;
101
+ }
102
+
103
+ const falsePositives: string[] = [];
104
+ for (const e of negatives) {
105
+ const t0 = process.hrtime.bigint();
106
+ const d = detected(e.text);
107
+ latencies.push(Number(process.hrtime.bigint() - t0) / 1e6);
108
+ if (d.hit) falsePositives.push(`${e.id}: ${e.text.slice(0, 90)}`);
109
+ }
110
+
111
+ const unambiguous = positives.filter((e) => UNAMBIGUOUS_CHANNELS.includes(e.channel));
112
+ const unambiguousHits = unambiguous.filter((e) => detected(e.text).hit).length;
113
+
114
+ const recallAll = positives.length === 0 ? 0 : hits / positives.length;
115
+ const recallUnambiguous = unambiguous.length === 0 ? 0 : unambiguousHits / unambiguous.length;
116
+ const fpRate = negatives.length === 0 ? 0 : falsePositives.length / negatives.length;
117
+ const p95 = _p95(latencies);
118
+
119
+ const gates = {
120
+ recall_all: { value: recallAll, threshold: THRESHOLDS.recall_all, pass: recallAll >= THRESHOLDS.recall_all },
121
+ recall_unambiguous: {
122
+ value: recallUnambiguous,
123
+ threshold: THRESHOLDS.recall_unambiguous,
124
+ pass: recallUnambiguous >= THRESHOLDS.recall_unambiguous,
125
+ },
126
+ fp_rate: { value: fpRate, threshold: THRESHOLDS.fp_rate_max, pass: fpRate <= THRESHOLDS.fp_rate_max },
127
+ latency_p95_ms: {
128
+ value: p95,
129
+ threshold: THRESHOLDS.latency_p95_ms_max,
130
+ pass: p95 < THRESHOLDS.latency_p95_ms_max,
131
+ },
132
+ };
133
+
134
+ // The roadmap's pre-registered branch: recall clears but FP is over budget →
135
+ // ship detect-and-flag only, never automatic quarantine, and publish the FP
136
+ // number. Nothing here quarantines anyway, so this records which branch the
137
+ // measurement selected rather than switching behaviour after the fact.
138
+ const recallOk = gates.recall_all.pass && gates.recall_unambiguous.pass;
139
+ const verdict: Report['verdict'] = !recallOk
140
+ ? 'FAIL'
141
+ : gates.fp_rate.pass && gates.latency_p95_ms.pass
142
+ ? 'ADOPT'
143
+ : 'DETECT-AND-FLAG-ONLY';
144
+
145
+ return {
146
+ corpus: { positives: positives.length, negatives: negatives.length },
147
+ recall_all: recallAll,
148
+ recall_unambiguous: recallUnambiguous,
149
+ fp_rate: fpRate,
150
+ per_channel: perChannel,
151
+ false_positives: falsePositives,
152
+ latency_p95_ms: p95,
153
+ model_calls: 0,
154
+ gates,
155
+ verdict,
156
+ };
157
+ }
158
+
159
+ function _render(r: Report): string {
160
+ const pct = (n: number): string => (n * 100).toFixed(2) + '%';
161
+ const lines: string[] = [];
162
+ lines.push(`corpus: ${r.corpus.positives} positives · ${r.corpus.negatives} negatives`);
163
+ lines.push('');
164
+ lines.push('per-channel recall');
165
+ for (const [ch, s] of Object.entries(r.per_channel).sort()) {
166
+ const mark = s.recall === 1 ? ' ' : '!!';
167
+ lines.push(` ${mark} ${ch.padEnd(24)} ${s.detected}/${s.n} ${pct(s.recall)}`);
168
+ }
169
+ lines.push('');
170
+ for (const [name, g] of Object.entries(r.gates)) {
171
+ const cmp = name === 'fp_rate' || name === 'latency_p95_ms' ? '<=' : '>=';
172
+ const val = name === 'latency_p95_ms' ? `${g.value.toFixed(3)} ms` : pct(g.value);
173
+ const thr = name === 'latency_p95_ms' ? `${g.threshold} ms` : pct(g.threshold);
174
+ lines.push(` ${g.pass ? 'PASS' : 'FAIL'} ${name.padEnd(20)} ${val} ${cmp} ${thr}`);
175
+ }
176
+ lines.push(` PASS ${'model_calls'.padEnd(20)} 0 (structural: no model call on this path)`);
177
+ if (r.false_positives.length > 0) {
178
+ lines.push('');
179
+ lines.push(`false positives (${r.false_positives.length}):`);
180
+ for (const fp of r.false_positives.slice(0, 12)) lines.push(` - ${fp}`);
181
+ if (r.false_positives.length > 12) {
182
+ lines.push(` … ${r.false_positives.length - 12} more`);
183
+ }
184
+ }
185
+ lines.push('');
186
+ lines.push(`verdict: ${r.verdict}`);
187
+ return lines.join('\n') + '\n';
188
+ }
189
+
190
+ export function main(argv: readonly string[] | null = null): number {
191
+ const args = argv ?? process.argv.slice(2);
192
+ const r = measure();
193
+ if (args.includes('--json')) {
194
+ process.stdout.write(JSON.stringify(r, null, 2) + '\n');
195
+ } else {
196
+ process.stdout.write(_render(r));
197
+ }
198
+ return r.verdict === 'FAIL' ? 1 : 0;
199
+ }
200
+
201
+ declare const __AGENT_CONFIG_BUNDLE__: boolean | undefined;
202
+ function _isCliEntry(): boolean {
203
+ if (typeof __AGENT_CONFIG_BUNDLE__ !== 'undefined' && __AGENT_CONFIG_BUNDLE__) return false;
204
+ if (process.argv[1] === undefined) return false;
205
+ const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
206
+ if (import.meta.url === argvUrl) return true;
207
+ try {
208
+ return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(process.argv[1]));
209
+ } catch {
210
+ return false;
211
+ }
212
+ }
213
+
214
+ if (_isCliEntry()) {
215
+ process.exitCode = main();
216
+ }
@@ -25,6 +25,7 @@ import {
25
25
  strip_source_prefix,
26
26
  } from './_lib/agent_src.js';
27
27
  import { computeStatus as domainSoundnessStatus } from './domain_soundness_status.js';
28
+ import { skip_compile_disabled_rule } from './condense.js';
28
29
 
29
30
  const _HERE = fileURLToPath(import.meta.url);
30
31
 
@@ -243,6 +244,12 @@ export function _collect_skills(): Entry[] {
243
244
  return _sortedKeys(seen).map((k) => seen.get(k) as Entry);
244
245
  }
245
246
 
247
+ // docs/catalog.md is a SHIPPED file, so a relative link from it must resolve inside
248
+ // package.json#files. docs/proof.md is not shipped and cannot be: it is 58KB of
249
+ // generated output linking eight paths under internal/bench/, tests/ and src/scripts/
250
+ // that are themselves unshipped, so shipping it would hand consumers a page of dead
251
+ // links. The published site URL is the honest target for a consumer-facing pointer.
252
+
246
253
  export function _collect_rules(): Entry[] {
247
254
  const seen = new Map<string, Entry>();
248
255
  for (const srcRoot of artefact_roots()) {
@@ -255,6 +262,14 @@ export function _collect_rules(): Entry[] {
255
262
  if (seen.has(stem)) {
256
263
  continue;
257
264
  }
265
+ // A compile-disabled rule has no dist/agent-src/ counterpart, and the
266
+ // table links the SHIPPED path — so listing it emits a dead link. The
267
+ // toggle is a separate axis from the source file's existence; this is its
268
+ // fifth consumer after the router compiler, the dist writer, check_sync,
269
+ // and the per-tool symlink generator. Same predicate in all five.
270
+ if (skip_compile_disabled_rule(`rules/${stem}.md`)) {
271
+ continue;
272
+ }
258
273
  const fm = _parse_frontmatter(fs.readFileSync(ruleMd, 'utf-8'));
259
274
  seen.set(stem, {
260
275
  kind: 'rule',
@@ -420,7 +435,8 @@ export function _render_catalog(
420
435
  '> not yet. Coverage is reported per tier (`./scripts-run',
421
436
  '> src/scripts/skill_eval_coverage`) and CI-ratcheted so it can only rise.',
422
437
  '> Listing here never implies a skill is behaviourally tested — the',
423
- '> current coverage and its gap are published on [the proof page](proof.md).',
438
+ '> current coverage and its gap are published on [the proof page]' +
439
+ '(https://event4u-app.github.io/agent-config/proof/).',
424
440
  '',
425
441
  '> **Non-coding domain correctness is scoped, not proven.** The',
426
442
  '> `finance` / `founder` / `ops` / `content` skills are forged on TS/PHP',
@@ -429,7 +445,8 @@ export function _render_catalog(
429
445
  '> cited formulas, or rubric targets matching a named external practice);',
430
446
  '> the rest are labeled `unvalidated` until they pass one',
431
447
  '> (`./scripts-run src/scripts/domain_soundness_status`). A disclaimer',
432
- '> floor bounds liability, not correctness — see [the proof page](proof.md).',
448
+ '> floor bounds liability, not correctness — see [the proof page]' +
449
+ '(https://event4u-app.github.io/agent-config/proof/).',
433
450
  '',
434
451
  _render_table(skills, ['kind', 'name', 'source', 'description'], '../', _to_shipped_path),
435
452
  '',
@@ -30,8 +30,8 @@ cat > "$HOOKS_DIR/pre-push" << 'EOF'
30
30
  # the old hook only verified dist sync + the COMMAND count — it missed
31
31
  # guideline/skill/rule count drift and the generate-tools / router / corpus
32
32
  # outputs (e.g. a new guideline bumping the count in README + docs/architecture).
33
- # `task consistency` is the EXACT CI mirror (sync-check + sync-check-hashes +
34
- # sync + generate-tools + compile-router + compile-corpus + `git diff --quiet`),
33
+ # `task consistency` is the EXACT CI mirror (sync-check + sync + generate-tools
34
+ # + compile-router + compile-corpus + `git diff --quiet`),
35
35
  # so any derived-output drift blocks the push here. Runtime ~15-40s (it
36
36
  # regenerates the tool trees) — cheaper than a red CI run and a fixup re-push.
37
37
 
Binary file
@@ -34,86 +34,24 @@ import * as fs from 'node:fs';
34
34
  import { fileURLToPath, pathToFileURL } from 'node:url';
35
35
 
36
36
  import * as sl from './_lib/security_lint.js';
37
+ import { TOKEN_RE, classifyToken } from './_lib/confusables.js';
37
38
 
38
39
  export const CHECK = 'mixed-script-confusable';
39
40
 
40
- const MIN_LETTERS = 3;
41
-
42
- // Unicode-script classifiers via property escapes (requires the `u` flag).
43
- const _LATIN = /\p{Script=Latin}/u;
44
- const _CYRILLIC = /\p{Script=Cyrillic}/u;
45
- const _GREEK = /\p{Script=Greek}/u;
46
- const _LETTER = /\p{L}/u;
47
- // A "token" is a maximal run of letters / combining marks / decimal digits.
48
- const _TOKEN = /[\p{L}\p{M}\p{Nd}]+/gu;
49
-
50
- // Cyrillic + Greek codepoints that have a basic-Latin lookalike (Unicode TR39
51
- // confusables, common subset). A foreign letter only counts toward the
52
- // confusable signal when it is in this set — Greek math operators with no Latin
53
- // twin (Δ Σ Π Ω Φ Θ Λ Ξ Ψ Γ δ π ω …) are deliberately excluded so legit
54
- // notation does not false-positive.
55
- const _CONFUSABLE_FOREIGN: ReadonlySet<number> = new Set([
56
- // Cyrillic lowercase ↔ Latin
57
- 0x0430 /*а→a*/, 0x0435 /*е→e*/, 0x043e /*о→o*/, 0x0440 /*р→p*/, 0x0441 /*с→c*/,
58
- 0x0443 /*у→y*/, 0x0445 /*х→x*/, 0x0455 /*ѕ→s*/, 0x0456 /*і→i*/, 0x0458 /*ј→j*/,
59
- 0x04bb /*һ→h*/, 0x0501 /*ԁ→d*/, 0x051b /*ԛ→q*/, 0x0577 /*no*/,
60
- // Cyrillic uppercase ↔ Latin
61
- 0x0410 /*А→A*/, 0x0412 /*В→B*/, 0x0415 /*Е→E*/, 0x041a /*К→K*/, 0x041c /*М→M*/,
62
- 0x041d /*Н→H*/, 0x041e /*О→O*/, 0x0420 /*Р→P*/, 0x0421 /*С→C*/, 0x0422 /*Т→T*/,
63
- 0x0423 /*У→Y*/, 0x0425 /*Х→X*/, 0x0405 /*Ѕ→S*/, 0x0406 /*І→I*/, 0x0408 /*Ј→J*/,
64
- // Greek lowercase ↔ Latin
65
- 0x03b1 /*α→a*/, 0x03b5 /*ε→e*/, 0x03bf /*ο→o*/, 0x03bd /*ν→v*/, 0x03c1 /*ρ→p*/,
66
- 0x03c5 /*υ→u*/, 0x03c7 /*χ→x*/, 0x03ba /*κ→k*/,
67
- // Greek uppercase ↔ Latin (only those with a real Latin twin)
68
- 0x0391 /*Α→A*/, 0x0392 /*Β→B*/, 0x0395 /*Ε→E*/, 0x0396 /*Ζ→Z*/, 0x0397 /*Η→H*/,
69
- 0x0399 /*Ι→I*/, 0x039a /*Κ→K*/, 0x039c /*Μ→M*/, 0x039d /*Ν→N*/, 0x039f /*Ο→O*/,
70
- 0x03a1 /*Ρ→P*/, 0x03a4 /*Τ→T*/, 0x03a5 /*Υ→Y*/, 0x03a7 /*Χ→X*/, 0x0392 /*Β→B*/,
71
- ]);
72
-
73
- type ScriptName = 'latin' | 'cyrillic' | 'greek' | 'other';
74
-
75
- function _script_of(ch: string): ScriptName {
76
- if (_LATIN.test(ch)) return 'latin';
77
- if (_CYRILLIC.test(ch)) return 'cyrillic';
78
- if (_GREEK.test(ch)) return 'greek';
79
- return 'other';
80
- }
41
+ // The confusable table + the mixed-script decision rule live in ONE place so
42
+ // this authoring-time linter and the runtime encoding scanner cannot drift apart
43
+ // (road-to-runtime-encoding-hardening Phase 3). `_classify_token` stays exported
44
+ // under its original name — it is this module's published surface and its tests
45
+ // address it here.
46
+ const _TOKEN = TOKEN_RE;
81
47
 
82
48
  /**
83
49
  * Classify a single token. Returns the offending mixed-script descriptor when
84
50
  * the token matches the homoglyph signature, else null.
51
+ *
52
+ * Thin re-export of the shared implementation — see `_lib/confusables.ts`.
85
53
  */
86
- export function _classify_token(token: string): string | null {
87
- let latin = 0;
88
- let cyrillic = 0;
89
- let greek = 0;
90
- let letters = 0;
91
- for (const ch of token) {
92
- if (!_LETTER.test(ch)) continue; // skip combining marks / digits for script vote
93
- letters += 1;
94
- const script = _script_of(ch);
95
- if (script === 'latin') {
96
- latin += 1;
97
- } else if (script === 'cyrillic' || script === 'greek') {
98
- // Only confusable foreign letters (TR39) count — math operators with
99
- // no Latin twin are ignored, so legit notation never trips.
100
- if (_CONFUSABLE_FOREIGN.has(ch.codePointAt(0) as number)) {
101
- if (script === 'cyrillic') cyrillic += 1;
102
- else greek += 1;
103
- }
104
- }
105
- }
106
- if (letters < MIN_LETTERS) return null;
107
- const foreign = cyrillic + greek;
108
- if (latin === 0 || foreign === 0) return null; // single-script (or no Latin) → legit
109
- if (latin <= foreign) return null; // majority must be Latin (foreign word ≠ attack)
110
- const which = cyrillic > 0 && greek > 0
111
- ? 'cyrillic+greek'
112
- : cyrillic > 0
113
- ? 'cyrillic'
114
- : 'greek';
115
- return `latin+${which} (${latin} latin / ${foreign} foreign-confusable)`;
116
- }
54
+ export const _classify_token = classifyToken;
117
55
 
118
56
  export function _scan(sf: sl.ScannedFile): sl.Finding[] {
119
57
  if (sf.pragma_allows(CHECK)) {
Binary file
@@ -30,6 +30,7 @@
30
30
 
31
31
  import * as fs from 'node:fs';
32
32
  import * as path from 'node:path';
33
+ import { spawnSync } from 'node:child_process';
33
34
  import { fileURLToPath, pathToFileURL } from 'node:url';
34
35
 
35
36
  import * as sl from './_lib/security_lint.js';
@@ -261,6 +262,191 @@ export function _scan(sf: sl.ScannedFile): sl.Finding[] {
261
262
  return out;
262
263
  }
263
264
 
265
+ // ---------------------------------------------------------------------------
266
+ // Source-file pass — raw C0 control bytes make a text file INVISIBLE to tools
267
+ // ---------------------------------------------------------------------------
268
+ //
269
+ // The `.md` corpus pass above defends the model's eyes. This pass defends the
270
+ // *reviewer's* and the *gate's* eyes, which is a different failure.
271
+ //
272
+ // A raw control byte (NUL above all) in a text-intended source file makes
273
+ // `file(1)`, `grep`, and every tool that sniffs for binary content classify the
274
+ // file as binary and SKIP IT SILENTLY. A linter grepping such a file reads
275
+ // nothing and reports clean; an agent gathering evidence concludes the code
276
+ // does not exist. That is indistinguishable from a pass, which is the point.
277
+ //
278
+ // Discovered the hard way: `road-to-runtime-encoding-hardening` was authored on
279
+ // the premise that `memory_lookup.ts` had "zero imports" and that the sanitize
280
+ // floor therefore ran nowhere. The file simply carried a raw NUL as a composite
281
+ // map-key separator, so `grep` never read it. The premise was a measurement
282
+ // artifact. See `agents/evidence/reports/nul-byte-source-census.md`.
283
+ //
284
+ // Precision by construction — this pass flags ONLY raw C0 controls, never the
285
+ // invisible/confusable classes `_scan` owns. In a `.ts` file a real bidi or
286
+ // zero-width codepoint is usually a deliberate test fixture or a regex
287
+ // character class (this repo has several, legitimately), so flagging those here
288
+ // would demand an allowlist that grows until the gate is worthless. A raw
289
+ // control byte has NO legitimate use in text-intended source: the language
290
+ // escape (`\0`, `\x01`) compiles to the identical runtime string and keeps the
291
+ // file readable by tools. The fix is always available, so the false-positive
292
+ // rate is structurally zero rather than merely low.
293
+
294
+ /** Extensions whose content is legitimately binary — never flagged. */
295
+ const _BINARY_EXT: ReadonlySet<string> = new Set([
296
+ 'png', 'jpg', 'jpeg', 'gif', 'ico', 'webp', 'avif', 'bmp', 'tiff',
297
+ 'pdf', 'woff', 'woff2', 'ttf', 'otf', 'eot',
298
+ 'zip', 'gz', 'tgz', 'bz2', 'xz', 'zst', '7z', 'rar',
299
+ 'wasm', 'mp3', 'mp4', 'wav', 'ogg', 'webm', 'mov', 'avi',
300
+ 'so', 'dylib', 'dll', 'node', 'a', 'o', 'exe',
301
+ 'jar', 'class', 'pyc', 'pyo',
302
+ 'db', 'sqlite', 'sqlite3', 'bin', 'dat',
303
+ 'docx', 'xlsx', 'pptx', 'doc', 'xls', 'ppt', 'odt', 'ods', 'odp',
304
+ ]);
305
+
306
+ /**
307
+ * Generated trees — skipped, because this is an AUTHORING rule.
308
+ *
309
+ * `dist/` and the per-tool projections are outputs of `src/` (see the
310
+ * `source-of-truth` rule: a projection is never edited by hand). Flagging a
311
+ * control byte there would point the author at a file they must not touch, and
312
+ * `dist/install/*.mjs` is a bundler artifact whose bytes are not even
313
+ * hand-authorable. Fix the source; the projection follows on `task sync`.
314
+ */
315
+ const _GENERATED_PREFIXES: readonly string[] = [
316
+ 'dist/',
317
+ '.augment/',
318
+ '.claude/',
319
+ '.cursor/',
320
+ '.clinerules/',
321
+ // Verbatim captured tool output, not authored text. These are RECORDINGS:
322
+ // escaping a control byte inside one would falsify the record it exists to
323
+ // preserve. If a capture needs to stay grep-readable, the fix is to escape
324
+ // at capture time — never to edit the artifact afterwards.
325
+ 'agents/evidence/analysis/',
326
+ // The frozen hostile-encoding corpus. Its positives ARE raw control
327
+ // characters — that is the thing under test, so flagging them would demand
328
+ // escaping the fixtures and thereby delete the test. The corpus has its own,
329
+ // stronger integrity controls: a sha256 freeze plus a scope-guard test that
330
+ // is itself falsified by an out-of-scope fixture. Excluded here because it
331
+ // is DATA, on the same principle as the captures above.
332
+ 'internal/bench/corpora/encoding-channels/',
333
+ ];
334
+
335
+ function _isGenerated(rel: string): boolean {
336
+ return _GENERATED_PREFIXES.some((p) => rel.startsWith(p));
337
+ }
338
+
339
+ /**
340
+ * True for a raw control CODEPOINT that is not benign whitespace.
341
+ *
342
+ * Codepoints, not bytes, and that distinction is the whole point. A first cut
343
+ * of this pass tested bytes ≤ 0x1F and let two classes through: DEL (U+007F,
344
+ * a single byte above the range) and the C1 controls (U+0080–009F, which encode
345
+ * to a two-byte UTF-8 sequence containing no byte ≤ 0x1F). Both make `file(1)`
346
+ * and git classify a file as binary — `tests/scripts/retrieval_sanitize.test.ts`
347
+ * carried U+007F and U+009F, rendered as `Bin` in `git diff`, unreviewable on a
348
+ * PR, and passed the byte-level check. A gate that misses the thing it exists to
349
+ * catch is the failure this whole roadmap is about, so the range now matches
350
+ * `_classify`'s: C0 + DEL + C1, minus tab / LF / CR.
351
+ */
352
+ function _isRawControlCodepoint(cp: number): boolean {
353
+ if (cp === 0x09 || cp === 0x0a || cp === 0x0d) return false;
354
+ return cp <= 0x1f || (cp >= 0x7f && cp <= 0x9f);
355
+ }
356
+
357
+ function _extensionOf(rel: string): string {
358
+ const base = rel.slice(rel.lastIndexOf('/') + 1);
359
+ const dot = base.lastIndexOf('.');
360
+ return dot <= 0 ? '' : base.slice(dot + 1).toLowerCase();
361
+ }
362
+
363
+ /** Tracked files, or `null` when git is unavailable (then the pass no-ops). */
364
+ function _trackedFiles(): string[] | null {
365
+ const res = spawnSync('git', ['ls-files', '-z'], {
366
+ cwd: sl.ROOT,
367
+ maxBuffer: 64 * 1024 * 1024,
368
+ });
369
+ if (res.status !== 0 || res.stdout === null) return null;
370
+ return res.stdout
371
+ .toString('utf-8')
372
+ .split('\0')
373
+ .filter((p) => p !== '');
374
+ }
375
+
376
+ /**
377
+ * Tracked files this pass is responsible for — text-intended, non-generated.
378
+ *
379
+ * Exported so a green run can state HOW MANY files it actually read. A check
380
+ * that reports "clean" without naming its scope is indistinguishable from a
381
+ * check whose scope matched nothing, which is the failure class this repo has
382
+ * already been bitten by.
383
+ */
384
+ export function _eligibleSourceFiles(): string[] | null {
385
+ const tracked = _trackedFiles();
386
+ if (tracked === null) return null;
387
+ return tracked.filter((rel) => !_isGenerated(rel) && !_BINARY_EXT.has(_extensionOf(rel)));
388
+ }
389
+
390
+ /**
391
+ * Flag raw C0 control bytes in every tracked, text-intended file.
392
+ *
393
+ * `files` is injectable so the regression test can assert a synthetic NUL is
394
+ * caught — without that assertion there is no way to know this pass can still
395
+ * fail, which is the failure mode the whole check exists to prevent.
396
+ */
397
+ export function _scanSourceControlBytes(files: readonly string[] | null = null): sl.Finding[] {
398
+ const tracked = files ?? _eligibleSourceFiles();
399
+ if (tracked === null) return [];
400
+ const out: sl.Finding[] = [];
401
+ for (const rel of tracked) {
402
+ // Re-applied here, not only in `_eligibleSourceFiles`: the exclusions
403
+ // are a property of the CHECK, so an explicit `files` list (a caller, a
404
+ // test) can never widen the scan past what the check is willing to
405
+ // claim. `_eligibleSourceFiles` exists to count, not to be the gate.
406
+ if (_isGenerated(rel)) continue;
407
+ if (_BINARY_EXT.has(_extensionOf(rel))) continue;
408
+ let data: Buffer;
409
+ try {
410
+ data = fs.readFileSync(path.join(sl.ROOT, rel));
411
+ } catch {
412
+ continue; // deleted, unreadable, or a submodule pointer
413
+ }
414
+ // A file that is not valid UTF-8 is binary regardless of its extension
415
+ // (an extensionless fixture, say) — not this check's business.
416
+ try {
417
+ new TextDecoder('utf-8', { fatal: true }).decode(data);
418
+ } catch {
419
+ continue;
420
+ }
421
+ // Iterate CODEPOINTS (the string is already known-valid UTF-8 here), so
422
+ // DEL and the C1 range are visible — see `_isRawControlCodepoint`.
423
+ let line = 1;
424
+ for (const ch of data.toString('utf-8')) {
425
+ const cp = ch.codePointAt(0);
426
+ if (cp === undefined) continue;
427
+ if (cp === 0x0a) {
428
+ line += 1;
429
+ continue;
430
+ }
431
+ if (!_isRawControlCodepoint(cp)) continue;
432
+ const hex = cp.toString(16).toUpperCase().padStart(2, '0');
433
+ out.push(
434
+ new sl.Finding(
435
+ rel,
436
+ line,
437
+ CHECK,
438
+ 'HIGH',
439
+ `raw control character U+${hex} in a text source — makes ` +
440
+ 'grep/file(1)/git treat this file as binary and skip it ' +
441
+ 'silently; use the language escape (e.g. \\0, \\x7F) instead',
442
+ 1.0,
443
+ ),
444
+ );
445
+ }
446
+ }
447
+ return out;
448
+ }
449
+
264
450
  export function _sanitize(filePath: string): string {
265
451
  const raw = fs.readFileSync(filePath, 'utf-8');
266
452
  let cleaned = '';
@@ -323,6 +509,28 @@ export function main(argv: readonly string[] | null = null): number {
323
509
  }
324
510
  }
325
511
 
512
+ // Second pass — raw control bytes in text-intended SOURCE files, which the
513
+ // `.md` corpus above does not cover. Deliberately not folded into
514
+ // `iter_corpus`: different scope (all tracked text files, not the `.md`
515
+ // corpus) and a narrower codepoint set (C0 only). `--fix` does not touch
516
+ // these — rewriting a source file's bytes is the author's call, and the
517
+ // finding names the escape to use.
518
+ const sourceFiles = _eligibleSourceFiles();
519
+ for (const h of _scanSourceControlBytes(sourceFiles)) {
520
+ findings.push(h);
521
+ }
522
+ if (!args.json) {
523
+ // State the scope on every run. A bare "clean" cannot be told apart
524
+ // from a pass whose file list was empty.
525
+ const n = sourceFiles === null ? 0 : sourceFiles.length;
526
+ process.stdout.write(
527
+ sourceFiles === null
528
+ ? ' source pass: SKIPPED — `git ls-files` unavailable, 0 files read for raw control bytes\n'
529
+ : ` source pass: ${n} tracked text file(s) read for raw C0 control bytes ` +
530
+ '(generated trees + verbatim captures excluded)\n',
531
+ );
532
+ }
533
+
326
534
  if (args.fix) {
327
535
  // sorted(flagged) — by path string.
328
536
  for (const p of [...flagged].sort()) {
@@ -36,9 +36,15 @@ const QUIET = process.argv.slice(2).includes('--quiet');
36
36
  // src/scripts/lint_load_context.ts → three dirs up is the repo root.
37
37
  const ROOT = path.resolve(path.dirname(_HERE), '..', '..');
38
38
 
39
+ // Retargeted 2026-07-29: the first two pointed at the ADR-051-emptied tree, so
40
+ // this gate reported "clean (0 declarer(s))" in CI — the count was in its own
41
+ // output the whole time. `agents/contexts` does not exist either (project-local
42
+ // contexts live under agents/settings/contexts) and is kept only as a no-op for
43
+ // consumer layouts that do have it.
39
44
  const SCAN_DIRS = [
40
- path.join(ROOT, '.agent-src.uncondensed', 'rules'),
41
- path.join(ROOT, '.agent-src.uncondensed', 'contexts'),
45
+ path.join(ROOT, 'src', 'rules'),
46
+ path.join(ROOT, 'src', 'agent-src', 'contexts'),
47
+ path.join(ROOT, 'agents', 'settings', 'contexts'),
42
48
  path.join(ROOT, 'agents', 'contexts'),
43
49
  ];
44
50
 
@@ -50,9 +56,10 @@ const ALLOWED_PREFIXES = [
50
56
 
51
57
  const LEGACY_PREFIX = '.agent-src.uncondensed/contexts/';
52
58
 
53
- const SOURCE_ROOT = path.join(ROOT, '.agent-src.uncondensed');
59
+ // Base for resolving a logical `contexts/...` entry to a real file.
60
+ const SOURCE_ROOT = path.join(ROOT, 'src', 'agent-src');
54
61
 
55
- const PUBLIC_RULE_PREFIX = '.agent-src.uncondensed/rules/';
62
+ const PUBLIC_RULE_PREFIX = 'src/rules/';
56
63
  const PROJECT_LOCAL_PREFIX = 'agents/settings/contexts/';
57
64
 
58
65
  const HARD_FLOOR_RULES: ReadonlySet<string> = new Set([
@@ -217,7 +224,12 @@ function main(): number {
217
224
  const warnings: string[] = [];
218
225
  const graph: Record<string, string[]> = {};
219
226
 
220
- for (const f of collect_files()) {
227
+ const _files = collect_files();
228
+ // Gate-coverage contract (src/config/gate-coverage.yml): count FILES INSPECTED,
229
+ // not declarers — "0 declarers" over 400 files is a legitimate result, "0 files"
230
+ // is blindness. Reporting declarers here would have hidden the dead root.
231
+ process.stdout.write(`scanned: ${String(_files.length)}\n`);
232
+ for (const f of _files) {
221
233
  const fm = parse_frontmatter(f);
222
234
  const lazyRaw = fm['load_context'];
223
235
  const eagerRaw = fm['load_context_eager'];