@event4u/agent-config 16.1.0 → 16.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (467) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +98 -257
  5. package/README.md +14 -12
  6. package/dist/agent-src/commands/analyze/inbox.md +1 -1
  7. package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
  8. package/dist/agent-src/commands/bug/fix.md +17 -2
  9. package/dist/agent-src/commands/feature/plan.md +1 -1
  10. package/dist/agent-src/commands/feature/roadmap.md +1 -1
  11. package/dist/agent-src/commands/fix/ci.md +1 -1
  12. package/dist/agent-src/commands/implement-ticket.md +1 -1
  13. package/dist/agent-src/commands/jira-ticket.md +1 -1
  14. package/dist/agent-src/commands/roadmap/create.md +1 -1
  15. package/dist/agent-src/commands/roadmap/materialize.md +1 -1
  16. package/dist/agent-src/commands/roadmap/process-full.md +5 -5
  17. package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
  18. package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
  19. package/dist/agent-src/commands/roadmap.md +18 -4
  20. package/dist/agent-src/commands/tests/create.md +17 -3
  21. package/dist/agent-src/commands/tests/execute.md +22 -5
  22. package/dist/agent-src/commands/work.md +4 -0
  23. package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
  24. package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
  25. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
  26. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +4 -8
  27. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
  28. package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
  29. package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
  30. package/dist/agent-src/rules/active-remediation.md +1 -1
  31. package/dist/agent-src/rules/autonomous-execution.md +1 -0
  32. package/dist/agent-src/rules/broken-access-control.md +1 -0
  33. package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
  34. package/dist/agent-src/rules/context-hygiene.md +1 -1
  35. package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
  36. package/dist/agent-src/rules/design-fidelity.md +13 -16
  37. package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
  38. package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
  39. package/dist/agent-src/rules/domain-safety-pii.md +1 -0
  40. package/dist/agent-src/rules/domain-safety-retention.md +1 -0
  41. package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
  42. package/dist/agent-src/rules/evaluator-independence.md +3 -2
  43. package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
  44. package/dist/agent-src/rules/finance-safety-floor.md +1 -0
  45. package/dist/agent-src/rules/git-history-discipline.md +1 -0
  46. package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
  47. package/dist/agent-src/rules/legal-safety-floor.md +3 -2
  48. package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
  49. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
  50. package/dist/agent-src/rules/media-governance-routing.md +14 -17
  51. package/dist/agent-src/rules/persona-governance.md +2 -2
  52. package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
  53. package/dist/agent-src/rules/question-not-instruction.md +1 -0
  54. package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
  55. package/dist/agent-src/rules/runtime-safety.md +1 -0
  56. package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
  57. package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
  58. package/dist/agent-src/rules/session-canary.md +8 -62
  59. package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
  60. package/dist/agent-src/rules/source-confidentiality.md +1 -0
  61. package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
  62. package/dist/agent-src/rules/tool-safety.md +1 -0
  63. package/dist/agent-src/rules/ui-audit-gate.md +1 -2
  64. package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
  65. package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
  66. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  67. package/dist/agent-src/scripts/deferral_carry.ts +339 -0
  68. package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
  69. package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +1 -1
  70. package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +2 -2
  71. package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
  72. package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
  73. package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
  74. package/dist/agent-src/skills/design-review/SKILL.md +30 -4
  75. package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
  76. package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
  77. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +18 -3
  78. package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
  79. package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
  80. package/dist/agent-src/skills/iconography/SKILL.md +1 -1
  81. package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
  82. package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
  83. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
  84. package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
  85. package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
  86. package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
  87. package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
  88. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  89. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
  90. package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
  91. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
  92. package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
  93. package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
  94. package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
  95. package/dist/agent-src/skills/ui-component-architect/SKILL.md +25 -2
  96. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  97. package/dist/agent-src/templates/roadmaps.md +30 -0
  98. package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
  99. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
  100. package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
  101. package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
  102. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  103. package/dist/agent-src/templates/scripts/work_engine/state.ts +57 -7
  104. package/dist/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
  105. package/dist/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
  106. package/dist/cli/python/knowledge_ingest.js +1 -1
  107. package/dist/cli/python/workspace_drive.js +1 -1
  108. package/dist/cli/registry.js +1 -1
  109. package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
  110. package/dist/cli-delegate/check_update_banner.js +12 -1
  111. package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
  112. package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
  113. package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
  114. package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
  115. package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
  116. package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
  117. package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
  118. package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
  119. package/dist/cli-delegate/{chunk-UNCRJBT3.js → chunk-JQVYKIZA.js} +41 -0
  120. package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
  121. package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
  122. package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-KR6EM23A.js} +235 -1455
  123. package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
  124. package/dist/cli-delegate/chunk-NQ7WT43P.js +2729 -0
  125. package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
  126. package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
  127. package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
  128. package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
  129. package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
  130. package/dist/cli-delegate/{chunk-HDVVGPQW.js → chunk-RQNNW7IF.js} +1405 -567
  131. package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-S4UMZNES.js} +1 -1
  132. package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
  133. package/dist/cli-delegate/{chunk-GJCBB2UG.js → chunk-TRI6DQZ6.js} +3054 -325
  134. package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
  135. package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
  136. package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
  137. package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
  138. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  139. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  140. package/dist/cli-delegate/cmd_conformance.js +1862 -809
  141. package/dist/cli-delegate/cmd_doctor.js +13 -6
  142. package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
  143. package/dist/cli-delegate/cmd_explain.js +5 -5
  144. package/dist/cli-delegate/cmd_export.js +11 -8
  145. package/dist/cli-delegate/cmd_fleet.js +3 -3
  146. package/dist/cli-delegate/cmd_handoff.js +10 -7
  147. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  148. package/dist/cli-delegate/cmd_memory_get.js +3 -1
  149. package/dist/cli-delegate/cmd_migrate.js +2 -2
  150. package/dist/cli-delegate/cmd_packs_active.js +3 -3
  151. package/dist/cli-delegate/cmd_preflight.js +6 -6
  152. package/dist/cli-delegate/cmd_prune.js +11 -8
  153. package/dist/cli-delegate/cmd_refresh.js +2 -1
  154. package/dist/cli-delegate/cmd_route_audit.js +8 -6
  155. package/dist/cli-delegate/cmd_route_explain.js +4 -4
  156. package/dist/cli-delegate/cmd_session_recycle.js +4 -3
  157. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  158. package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
  159. package/dist/cli-delegate/cmd_settings_set.js +4 -4
  160. package/dist/cli-delegate/cmd_sync.js +11 -8
  161. package/dist/cli-delegate/cmd_uninstall.js +11 -8
  162. package/dist/cli-delegate/cmd_update.js +1 -1
  163. package/dist/cli-delegate/cmd_upgrade.js +3 -2
  164. package/dist/cli-delegate/cmd_validate.js +11 -8
  165. package/dist/cli-delegate/cmd_versions.js +1 -1
  166. package/dist/cli-delegate/deferral_carry.js +16 -0
  167. package/dist/cli-delegate/gate_execute.js +2 -2
  168. package/dist/cli-delegate/roadmap_gates.js +5 -5
  169. package/dist/cli-delegate/update_roadmap_progress.js +1 -1
  170. package/dist/discovery/deprecation-report.md +1 -1
  171. package/dist/discovery/discovery-manifest.json +132 -80
  172. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  173. package/dist/discovery/discovery-manifest.summary.md +3 -3
  174. package/dist/discovery/dormancy-report.md +1 -1
  175. package/dist/discovery/orphan-report.md +1 -1
  176. package/dist/discovery/packs.json +7 -5
  177. package/dist/discovery/trust-report.md +2 -2
  178. package/dist/discovery/workspaces.json +6 -4
  179. package/dist/hooks/dispatch.js +7972 -5186
  180. package/dist/hooks/dispatch.sha256 +1 -0
  181. package/dist/install/claudePathsPlan.js +47 -6
  182. package/dist/install/claudeRuleRewrite.js +7 -0
  183. package/dist/install/emit_host_rules_cli.js +39 -36
  184. package/dist/install/globalRuleScope.js +87 -0
  185. package/dist/install/host_rule_ownership.js +160 -0
  186. package/dist/install/install.mjs +2226 -1055
  187. package/dist/install/installThinLayer.js +261 -0
  188. package/dist/install/installedRuleLinks.js +176 -0
  189. package/dist/install/wizard-plan.js +24 -0
  190. package/dist/mcp/registry-manifest.json +3 -3
  191. package/dist/mcp/server.json +2 -2
  192. package/dist/mcp/server.mjs +40913 -34865
  193. package/dist/scripts/_lib/agent_settings.js +11 -0
  194. package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
  195. package/dist/scripts/_lib/installed_layer.js +378 -0
  196. package/dist/scripts/_lib/lean_projection_mode.js +218 -15
  197. package/dist/scripts/_lib/rule_consequence_class.js +45 -0
  198. package/dist/scripts/_lib/rule_injection.js +67 -10
  199. package/dist/scripts/_lib/rule_law_section.js +122 -0
  200. package/dist/scripts/_lib/thin_rules.js +458 -0
  201. package/dist/scripts/_lib/windsurf_render.js +60 -0
  202. package/dist/scripts/condense.js +14 -26
  203. package/dist/scripts/project_thin_rules.js +14 -294
  204. package/dist/server/schemas/settings.js +29 -0
  205. package/dist/shared/skillRanking.js +74 -13
  206. package/dist/ui/assets/index-Cwq4d0hX.js +23 -0
  207. package/dist/ui/assets/index-Cyjy8bWO.css +1 -0
  208. package/dist/ui/index.html +2 -2
  209. package/docs/contracts/settings-classes.md +10 -6
  210. package/package.json +4 -4
  211. package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  212. package/src/agent-src/scripts/deferral_carry.ts +339 -0
  213. package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
  214. package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
  215. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
  216. package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
  217. package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
  218. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  219. package/src/agent-src/templates/scripts/work_engine/state.ts +57 -7
  220. package/src/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
  221. package/src/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
  222. package/src/config/agent-settings.template.yml +91 -22
  223. package/src/config/ci-local-parity.yml +18 -0
  224. package/src/config/continuity-surface.json +9 -2
  225. package/src/config/evaluator-budgets.json +4 -4
  226. package/src/config/gate-coverage.yml +327 -3
  227. package/src/config/gate-violation-baselines.json +21 -9
  228. package/src/config/hook-bundle-budget.json +25 -0
  229. package/src/config/hook-latency-budget.json +21 -0
  230. package/src/config/hook-token-budget.json +8 -3
  231. package/src/config/host-instruction-limits.json +33 -0
  232. package/src/config/metric-registry.yml +114 -0
  233. package/src/config/placeholder-drift-budget.json +10 -0
  234. package/src/config/routing-coverage-seed.json +38 -3
  235. package/src/config/rule-activation-census.json +7 -3
  236. package/src/config/rule-consequence-class.json +161 -0
  237. package/src/config/rule-law-ceilings.json +99 -0
  238. package/src/install/claudePathsPlan.ts +46 -4
  239. package/src/install/claudeRuleRewrite.ts +10 -1
  240. package/src/install/emit_host_rules_cli.ts +43 -34
  241. package/src/install/globalRuleScope.ts +109 -0
  242. package/src/install/host_rule_ownership.ts +170 -0
  243. package/src/install/installThinLayer.ts +312 -0
  244. package/src/install/installedRuleLinks.ts +220 -0
  245. package/src/install/wizard-plan.ts +24 -0
  246. package/src/scripts/_cli/cmd_doctor.ts +28 -90
  247. package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
  248. package/src/scripts/_cli/doctor_execution.ts +100 -17
  249. package/src/scripts/_cli/doctor_network_posture.ts +226 -0
  250. package/src/scripts/_dispatch.bash +16 -2
  251. package/src/scripts/_lib/agent_settings.ts +11 -0
  252. package/src/scripts/_lib/body_portable.ts +102 -0
  253. package/src/scripts/_lib/cc_transcript.ts +132 -1
  254. package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
  255. package/src/scripts/_lib/concern_sla_window.ts +200 -0
  256. package/src/scripts/_lib/estate_offsets.ts +241 -0
  257. package/src/scripts/_lib/exemption_shape.ts +143 -0
  258. package/src/scripts/_lib/fnv.ts +23 -0
  259. package/src/scripts/_lib/foreign_scan.ts +106 -0
  260. package/src/scripts/_lib/forge_protection.ts +114 -0
  261. package/src/scripts/_lib/forge_reader.ts +558 -0
  262. package/src/scripts/_lib/gitignore_block.ts +314 -0
  263. package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
  264. package/src/scripts/_lib/graph_feeder_record.ts +214 -0
  265. package/src/scripts/_lib/hook_settings.ts +73 -0
  266. package/src/scripts/_lib/host_capability.ts +40 -19
  267. package/src/scripts/_lib/host_env_write.ts +111 -0
  268. package/src/scripts/_lib/host_hook_merge.ts +165 -0
  269. package/src/scripts/_lib/installed_layer.ts +538 -0
  270. package/src/scripts/_lib/json_merge.ts +82 -0
  271. package/src/scripts/_lib/json_pointers.ts +93 -11
  272. package/src/scripts/_lib/lean_projection_mode.ts +275 -15
  273. package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
  274. package/src/scripts/_lib/machine_wake.ts +16 -3
  275. package/src/scripts/_lib/neighbour_census.ts +760 -0
  276. package/src/scripts/_lib/neighbour_scan.ts +122 -0
  277. package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
  278. package/src/scripts/_lib/obligations.ts +119 -8
  279. package/src/scripts/_lib/probe_inputs.ts +271 -0
  280. package/src/scripts/_lib/prompt_shape.ts +46 -0
  281. package/src/scripts/_lib/read_surface_scan.ts +322 -0
  282. package/src/scripts/_lib/release_highlights.ts +2 -1
  283. package/src/scripts/_lib/release_migration_gate.ts +19 -3
  284. package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
  285. package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
  286. package/src/scripts/_lib/review_coverage.ts +134 -0
  287. package/src/scripts/_lib/rule_consequence_class.ts +71 -0
  288. package/src/scripts/_lib/rule_injection.ts +130 -10
  289. package/src/scripts/_lib/rule_law_section.ts +147 -0
  290. package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
  291. package/src/scripts/_lib/shell_write_shapes.ts +108 -0
  292. package/src/scripts/_lib/skill_origin.ts +254 -0
  293. package/src/scripts/_lib/structural_hiding.ts +622 -0
  294. package/src/scripts/_lib/structured_ask.ts +64 -21
  295. package/src/scripts/_lib/thin_rules.ts +540 -0
  296. package/src/scripts/_lib/touched_file_quality.ts +434 -0
  297. package/src/scripts/_lib/turn_end_refusals.ts +600 -4
  298. package/src/scripts/_lib/turn_end_transcript.ts +216 -0
  299. package/src/scripts/_lib/verification_command.ts +324 -0
  300. package/src/scripts/_lib/verification_evidence.ts +647 -0
  301. package/src/scripts/_lib/verify_clause.ts +280 -0
  302. package/src/scripts/_lib/windsurf_render.ts +63 -0
  303. package/src/scripts/ai_council/cli_call_budget.ts +13 -5
  304. package/src/scripts/ai_council/clients.ts +26 -57
  305. package/src/scripts/ai_council/config.ts +1 -1
  306. package/src/scripts/ai_council/vendor_defaults.ts +45 -0
  307. package/src/scripts/ai_team/team_dispatch.ts +4 -0
  308. package/src/scripts/audit_skill_overlap.ts +261 -0
  309. package/src/scripts/before_complete_hook.ts +573 -25
  310. package/src/scripts/bench_hook_latency.ts +412 -5
  311. package/src/scripts/bench_touched_file_quality.ts +238 -0
  312. package/src/scripts/cache_realization_report.ts +61 -1
  313. package/src/scripts/check_argument_hint.ts +287 -0
  314. package/src/scripts/check_claims.ts +125 -1
  315. package/src/scripts/check_enforcement_coverage.ts +38 -9
  316. package/src/scripts/check_enforcement_matrix.ts +621 -22
  317. package/src/scripts/check_estate_count.ts +130 -153
  318. package/src/scripts/check_finding_dispositions.ts +138 -7
  319. package/src/scripts/check_generator_sync.ts +71 -0
  320. package/src/scripts/check_hook_bundle_composition.ts +370 -0
  321. package/src/scripts/check_host_docs_digest.ts +786 -0
  322. package/src/scripts/check_host_format_column.ts +559 -0
  323. package/src/scripts/check_input_references.ts +228 -0
  324. package/src/scripts/check_inputs_parity.ts +235 -0
  325. package/src/scripts/check_kernel_edit_ratified.ts +89 -9
  326. package/src/scripts/check_kill_switch_table.ts +294 -0
  327. package/src/scripts/check_memory.ts +7 -1
  328. package/src/scripts/check_placeholder_drift.ts +221 -0
  329. package/src/scripts/check_read_surface_coverage.ts +515 -0
  330. package/src/scripts/check_release_highlights.ts +10 -0
  331. package/src/scripts/check_release_holds.ts +2 -1
  332. package/src/scripts/check_release_pr_shape.ts +38 -15
  333. package/src/scripts/check_routing_coverage.ts +378 -11
  334. package/src/scripts/check_standing_rule_delivery.ts +33 -13
  335. package/src/scripts/check_static_parity.ts +17 -0
  336. package/src/scripts/check_verify_expectation_delta.ts +521 -0
  337. package/src/scripts/ci_settle.ts +145 -19
  338. package/src/scripts/closure_scan.ts +115 -1
  339. package/src/scripts/code_graph/detect.ts +127 -7
  340. package/src/scripts/code_graph/foreign.ts +194 -0
  341. package/src/scripts/code_graph/query.ts +217 -4
  342. package/src/scripts/code_graph/types.ts +26 -2
  343. package/src/scripts/code_graph/validate.ts +3 -1
  344. package/src/scripts/code_graph/verbs.ts +103 -0
  345. package/src/scripts/compile_hook_manifest.ts +90 -14
  346. package/src/scripts/condense.ts +14 -27
  347. package/src/scripts/estate_exemption_shape.ts +202 -0
  348. package/src/scripts/external_sources_denylist.json +29 -4
  349. package/src/scripts/generate_host_cost_table.ts +1 -1
  350. package/src/scripts/hook_manifest.json +1 -1
  351. package/src/scripts/hook_manifest.yaml +192 -14
  352. package/src/scripts/hooks/block_config_weakening.ts +294 -4
  353. package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
  354. package/src/scripts/hooks/block_plumbing_writes.ts +342 -0
  355. package/src/scripts/hooks/bundle_integrity.ts +291 -0
  356. package/src/scripts/hooks/chain_nudge_hook.ts +1 -2
  357. package/src/scripts/hooks/code_graph_context_hook.ts +253 -25
  358. package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
  359. package/src/scripts/hooks/concern_failure_policy.ts +280 -0
  360. package/src/scripts/hooks/concern_registry.ts +2 -0
  361. package/src/scripts/hooks/concern_timings.ts +94 -0
  362. package/src/scripts/hooks/delegation_nudge_hook.ts +1 -2
  363. package/src/scripts/hooks/design_pass_hook.ts +100 -9
  364. package/src/scripts/hooks/design_slop_hook.ts +1 -2
  365. package/src/scripts/hooks/dispatch_hook.ts +77 -71
  366. package/src/scripts/hooks/edit_shape_hook.ts +1 -2
  367. package/src/scripts/hooks/end_review_nudge_hook.ts +1 -1
  368. package/src/scripts/hooks/evidence_independence.ts +1 -2
  369. package/src/scripts/hooks/exit_codes.ts +129 -0
  370. package/src/scripts/hooks/host_lowering.json +1 -0
  371. package/src/scripts/hooks/host_lowering.ts +146 -3
  372. package/src/scripts/hooks/host_lowering.yaml +262 -46
  373. package/src/scripts/hooks/host_semantics.ts +30 -2
  374. package/src/scripts/hooks/injection_budget.ts +9 -2
  375. package/src/scripts/hooks/interruption_ledger_hook.ts +1 -2
  376. package/src/scripts/hooks/journal_record_hook.ts +1 -2
  377. package/src/scripts/hooks/memory_recall_hook.ts +1 -2
  378. package/src/scripts/hooks/obligation_settle_hook.ts +151 -5
  379. package/src/scripts/hooks/one_question_per_ask_hook.ts +43 -6
  380. package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
  381. package/src/scripts/hooks/payload_stub.ts +10 -1
  382. package/src/scripts/hooks/permission_gate.ts +1 -2
  383. package/src/scripts/hooks/push_settle_hook.ts +1 -3
  384. package/src/scripts/hooks/replay_hook.ts +2 -1
  385. package/src/scripts/hooks/reread_guard_hook.ts +1 -2
  386. package/src/scripts/hooks/review_baseline_hook.ts +1 -2
  387. package/src/scripts/hooks/rtk_wrap_hook.ts +1 -2
  388. package/src/scripts/hooks/rule_inject_hook.ts +765 -68
  389. package/src/scripts/hooks/run_continuation_hook.ts +13 -15
  390. package/src/scripts/hooks/skill_route_hook.ts +1 -2
  391. package/src/scripts/hooks/source_first_gate_hook.ts +1 -2
  392. package/src/scripts/hooks/spawn_guard_shadow_hook.ts +1 -2
  393. package/src/scripts/hooks/subagent_ledger_hook.ts +1 -2
  394. package/src/scripts/hooks/suggestion_capture_hook.ts +1 -1
  395. package/src/scripts/hooks/table_fingerprint.ts +70 -0
  396. package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
  397. package/src/scripts/hooks/telemetry_usage_hook.ts +65 -10
  398. package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
  399. package/src/scripts/hooks/turn_end_gate_hook.ts +421 -324
  400. package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
  401. package/src/scripts/hooks_status.ts +112 -0
  402. package/src/scripts/injection_scan_hook.ts +7 -0
  403. package/src/scripts/install.ts +75 -189
  404. package/src/scripts/installed_layer_report.ts +103 -0
  405. package/src/scripts/language_mirror_hook.ts +15 -6
  406. package/src/scripts/learning_sidecar.ts +119 -8
  407. package/src/scripts/lint_deny_text.ts +419 -0
  408. package/src/scripts/lint_exit_codes.ts +262 -0
  409. package/src/scripts/lint_hook_manifest.ts +108 -0
  410. package/src/scripts/lint_major_migration_sections.ts +156 -26
  411. package/src/scripts/lint_pack_boundaries.ts +63 -5
  412. package/src/scripts/lint_roadmap_blockers.ts +78 -12
  413. package/src/scripts/lint_rule_law_section.ts +517 -0
  414. package/src/scripts/lint_skill_descriptions.ts +1 -1
  415. package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
  416. package/src/scripts/lint_workflow_security.ts +161 -5
  417. package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
  418. package/src/scripts/mcp_server/graph_tools.ts +72 -3
  419. package/src/scripts/mcp_server/prompts.ts +142 -1
  420. package/src/scripts/measure_routing_signal.ts +54 -16
  421. package/src/scripts/measure_skill_ranker_baseline.ts +515 -53
  422. package/src/scripts/measure_turn_end_gate.ts +193 -0
  423. package/src/scripts/memory_learn_hook.ts +91 -6
  424. package/src/scripts/memory_lookup.ts +1 -1
  425. package/src/scripts/model_rule_injection.ts +52 -5
  426. package/src/scripts/prepack-check.mjs +53 -0
  427. package/src/scripts/project_thin_rules.ts +34 -327
  428. package/src/scripts/release_publication.ts +13 -1
  429. package/src/scripts/report_evidence_temperature.ts +657 -0
  430. package/src/scripts/report_installed_rule_links.ts +157 -0
  431. package/src/scripts/report_invocation_surface.ts +383 -0
  432. package/src/scripts/report_label_agreement.ts +233 -0
  433. package/src/scripts/report_obligation_carriers.ts +699 -0
  434. package/src/scripts/report_obligation_mechanism.ts +230 -0
  435. package/src/scripts/report_obligation_writer_split.ts +236 -0
  436. package/src/scripts/report_single_token_triggers.ts +277 -0
  437. package/src/scripts/report_skill_menu_census.ts +208 -0
  438. package/src/scripts/report_skill_ranker_confusion.ts +442 -0
  439. package/src/scripts/report_standing_payload_by_host.ts +188 -15
  440. package/src/scripts/report_verification_record_coverage.ts +306 -0
  441. package/src/scripts/roadmap_verify_share.ts +213 -0
  442. package/src/scripts/rule_activation_census.ts +5 -2
  443. package/src/scripts/rule_trigger_eval.ts +9 -9
  444. package/src/scripts/schemas/command.schema.json +44 -0
  445. package/src/scripts/schemas/review-findings.schema.json +7 -2
  446. package/src/scripts/schemas/rule.schema.json +5 -0
  447. package/src/scripts/schemas/skill.schema.json +44 -0
  448. package/src/scripts/self_review_gate.ts +421 -17
  449. package/src/scripts/semantic_parity_census.ts +314 -0
  450. package/src/scripts/session_eol_report.ts +54 -1
  451. package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
  452. package/src/scripts/sweep_dead_scan_roots.ts +1 -1
  453. package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
  454. package/src/scripts/sync_gitignore.ts +29 -235
  455. package/src/scripts/trigger_eval_grandfather.json +0 -7
  456. package/src/scripts/trigger_eval_rotation.ts +122 -27
  457. package/src/scripts/ui_conformance_probe.ts +156 -4
  458. package/src/scripts/update_prices.ts +85 -3
  459. package/src/scripts/write_bundle_digest.mjs +74 -0
  460. package/src/server/schemas/settings.ts +41 -0
  461. package/src/shared/skillRanking.ts +117 -11
  462. package/src/templates/consumer-settings/ONBOARDING.md +1 -0
  463. package/dist/cli-delegate/chunk-FXYUYU4N.js +0 -4416
  464. package/dist/cli-delegate/chunk-QJWAUMJW.js +0 -1072
  465. package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
  466. package/dist/ui/assets/index-DH1xc62v.js +0 -29
  467. package/dist/ui/assets/index-jSfMW8_t.css +0 -1
@@ -31,243 +31,37 @@ import * as path from 'node:path';
31
31
  import process from 'node:process';
32
32
  import { fileURLToPath, pathToFileURL } from 'node:url';
33
33
 
34
- export const SECTION_HEADER = '# event4u/agent-config';
35
- export const SECTION_FOOTER = '# event4u/agent-config — END';
36
- export const DEFAULT_GITIGNORE = '.gitignore';
34
+ export {
35
+ SECTION_HEADER,
36
+ SECTION_FOOTER,
37
+ DEFAULT_GITIGNORE,
38
+ DEFAULT_TEMPLATE,
39
+ LEGACY_PATTERNS,
40
+ TemplateNotFoundError,
41
+ load_template,
42
+ find_block,
43
+ block_entries,
44
+ template_entries,
45
+ build_fresh_block,
46
+ sync_block,
47
+ cleanup_legacy,
48
+ format_file,
49
+ } from './_lib/gitignore_block.js';
50
+ import {
51
+ DEFAULT_GITIGNORE,
52
+ DEFAULT_TEMPLATE,
53
+ TemplateNotFoundError,
54
+ load_template,
55
+ cleanup_legacy,
56
+ format_file,
57
+ sync_block,
58
+ template_entries,
59
+ _isFile,
60
+ _splitlines,
61
+ _strip,
62
+ } from './_lib/gitignore_block.js';
37
63
 
38
64
  const _HERE = fileURLToPath(import.meta.url);
39
- // _HERE === <repo>/src/scripts/sync_gitignore.ts ; parents[2] of the .py file
40
- // is the repo root — two dirs up from src/scripts. the retired Python implementation derives
41
- // DEFAULT_TEMPLATE = <file>.parent.parent.parent / "src" / "config" /
42
- // "gitignore-block.txt".
43
- export const DEFAULT_TEMPLATE = path.join(
44
- path.dirname(_HERE),
45
- '..',
46
- '..',
47
- 'src',
48
- 'config',
49
- 'gitignore-block.txt',
50
- );
51
-
52
- // Legacy patterns that lived in older versions of src/config/gitignore-block.txt
53
- // before runtime artefacts moved under /agents/runtime/ (May 2026). They get
54
- // stripped wherever they appear in the consumer's .gitignore — inside the
55
- // managed block or outside (older installers / hand-edits). Current canonical
56
- // equivalents (e.g. /agents/runtime/.agent-prices.md) come from the template
57
- // and are NOT affected. Leading-slash variants are matched defensively.
58
- //
59
- // Authoritative source: src/config/agents-paths.yml entries with `legacy: true`.
60
- // Manual sync until the generation step from the manifest is implemented
61
- // (road-to-agents-dir-and-gitignore-hygiene Phase 3.2 follow-on).
62
- export const LEGACY_PATTERNS: readonly string[] = [
63
- '.agent-chat-history',
64
- '.agent-chat-history.bak',
65
- '.agent-chat-history.*.bak',
66
- '.agent-prices.md',
67
- '.council-tmp/',
68
- // 2.x intermediate: prices cache lived directly under agents/ before
69
- // consolidating under agents/runtime/.
70
- 'agents/.agent-prices.md',
71
- // Budget history JSONLs — previously listed explicitly at project
72
- // root or under agents/; now covered by the /agents/runtime/
73
- // catch-all in the managed block.
74
- '.augment-budget-history.jsonl',
75
- '.rule-budget-history.jsonl',
76
- 'agents/.augment-budget-history.jsonl',
77
- 'agents/.rule-budget-history.jsonl',
78
- ];
79
-
80
- function _strip(ln: string): string {
81
- // Python: ln.rstrip("\n").rstrip() — strip a trailing newline, then strip
82
- // all trailing whitespace.
83
- return ln.replace(/\n+$/, '').replace(/\s+$/, '');
84
- }
85
-
86
- function _is_entry(ln: string): boolean {
87
- // Non-empty, non-comment line = a path/pattern entry.
88
- const s = _strip(ln).replace(/^\s+/, '');
89
- return Boolean(s) && !s.startsWith('#');
90
- }
91
-
92
- /** Error raised when the template file is missing (→ exit 2 in main). */
93
- export class TemplateNotFoundError extends Error {
94
- constructor(p: string) {
95
- super(`template not found: ${p}`);
96
- this.name = 'TemplateNotFoundError';
97
- }
98
- }
99
-
100
- function _isFile(p: string): boolean {
101
- try {
102
- return fs.statSync(p).isFile();
103
- } catch {
104
- return false;
105
- }
106
- }
107
-
108
- /** Python str.splitlines() — split on universal newlines, no trailing empty. */
109
- function _splitlines(text: string): string[] {
110
- if (text === '') return [];
111
- // str.splitlines() splits on \n, \r, \r\n (and more) and does NOT keep a
112
- // trailing empty element. The targets here only ever contain \n / \r\n.
113
- const parts = text.split(/\r\n|\r|\n/);
114
- if (parts.length > 0 && parts[parts.length - 1] === '') parts.pop();
115
- return parts;
116
- }
117
-
118
- export function load_template(p: string): string[] {
119
- if (!_isFile(p)) {
120
- throw new TemplateNotFoundError(p);
121
- }
122
- const text = fs.readFileSync(p, 'utf-8');
123
- // Keep trailing newlines stripped; we splice explicit newlines.
124
- return _splitlines(text).map(_strip);
125
- }
126
-
127
- /**
128
- * Locate the managed block; return [start_idx, end_idx_exclusive] or null.
129
- *
130
- * `start_idx` points at the SECTION_HEADER line.
131
- * `end_idx_exclusive` points one past the last line of the block.
132
- * Honors explicit SECTION_FOOTER when present; otherwise treats the
133
- * block as extending to EOF or to the next non-managed section.
134
- */
135
- export function find_block(lines: readonly string[]): [number, number] | null {
136
- for (let i = 0; i < lines.length; i += 1) {
137
- if (_strip(lines[i] as string) === SECTION_HEADER) {
138
- const start = i;
139
- // Explicit footer?
140
- for (let j = i + 1; j < lines.length; j += 1) {
141
- if (_strip(lines[j] as string) === SECTION_FOOTER) {
142
- return [start, j + 1];
143
- }
144
- }
145
- // Legacy: extend to EOF or next non-managed section break.
146
- let end = lines.length;
147
- for (let j = i + 1; j < lines.length; j += 1) {
148
- const s = _strip(lines[j] as string).replace(/^\s+/, '');
149
- if (
150
- s.startsWith('#') &&
151
- !s.startsWith('# Agent config') &&
152
- s !== SECTION_HEADER
153
- ) {
154
- end = j;
155
- while (end > i + 1 && _strip(lines[end - 1] as string) === '') {
156
- end -= 1;
157
- }
158
- break;
159
- }
160
- }
161
- return [start, end];
162
- }
163
- }
164
- return null;
165
- }
166
-
167
- /** Return entries (paths/patterns) present in the given block. */
168
- export function block_entries(block_lines: readonly string[]): string[] {
169
- return block_lines
170
- .filter((ln) => _is_entry(ln))
171
- .map((ln) => _strip(ln).replace(/^\s+/, ''));
172
- }
173
-
174
- export function template_entries(template_lines: readonly string[]): string[] {
175
- return template_lines.filter((ln) => _is_entry(ln)).map((ln) => ln.replace(/^\s+/, ''));
176
- }
177
-
178
- /** Return a fresh, fully-managed block with START + body + END. */
179
- export function build_fresh_block(template_lines: readonly string[]): string[] {
180
- return [SECTION_HEADER, ...template_lines, SECTION_FOOTER];
181
- }
182
-
183
- /**
184
- * Return [new_lines, added_entries].
185
- *
186
- * - If block missing: append fresh block (preceded by a blank line if the
187
- * file's last line is not already empty).
188
- * - If block present and replace=true: rewrite block in full.
189
- * - If block present and replace=false: append any missing managed entries
190
- * before the END marker (adding END if absent). User-added lines inside the
191
- * block are preserved.
192
- */
193
- export function sync_block(
194
- existing_lines: readonly string[],
195
- template_lines: readonly string[],
196
- options: { replace?: boolean } = {},
197
- ): [string[], string[]] {
198
- const replace = options.replace ?? false;
199
- const loc = find_block(existing_lines);
200
- const fresh = build_fresh_block(template_lines);
201
-
202
- // Missing block → append with leading blank if needed.
203
- if (loc === null) {
204
- const newLines = [...existing_lines];
205
- if (newLines.length > 0 && _strip(newLines[newLines.length - 1] as string) !== '') {
206
- newLines.push('');
207
- }
208
- newLines.push(...fresh);
209
- return [newLines, template_entries(template_lines)];
210
- }
211
-
212
- const [start, end] = loc;
213
- const head = existing_lines.slice(0, start);
214
- let block = existing_lines.slice(start, end);
215
- const tail = existing_lines.slice(end);
216
-
217
- if (replace) {
218
- const existing = new Set(block_entries(block));
219
- const added = template_entries(template_lines).filter((e) => !existing.has(e));
220
- return [[...head, ...fresh, ...tail], added];
221
- }
222
-
223
- // Append-only mode.
224
- const existing_entries = new Set(block_entries(block));
225
- const missing = template_entries(template_lines).filter((e) => !existing_entries.has(e));
226
- if (missing.length === 0) {
227
- return [[...existing_lines], []];
228
- }
229
-
230
- // Ensure block ends with SECTION_FOOTER; insert missing entries right
231
- // before it.
232
- let insert_at: number;
233
- if (block.length > 0 && _strip(block[block.length - 1] as string) === SECTION_FOOTER) {
234
- insert_at = block.length - 1;
235
- } else {
236
- block = [...block, SECTION_FOOTER];
237
- insert_at = block.length - 1;
238
- }
239
- const new_block = [...block.slice(0, insert_at), ...missing, ...block.slice(insert_at)];
240
- return [[...head, ...new_block, ...tail], missing];
241
- }
242
-
243
- /**
244
- * Strip legacy entries from anywhere in the file.
245
- *
246
- * A line is legacy when its stripped, leading-whitespace-trimmed content
247
- * matches a `LEGACY_PATTERNS` entry — with or without a leading slash.
248
- * Comments and blank lines are untouched; current managed entries (e.g.
249
- * `/agents/.agent-chat-history`) are not in the legacy set and survive.
250
- */
251
- export function cleanup_legacy(lines: readonly string[]): [string[], string[]] {
252
- const legacy = new Set(LEGACY_PATTERNS);
253
- const kept: string[] = [];
254
- const removed: string[] = [];
255
- for (const ln of lines) {
256
- const s = _strip(ln).replace(/^\s+/, '');
257
- if (legacy.has(s) || (s.startsWith('/') && legacy.has(s.slice(1)))) {
258
- removed.push(s);
259
- continue;
260
- }
261
- kept.push(ln);
262
- }
263
- return [kept, removed];
264
- }
265
-
266
- /** Join lines with newlines and enforce exactly one trailing newline. */
267
- export function format_file(lines: readonly string[]): string {
268
- const text = lines.join('\n');
269
- return text.replace(/\n+$/, '') + '\n';
270
- }
271
65
 
272
66
  /** Python difflib.unified_diff(..., n=3) over keepends-split lines. */
273
67
  export function render_diff(old_text: string, new_text: string, p: string): string {
@@ -5,12 +5,10 @@
5
5
  "sequential-thinking"
6
6
  ],
7
7
  "skills": [
8
- "accessibility-auditor",
9
8
  "activation-design",
10
9
  "agent-docs-writing",
11
10
  "agents-md-thin-root",
12
11
  "ai-council",
13
- "api-design",
14
12
  "api-endpoint",
15
13
  "api-testing",
16
14
  "artisan-commands",
@@ -45,7 +43,6 @@
45
43
  "dependency-upgrade",
46
44
  "description-assist",
47
45
  "design-review",
48
- "design-system-capture",
49
46
  "devcontainer",
50
47
  "developer-like-execution",
51
48
  "discovery-interview",
@@ -154,7 +151,6 @@
154
151
  "repomix-packer",
155
152
  "requesting-code-review",
156
153
  "retention-loops",
157
- "review-routing",
158
154
  "rice-prioritization",
159
155
  "risk-officer",
160
156
  "roadmap-management",
@@ -170,7 +166,6 @@
170
166
  "security",
171
167
  "sentry-integration",
172
168
  "sequential-thinking",
173
- "skill-improvement-pipeline",
174
169
  "skill-management",
175
170
  "skill-reviewer",
176
171
  "song-to-script",
@@ -181,7 +176,6 @@
181
176
  "subagent-orchestration",
182
177
  "symfony-workflow",
183
178
  "systematic-debugging",
184
- "tailwind-engineer",
185
179
  "tech-debt-tracker",
186
180
  "technical-specification",
187
181
  "terraform",
@@ -192,7 +186,6 @@
192
186
  "throughput-vs-morale-tradeoff",
193
187
  "token-optimizer",
194
188
  "traefik",
195
- "ui-component-architect",
196
189
  "unit-economics-modeling",
197
190
  "universal-project-analysis",
198
191
  "upstream-contribute",
@@ -19,9 +19,11 @@
19
19
  * - `--dry-run` (MockRouter, no key, no spend) exercises the plumbing only;
20
20
  * floors are REPORTED but never fail the run — mock routing says nothing
21
21
  * about real trigger accuracy.
22
- * - Rotation is a pure function of (week index, batch size, sorted suite
23
- * list): ~batch suites per week, wrapping so every suite is visited on a
24
- * fixed cadence regardless of suite-count drift.
22
+ * - Rotation is a pure function of (week index, suite identity): a suite's
23
+ * slot comes from a hash of its own name, so every suite is visited once per
24
+ * `ROTATION_CYCLE_WEEKS` and adding one shifts nobody else. What floats is
25
+ * how many run in a given week; `rotation_plan` reports that and the weekly
26
+ * query cost it implies.
25
27
  *
26
28
  * Exit codes: 0 pass (always, in --dry-run) · 1 live floor breach ·
27
29
  * 2 usage / IO error.
@@ -48,7 +50,6 @@ const _HERE = path.dirname(fileURLToPath(import.meta.url));
48
50
  const REPO_ROOT = path.resolve(_HERE, '..', '..');
49
51
  const SKILLS_DIR = path.join(REPO_ROOT, 'src', 'skills');
50
52
  const DEFAULT_OUT_DIR = path.join(REPO_ROOT, 'internal', 'evals', 'results', 'rotation');
51
- const DEFAULT_BATCH = 5;
52
53
 
53
54
  /** Router that may expose an async route (fetch-based live routers). */
54
55
  type AsyncCapableRouter = TriggerRouter & {
@@ -64,23 +65,116 @@ export function week_index(d: Date): number {
64
65
  }
65
66
 
66
67
  /**
67
- * Deterministic rotation: batch consecutive suites starting at
68
- * `(week * batch) mod total`, wrapping. Every suite is visited within
69
- * ceil(total / batch) weeks; adding/removing suites shifts but never
70
- * starves the cycle.
68
+ * Weeks in one full rotation cycle. 12 × 7 = 84 days, inside the 90-day
69
+ * `MAX_AGE_DAYS` window `check_trigger_evals` enforces.
71
70
  */
72
- export function pick_rotation<T>(suites: readonly T[], week: number, batch: number): T[] {
73
- if (suites.length === 0 || batch <= 0) {
71
+ export const ROTATION_CYCLE_WEEKS = 12;
72
+
73
+ /** Provider queries one suite's live pass costs, measured at ~9.5; rounded up. */
74
+ export const QUERIES_PER_SUITE = 10;
75
+
76
+ /**
77
+ * Stated weekly ceiling for the rotation's paid calls. Growth past it does not
78
+ * silently raise the bill — `rotation_plan` reports `withinCeiling: false` and
79
+ * a test asserts the live suite list stays under it, so crossing it is a red a
80
+ * human decides on rather than an invoice they discover.
81
+ *
82
+ * **Set from measurement, and the arithmetic is the point.** At 102 suites a
83
+ * full pass costs ~1020 queries; spread over a 12-week cycle that is ~85 a week
84
+ * on average and 140 in the busiest week (hash spread, measured 2026-09-30).
85
+ * 160 leaves headroom for that unevenness and reds at roughly 117 suites.
86
+ *
87
+ * The number nobody can lower by tuning: a 90-day window over N suites costs
88
+ * `N × QUERIES_PER_SUITE` every 90 days, whatever the schedule. The scheme this
89
+ * replaced looked cheaper only because it never completed a pass — `batch = 5`
90
+ * over 102 suites is a 21-week cycle, which misses the 90-day window by 57 days.
91
+ * Cheapness was the symptom of the defect, not a property worth preserving.
92
+ */
93
+ export const MAX_WEEKLY_QUERIES = 160;
94
+
95
+ /**
96
+ * FNV-1a over the suite id. Any stable hash works; what matters is that a
97
+ * suite's slot depends on the suite alone and on nothing about the list it
98
+ * sits in.
99
+ */
100
+ function slot_of(id: string, cycleWeeks: number): number {
101
+ let h = 0x811c9dc5;
102
+ for (let i = 0; i < id.length; i += 1) {
103
+ h ^= id.charCodeAt(i);
104
+ h = Math.imul(h, 0x01000193) >>> 0;
105
+ }
106
+ return h % cycleWeeks;
107
+ }
108
+
109
+ /**
110
+ * Deterministic rotation by suite identity: a suite is due in the weeks whose
111
+ * `week mod cycleWeeks` equals its own slot, so worst-case staleness is exactly
112
+ * `cycleWeeks` for any suite present across a cycle — independent of how many
113
+ * suites exist.
114
+ *
115
+ * **Why not the positional window this replaces.** It selected `batch`
116
+ * consecutive suites from `start = (week * batch) mod total`, and that start
117
+ * re-bases whenever `total` changes, so a region can be skipped repeatedly.
118
+ * Simulated against a list growing by one suite every eight weeks over five
119
+ * years, worst-case staleness reached **24 weeks against a 12-week window**;
120
+ * `trigger_eval_rotation_growth.test.ts` is that simulation, and it was
121
+ * observed red against the old scheme before this replaced it. A loop over
122
+ * static totals cannot see the defect, which is why the earlier test suite
123
+ * passed while the property was false.
124
+ *
125
+ * The cost of the fix is that the batch is no longer a knob: how many suites
126
+ * run in a given week follows from the hash distribution, and `rotation_plan`
127
+ * reports it rather than leaving it to be discovered on an invoice.
128
+ */
129
+ export function pick_rotation<T>(
130
+ suites: readonly T[],
131
+ week: number,
132
+ cycleWeeks: number = ROTATION_CYCLE_WEEKS,
133
+ ): T[] {
134
+ if (suites.length === 0 || cycleWeeks <= 0) {
74
135
  return [];
75
136
  }
76
- const n = Math.min(batch, suites.length);
77
- const total = suites.length;
78
- const start = ((((week * batch) % total) + total) % total);
79
- const picked: T[] = [];
80
- for (let i = 0; i < n; i += 1) {
81
- picked.push(suites[(start + i) % total] as T);
137
+ const due = (((week % cycleWeeks) + cycleWeeks) % cycleWeeks);
138
+ return suites.filter((s) => slot_of(String(s), cycleWeeks) === due);
139
+ }
140
+
141
+ /** What a given suite list costs and promises, derivable without running it. */
142
+ export interface RotationPlan {
143
+ total: number;
144
+ cycleWeeks: number;
145
+ /** Suites in the busiest week of the cycle. */
146
+ peakSuitesPerWeek: number;
147
+ /** Provider queries in that busiest week. */
148
+ peakWeeklyQueries: number;
149
+ /** Worst-case days between two visits of one suite. */
150
+ worstCaseStalenessDays: number;
151
+ withinCeiling: boolean;
152
+ }
153
+
154
+ /**
155
+ * Derive the cost and staleness a suite list implies. Pure, so the weekly bill
156
+ * is readable from the code rather than from a run.
157
+ */
158
+ export function rotation_plan(
159
+ suites: readonly string[],
160
+ cycleWeeks: number = ROTATION_CYCLE_WEEKS,
161
+ ): RotationPlan {
162
+ const span = Math.max(cycleWeeks, 1);
163
+ const counts = new Array<number>(span).fill(0);
164
+ for (const s of suites) {
165
+ const slot = slot_of(s, span);
166
+ counts[slot] = (counts[slot] ?? 0) + 1;
82
167
  }
83
- return picked;
168
+ const peakSuitesPerWeek = counts.length > 0 ? Math.max(...counts) : 0;
169
+ const peakWeeklyQueries = peakSuitesPerWeek * QUERIES_PER_SUITE;
170
+ return {
171
+ total: suites.length,
172
+ cycleWeeks,
173
+ peakSuitesPerWeek,
174
+ peakWeeklyQueries,
175
+ worstCaseStalenessDays: cycleWeeks * 7,
176
+ withinCeiling: peakWeeklyQueries <= MAX_WEEKLY_QUERIES,
177
+ };
84
178
  }
85
179
 
86
180
  /** Enumerate skills carrying `evals/triggers.json`, sorted for determinism. */
@@ -181,7 +275,8 @@ export async function run_eval_async(
181
275
 
182
276
  export interface RotationOptions {
183
277
  week?: number;
184
- batch?: number;
278
+ /** Weeks in a full cycle; also the worst-case staleness. Default 12. */
279
+ cycleWeeks?: number;
185
280
  dryRun?: boolean;
186
281
  outDir?: string;
187
282
  model?: string;
@@ -202,7 +297,7 @@ export interface RotationSuiteOutcome {
202
297
 
203
298
  export interface RotationSummary {
204
299
  week: number;
205
- batch: number;
300
+ cycle_weeks: number;
206
301
  total_suites: number;
207
302
  dry_run: boolean;
208
303
  outcomes: RotationSuiteOutcome[];
@@ -211,14 +306,14 @@ export interface RotationSummary {
211
306
 
212
307
  export async function run_rotation(opts: RotationOptions = {}): Promise<RotationSummary> {
213
308
  const dryRun = opts.dryRun ?? false;
214
- const batch = opts.batch ?? DEFAULT_BATCH;
309
+ const cycleWeeks = opts.cycleWeeks ?? ROTATION_CYCLE_WEEKS;
215
310
  const week = opts.week ?? week_index(new Date());
216
311
  const outDir = opts.outDir ?? DEFAULT_OUT_DIR;
217
312
  const model = opts.model ?? DEFAULT_MODEL;
218
313
  const skillsDir = opts.skillsDir ?? SKILLS_DIR;
219
314
 
220
315
  const suites = list_trigger_suites(skillsDir);
221
- const picked = pick_rotation(suites, week, batch);
316
+ const picked = pick_rotation(suites, week, cycleWeeks);
222
317
  const catalogue = load_skill_metas();
223
318
 
224
319
  const router: AsyncCapableRouter =
@@ -257,7 +352,7 @@ export async function run_rotation(opts: RotationOptions = {}): Promise<Rotation
257
352
 
258
353
  return {
259
354
  week,
260
- batch,
355
+ cycle_weeks: cycleWeeks,
261
356
  total_suites: suites.length,
262
357
  dry_run: dryRun,
263
358
  outcomes,
@@ -278,7 +373,7 @@ function parse_args(argv: string[]): RotationOptions & { help?: boolean } {
278
373
  return v as string;
279
374
  };
280
375
  if (a === '--week') out.week = Number(take());
281
- else if (a === '--batch') out.batch = Number(take());
376
+ else if (a === '--cycle-weeks') out.cycleWeeks = Number(take());
282
377
  else if (a === '--dry-run') out.dryRun = true;
283
378
  else if (a === '--out-dir') out.outDir = path.resolve(take());
284
379
  else if (a === '--model') out.model = take();
@@ -292,8 +387,8 @@ function parse_args(argv: string[]): RotationOptions & { help?: boolean } {
292
387
  process.stderr.write('trigger_eval_rotation: error: --week must be an integer\n');
293
388
  process.exit(2);
294
389
  }
295
- if (out.batch !== undefined && (!Number.isInteger(out.batch) || out.batch <= 0)) {
296
- process.stderr.write('trigger_eval_rotation: error: --batch must be a positive integer\n');
390
+ if (out.cycleWeeks !== undefined && (!Number.isInteger(out.cycleWeeks) || out.cycleWeeks <= 0)) {
391
+ process.stderr.write('trigger_eval_rotation: error: --cycle-weeks must be a positive integer\n');
297
392
  process.exit(2);
298
393
  }
299
394
  return out;
@@ -303,7 +398,7 @@ export async function main(argv?: string[]): Promise<number> {
303
398
  const opts = parse_args(argv ?? process.argv.slice(2));
304
399
  if (opts.help) {
305
400
  process.stdout.write(
306
- 'usage: trigger_eval_rotation [--week N] [--batch N] [--dry-run]\n' +
401
+ 'usage: trigger_eval_rotation [--week N] [--cycle-weeks N] [--dry-run]\n' +
307
402
  ' [--out-dir DIR] [--model MODEL]\n',
308
403
  );
309
404
  return 0;
@@ -316,7 +411,7 @@ export async function main(argv?: string[]): Promise<number> {
316
411
  return 2;
317
412
  }
318
413
  process.stdout.write(
319
- `trigger-eval rotation · week=${summary.week} · batch=${summary.batch} · ` +
414
+ `trigger-eval rotation · week=${summary.week} · cycle=${summary.cycle_weeks}w · ` +
320
415
  `${summary.outcomes.length}/${summary.total_suites} suites this run` +
321
416
  `${summary.dry_run ? ' · DRY-RUN (floors advisory)' : ''}\n`,
322
417
  );