@event4u/agent-config 16.0.0 → 16.2.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 (382) 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 +289 -140
  5. package/CONTRIBUTING.md +9 -0
  6. package/README.md +2 -2
  7. package/dist/agent-src/commands/analyze/inbox.md +26 -0
  8. package/dist/agent-src/commands/analyze/roadmap-repos.md +27 -0
  9. package/dist/agent-src/commands/challenge-me/closure.md +178 -0
  10. package/dist/agent-src/commands/challenge-me.md +9 -2
  11. package/dist/agent-src/commands/council/default.md +25 -5
  12. package/dist/agent-src/commands/feature/plan.md +28 -1
  13. package/dist/agent-src/commands/feature/roadmap.md +28 -1
  14. package/dist/agent-src/commands/implement-ticket.md +27 -0
  15. package/dist/agent-src/commands/jira-ticket.md +27 -0
  16. package/dist/agent-src/commands/pr/create.md +29 -0
  17. package/dist/agent-src/commands/pr/merge.md +60 -9
  18. package/dist/agent-src/commands/roadmap/ai-council.md +7 -1
  19. package/dist/agent-src/commands/roadmap/create.md +74 -27
  20. package/dist/agent-src/commands/roadmap/materialize.md +27 -0
  21. package/dist/agent-src/commands/roadmap/process-full.md +123 -18
  22. package/dist/agent-src/commands/team.md +22 -0
  23. package/dist/agent-src/commands/work.md +4 -0
  24. package/dist/agent-src/contexts/authority/scope-growth-ownership.md +80 -0
  25. package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +47 -0
  26. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +44 -3
  27. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +19 -23
  28. package/dist/agent-src/contexts/execution/decision-closure-execution.md +93 -0
  29. package/dist/agent-src/contexts/execution/fix-loop-ladder.md +108 -0
  30. package/dist/agent-src/contexts/execution/plan-confidence-gate.md +4 -2
  31. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +75 -6
  32. package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
  33. package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
  34. package/dist/agent-src/guidelines/design-fidelity-routing.md +29 -0
  35. package/dist/agent-src/rules/autonomous-execution.md +15 -8
  36. package/dist/agent-src/rules/delegation-policy.md +23 -45
  37. package/dist/agent-src/rules/design-fidelity.md +32 -37
  38. package/dist/agent-src/rules/evaluator-independence.md +43 -49
  39. package/dist/agent-src/rules/test-first.md +41 -0
  40. package/dist/agent-src/rules/ui-audit-gate.md +1 -2
  41. package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +1 -1
  42. package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
  43. package/dist/agent-src/skills/ai-council/SKILL.md +11 -3
  44. package/dist/agent-src/skills/api-design/data/manifest.json +3 -3
  45. package/dist/agent-src/skills/database/data/manifest.json +4 -4
  46. package/dist/agent-src/skills/database/data/query-tuning.csv +3 -3
  47. package/dist/agent-src/skills/design-review/SKILL.md +80 -4
  48. package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
  49. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +30 -5
  50. package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
  51. package/dist/agent-src/skills/experiment-loop/SKILL.md +31 -1
  52. package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
  53. package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
  54. package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
  55. package/dist/agent-src/skills/storybook-workshop/SKILL.md +42 -3
  56. package/dist/agent-src/skills/threat-modeling/SKILL.md +9 -4
  57. package/dist/agent-src/skills/threat-modeling/data/manifest.json +4 -4
  58. package/dist/agent-src/skills/ui-component-architect/SKILL.md +23 -0
  59. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +37 -3
  60. package/dist/agent-src/templates/agent-settings.md +1 -1
  61. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  62. package/dist/agent-src/templates/roadmaps.md +218 -0
  63. package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
  64. package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
  65. package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
  66. package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
  67. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +260 -21
  68. package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
  69. package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
  70. package/dist/agent-src/templates/scripts/work_engine/state.ts +57 -7
  71. package/dist/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
  72. package/dist/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
  73. package/dist/cli/python/knowledge_ingest.js +1 -1
  74. package/dist/cli/python/workspace_drive.js +1 -1
  75. package/dist/cli-delegate/check_update_banner.js +40 -2
  76. package/dist/cli-delegate/chunk-4E2W63DA.js +335 -0
  77. package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-4XFP2Y3E.js} +1 -1
  78. package/dist/cli-delegate/chunk-5R7HOLAF.js +99 -0
  79. package/dist/cli-delegate/{chunk-IVBPRCQO.js → chunk-6KFEC3G7.js} +1 -1
  80. package/dist/cli-delegate/{chunk-2TAQ2K4V.js → chunk-6KM6ORRY.js} +55 -386
  81. package/dist/cli-delegate/{chunk-AK6HODNQ.js → chunk-7XGBX6ZH.js} +973 -555
  82. package/dist/cli-delegate/{chunk-2XY7ILBT.js → chunk-FC75PGJE.js} +42 -2
  83. package/dist/cli-delegate/{chunk-55ACLDUE.js → chunk-FP36SWJD.js} +587 -141
  84. package/dist/cli-delegate/{chunk-3FKR64R5.js → chunk-IGD6ERX6.js} +62 -7
  85. package/dist/cli-delegate/{chunk-GYC3VRYN.js → chunk-JNMVLWLR.js} +99 -14
  86. package/dist/cli-delegate/{chunk-H32DGUJH.js → chunk-P6ZHP5W2.js} +1 -1
  87. package/dist/cli-delegate/{chunk-57PN4GYJ.js → chunk-RGNIWTEA.js} +1 -1
  88. package/dist/cli-delegate/chunk-ROYYTEZU.js +39 -0
  89. package/dist/cli-delegate/{chunk-2DK2VJWG.js → chunk-WGXTVKCQ.js} +20 -6
  90. package/dist/cli-delegate/chunk-YDPILCOL.js +152 -0
  91. package/dist/cli-delegate/{chunk-QJWAUMJW.js → chunk-YJ72UIAK.js} +730 -15
  92. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  93. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  94. package/dist/cli-delegate/cmd_conformance.js +985 -831
  95. package/dist/cli-delegate/cmd_doctor.js +7 -5
  96. package/dist/cli-delegate/cmd_explain.js +2 -2
  97. package/dist/cli-delegate/cmd_export.js +9 -7
  98. package/dist/cli-delegate/cmd_fleet.js +4 -2
  99. package/dist/cli-delegate/cmd_handoff.js +7 -7
  100. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  101. package/dist/cli-delegate/cmd_memory_get.js +1 -1
  102. package/dist/cli-delegate/cmd_migrate.js +2 -2
  103. package/dist/cli-delegate/cmd_packs_active.js +2 -2
  104. package/dist/cli-delegate/cmd_preflight.js +4 -2
  105. package/dist/cli-delegate/cmd_prune.js +10 -8
  106. package/dist/cli-delegate/cmd_route_audit.js +3 -3
  107. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  108. package/dist/cli-delegate/cmd_session_recycle.js +4 -4
  109. package/dist/cli-delegate/cmd_settings_get.js +28 -2
  110. package/dist/cli-delegate/cmd_settings_migrate.js +9 -7
  111. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  112. package/dist/cli-delegate/cmd_sync.js +10 -8
  113. package/dist/cli-delegate/cmd_uninstall.js +16 -13
  114. package/dist/cli-delegate/cmd_update.js +1 -1
  115. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  116. package/dist/cli-delegate/cmd_validate.js +12 -10
  117. package/dist/cli-delegate/cmd_versions.js +1 -1
  118. package/dist/discovery/deprecation-report.md +1 -1
  119. package/dist/discovery/discovery-manifest.json +90 -43
  120. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  121. package/dist/discovery/discovery-manifest.summary.md +4 -4
  122. package/dist/discovery/dormancy-report.md +1 -1
  123. package/dist/discovery/orphan-report.md +1 -1
  124. package/dist/discovery/packs.json +10 -8
  125. package/dist/discovery/trust-report.md +3 -3
  126. package/dist/discovery/workspaces.json +8 -6
  127. package/dist/hooks/dispatch.js +7682 -2772
  128. package/dist/hooks/dispatch.sha256 +1 -0
  129. package/dist/install/claudeRuleRewrite.js +14 -3
  130. package/dist/install/conflict.js +60 -10
  131. package/dist/install/conflictTracker.js +218 -0
  132. package/dist/install/fsPrimitives.js +54 -0
  133. package/dist/install/install.mjs +2200 -1559
  134. package/dist/install/manifestFiles.js +259 -0
  135. package/dist/install/preflight.js +14 -2
  136. package/dist/install/preserve.js +157 -0
  137. package/dist/install/recordedOwnership.js +132 -0
  138. package/dist/install/txlog.js +11 -2
  139. package/dist/mcp/registry-manifest.json +3 -3
  140. package/dist/mcp/server.json +2 -2
  141. package/dist/mcp/server.mjs +3066 -1470
  142. package/dist/router.json +1 -1
  143. package/dist/scripts/_lib/agent_settings.js +3 -2
  144. package/dist/scripts/_lib/fs_atomic.js +167 -0
  145. package/dist/scripts/_lib/installed_tools.js +460 -0
  146. package/dist/scripts/_lib/lean_projection_mode.js +3 -2
  147. package/dist/scripts/_lib/settings_renamed_keys.js +78 -0
  148. package/dist/server/routes/install.js +8 -0
  149. package/dist/server/routes/wizard.js +9 -3
  150. package/dist/server/schemas/settings.js +40 -5
  151. package/dist/shared/missionExecution.js +97 -0
  152. package/dist/ui/assets/index-Cwq4d0hX.js +23 -0
  153. package/dist/ui/assets/index-Cyjy8bWO.css +1 -0
  154. package/dist/ui/index.html +2 -2
  155. package/docs/MIGRATION.md +103 -0
  156. package/docs/contracts/settings-classes.md +28 -7
  157. package/docs/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
  158. package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
  159. package/docs/guidelines/design-fidelity-routing.md +29 -0
  160. package/package.json +4 -4
  161. package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
  162. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
  163. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
  164. package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
  165. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +260 -21
  166. package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
  167. package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
  168. package/src/agent-src/templates/scripts/work_engine/state.ts +57 -7
  169. package/src/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
  170. package/src/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
  171. package/src/config/agent-settings.template.yml +168 -27
  172. package/src/config/auto-rule-budget.json +16 -0
  173. package/src/config/ci-local-parity.yml +36 -5
  174. package/src/config/continuity-surface.json +23 -2
  175. package/src/config/gate-coverage.yml +377 -13
  176. package/src/config/gate-violation-baselines.json +10 -6
  177. package/src/config/hook-latency-budget.json +21 -0
  178. package/src/config/hook-token-budget.json +4 -2
  179. package/src/config/loop-surfaces.yaml +215 -0
  180. package/src/config/metric-registry.yml +114 -0
  181. package/src/config/placeholder-drift-budget.json +10 -0
  182. package/src/config/platform-anchor.json +3 -2
  183. package/src/config/release-gate-locality.yml +11 -0
  184. package/src/config/routing-coverage-seed.json +33 -5
  185. package/src/config/rule-enforcement-baseline.json +0 -1
  186. package/src/install/claudeRuleRewrite.ts +16 -2
  187. package/src/install/conflict.ts +65 -9
  188. package/src/install/conflictTracker.ts +299 -0
  189. package/src/install/fsPrimitives.ts +54 -0
  190. package/src/install/manifestFiles.ts +312 -0
  191. package/src/install/preflight.ts +16 -2
  192. package/src/install/preserve.ts +205 -0
  193. package/src/install/recordedOwnership.ts +149 -0
  194. package/src/install/txlog.ts +11 -2
  195. package/src/install/types.ts +19 -4
  196. package/src/scripts/_cli/cmd_conformance.ts +88 -15
  197. package/src/scripts/_cli/cmd_doctor.ts +7 -20
  198. package/src/scripts/_cli/cmd_route_explain.ts +9 -2
  199. package/src/scripts/_cli/cmd_settings_get.ts +44 -0
  200. package/src/scripts/_cli/doctor_execution.ts +173 -0
  201. package/src/scripts/_cli/doctor_network_posture.ts +226 -0
  202. package/src/scripts/_lib/activation_payload.ts +247 -0
  203. package/src/scripts/_lib/agent_settings.ts +4 -2
  204. package/src/scripts/_lib/authority_path.ts +102 -0
  205. package/src/scripts/_lib/body_portable.ts +102 -0
  206. package/src/scripts/_lib/cascade_base.ts +94 -0
  207. package/src/scripts/_lib/cc_transcript.ts +132 -1
  208. package/src/scripts/_lib/changelog_eras.ts +7 -2
  209. package/src/scripts/_lib/concern_sla_window.ts +200 -0
  210. package/src/scripts/_lib/continuation_ladder.ts +149 -2
  211. package/src/scripts/_lib/council_transport.ts +129 -0
  212. package/src/scripts/_lib/delivery_ready.ts +112 -0
  213. package/src/scripts/_lib/forge_protection.ts +381 -0
  214. package/src/scripts/_lib/forge_reader.ts +558 -0
  215. package/src/scripts/_lib/hook_platform_keys.ts +27 -0
  216. package/src/scripts/_lib/host_env_write.ts +111 -0
  217. package/src/scripts/_lib/json_python_parity.ts +127 -0
  218. package/src/scripts/_lib/lean_projection_mode.ts +14 -3
  219. package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
  220. package/src/scripts/_lib/loop_surfaces.ts +382 -0
  221. package/src/scripts/_lib/mission_record.ts +190 -0
  222. package/src/scripts/_lib/obligation_frequency.ts +217 -0
  223. package/src/scripts/_lib/obligations.ts +513 -0
  224. package/src/scripts/_lib/orchestration_record.ts +11 -20
  225. package/src/scripts/_lib/probe_inputs.ts +271 -0
  226. package/src/scripts/_lib/read_surface_scan.ts +322 -0
  227. package/src/scripts/_lib/release_highlights.ts +201 -11
  228. package/src/scripts/_lib/release_holds.ts +493 -0
  229. package/src/scripts/_lib/release_migration_gate.ts +184 -0
  230. package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
  231. package/src/scripts/_lib/rides_along.ts +102 -0
  232. package/src/scripts/_lib/settings_renamed_keys.ts +82 -0
  233. package/src/scripts/_lib/shell_write_shapes.ts +108 -0
  234. package/src/scripts/_lib/structural_hiding.ts +622 -0
  235. package/src/scripts/_lib/test_delta.ts +166 -0
  236. package/src/scripts/_lib/test_provenance.ts +171 -0
  237. package/src/scripts/_lib/turn_end_refusals.ts +525 -4
  238. package/src/scripts/_lib/turn_end_transcript.ts +216 -0
  239. package/src/scripts/_lib/typed_op_grant.ts +246 -0
  240. package/src/scripts/_lib/typed_op_watch.ts +185 -0
  241. package/src/scripts/_lib/verification_command.ts +324 -0
  242. package/src/scripts/_lib/verification_evidence.ts +647 -0
  243. package/src/scripts/_lib/verify_clause.ts +280 -0
  244. package/src/scripts/ai_council/config.ts +8 -11
  245. package/src/scripts/ai_council/fallback_config.ts +5 -3
  246. package/src/scripts/ai_council/ownership_classes.ts +118 -0
  247. package/src/scripts/ai_team/team_dispatch.ts +4 -0
  248. package/src/scripts/ask_block_census.ts +285 -15
  249. package/src/scripts/before_complete_hook.ts +340 -23
  250. package/src/scripts/bench_hook_latency.ts +412 -5
  251. package/src/scripts/cache_realization_report.ts +61 -1
  252. package/src/scripts/check_argument_hint.ts +287 -0
  253. package/src/scripts/check_claims.ts +125 -1
  254. package/src/scripts/check_enforcement_coverage.ts +38 -9
  255. package/src/scripts/check_enforcement_matrix.ts +866 -0
  256. package/src/scripts/check_finding_dispositions.ts +22 -3
  257. package/src/scripts/check_gate_reachability.ts +173 -10
  258. package/src/scripts/check_generator_sync.ts +1025 -0
  259. package/src/scripts/check_host_docs_digest.ts +786 -0
  260. package/src/scripts/check_host_format_column.ts +559 -0
  261. package/src/scripts/check_input_references.ts +228 -0
  262. package/src/scripts/check_inputs_parity.ts +235 -0
  263. package/src/scripts/check_kernel_edit_ratified.ts +47 -5
  264. package/src/scripts/check_kill_switch_table.ts +294 -0
  265. package/src/scripts/check_placeholder_drift.ts +221 -0
  266. package/src/scripts/check_preamble_payload_budget.ts +75 -2
  267. package/src/scripts/check_read_surface_coverage.ts +515 -0
  268. package/src/scripts/check_release_highlights.ts +33 -1
  269. package/src/scripts/check_release_holds.ts +568 -0
  270. package/src/scripts/check_routing_coverage.ts +378 -11
  271. package/src/scripts/check_rule_projection_integrity.ts +22 -12
  272. package/src/scripts/check_static_parity.ts +17 -0
  273. package/src/scripts/check_test_delta.ts +294 -0
  274. package/src/scripts/check_test_weakening.ts +299 -0
  275. package/src/scripts/ci_settle.ts +145 -19
  276. package/src/scripts/closure_scan.ts +447 -0
  277. package/src/scripts/compile_hook_manifest.ts +102 -18
  278. package/src/scripts/council_record_shape.ts +209 -0
  279. package/src/scripts/external_sources_denylist.json +29 -4
  280. package/src/scripts/hook_manifest.json +1 -1
  281. package/src/scripts/hook_manifest.yaml +127 -11
  282. package/src/scripts/hooks/block_config_weakening.ts +229 -4
  283. package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
  284. package/src/scripts/hooks/block_plumbing_writes.ts +314 -0
  285. package/src/scripts/hooks/bundle_integrity.ts +291 -0
  286. package/src/scripts/hooks/chain_nudge_hook.ts +1 -2
  287. package/src/scripts/hooks/code_graph_context_hook.ts +1 -2
  288. package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
  289. package/src/scripts/hooks/concern_registry.ts +6 -0
  290. package/src/scripts/hooks/concern_timings.ts +94 -0
  291. package/src/scripts/hooks/delegation_nudge_hook.ts +1 -2
  292. package/src/scripts/hooks/design_pass_hook.ts +221 -5
  293. package/src/scripts/hooks/design_slop_hook.ts +1 -2
  294. package/src/scripts/hooks/dispatch_hook.ts +25 -19
  295. package/src/scripts/hooks/edit_shape_hook.ts +1 -2
  296. package/src/scripts/hooks/end_review_nudge_hook.ts +1 -1
  297. package/src/scripts/hooks/evidence_independence.ts +97 -2
  298. package/src/scripts/hooks/exit_codes.ts +128 -0
  299. package/src/scripts/hooks/host_lowering.json +1 -0
  300. package/src/scripts/hooks/host_lowering.ts +128 -3
  301. package/src/scripts/hooks/host_lowering.yaml +262 -46
  302. package/src/scripts/hooks/host_semantics.ts +30 -2
  303. package/src/scripts/hooks/injection_budget.ts +9 -2
  304. package/src/scripts/hooks/interruption_ledger_hook.ts +1 -2
  305. package/src/scripts/hooks/journal_record_hook.ts +1 -2
  306. package/src/scripts/hooks/memory_recall_hook.ts +539 -0
  307. package/src/scripts/hooks/obligation_settle_hook.ts +328 -0
  308. package/src/scripts/hooks/one_question_per_ask_hook.ts +25 -4
  309. package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
  310. package/src/scripts/hooks/permission_gate.ts +1 -2
  311. package/src/scripts/hooks/push_settle_hook.ts +1 -3
  312. package/src/scripts/hooks/replay_hook.ts +2 -1
  313. package/src/scripts/hooks/reread_guard_hook.ts +1 -2
  314. package/src/scripts/hooks/review_baseline_hook.ts +1 -2
  315. package/src/scripts/hooks/rtk_wrap_hook.ts +1 -2
  316. package/src/scripts/hooks/rule_inject_hook.ts +55 -4
  317. package/src/scripts/hooks/run_continuation_hook.ts +30 -35
  318. package/src/scripts/hooks/skill_route_hook.ts +1 -2
  319. package/src/scripts/hooks/source_first_gate_hook.ts +1 -2
  320. package/src/scripts/hooks/spawn_guard_shadow_hook.ts +1 -2
  321. package/src/scripts/hooks/subagent_ledger_hook.ts +1 -2
  322. package/src/scripts/hooks/suggestion_capture_hook.ts +1 -1
  323. package/src/scripts/hooks/table_fingerprint.ts +49 -0
  324. package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
  325. package/src/scripts/hooks/telemetry_usage_hook.ts +1 -2
  326. package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
  327. package/src/scripts/hooks/turn_end_gate_hook.ts +337 -324
  328. package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
  329. package/src/scripts/hooks_doctor.ts +85 -0
  330. package/src/scripts/hooks_status.ts +19 -0
  331. package/src/scripts/install.ts +109 -210
  332. package/src/scripts/janitor.ts +7 -0
  333. package/src/scripts/lint_decision_classes.ts +464 -0
  334. package/src/scripts/lint_deny_text.ts +419 -0
  335. package/src/scripts/lint_exit_codes.ts +262 -0
  336. package/src/scripts/lint_hook_manifest.ts +66 -0
  337. package/src/scripts/lint_major_migration_sections.ts +450 -0
  338. package/src/scripts/lint_plan_risk_register.ts +47 -3
  339. package/src/scripts/lint_roadmap_blockers.ts +139 -12
  340. package/src/scripts/lint_roadmap_producers.ts +202 -0
  341. package/src/scripts/lint_skill_descriptions.ts +1 -1
  342. package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
  343. package/src/scripts/mcp_server/prompts.ts +142 -1
  344. package/src/scripts/measure_rule_budget.ts +101 -5
  345. package/src/scripts/measure_skill_ranker_baseline.ts +305 -51
  346. package/src/scripts/measure_turn_end_gate.ts +193 -0
  347. package/src/scripts/memory_lookup.ts +1 -1
  348. package/src/scripts/new_roadmap.ts +37 -0
  349. package/src/scripts/orchestration_record.ts +0 -5
  350. package/src/scripts/prepack-check.mjs +53 -0
  351. package/src/scripts/release.ts +14 -98
  352. package/src/scripts/release_drill.ts +267 -1
  353. package/src/scripts/release_publication.ts +64 -1
  354. package/src/scripts/report_enforcement_drift.ts +566 -0
  355. package/src/scripts/report_host_injection_effect.ts +3 -11
  356. package/src/scripts/report_invocation_surface.ts +383 -0
  357. package/src/scripts/report_obligation_carriers.ts +699 -0
  358. package/src/scripts/report_obligation_writer_split.ts +236 -0
  359. package/src/scripts/report_skill_menu_census.ts +208 -0
  360. package/src/scripts/report_standing_payload_by_host.ts +26 -152
  361. package/src/scripts/roadmap_verify_share.ts +213 -0
  362. package/src/scripts/schemas/agent-settings.schema.json +23 -0
  363. package/src/scripts/schemas/command.schema.json +48 -0
  364. package/src/scripts/schemas/review-findings.schema.json +4 -0
  365. package/src/scripts/schemas/skill.schema.json +44 -0
  366. package/src/scripts/scope_growth.ts +219 -0
  367. package/src/scripts/self_review_gate.ts +359 -10
  368. package/src/scripts/semantic_parity_census.ts +314 -0
  369. package/src/scripts/session_eol_report.ts +54 -1
  370. package/src/scripts/sweep_dead_scan_roots.ts +1 -1
  371. package/src/scripts/trigger_eval_grandfather.json +0 -3
  372. package/src/scripts/trigger_eval_rotation.ts +122 -27
  373. package/src/scripts/ui_conformance_probe.ts +774 -0
  374. package/src/scripts/update_prices.ts +85 -3
  375. package/src/scripts/write_bundle_digest.mjs +74 -0
  376. package/src/server/schemas/settings.ts +62 -7
  377. package/src/shared/missionExecution.ts +126 -0
  378. package/src/templates/consumer-settings/ONBOARDING.md +1 -0
  379. package/dist/cli-delegate/chunk-523HCFYO.js +0 -90
  380. package/dist/ui/assets/index-D0jaCRPM.js +0 -29
  381. package/dist/ui/assets/index-jSfMW8_t.css +0 -1
  382. /package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-7RQP4UDH.js} +0 -0
@@ -0,0 +1,173 @@
1
+ /**
2
+ * The `execution` block of `agent-config doctor --json`.
3
+ *
4
+ * `road-to-adversarial-verification-and-long-runs` Phase 0.3. Its own module
5
+ * rather than a function inside `cmd_doctor.ts` for the reason
6
+ * `_lib/continuation_ladder.ts` states for itself: `check_source_size_budget` is
7
+ * a shrink-only ratchet and `cmd_doctor.ts` sits far past the 1,500-line cap, so
8
+ * every line added there is an added violation. A phase pays for its additions by
9
+ * putting new code in a file under the cap rather than by raising a baseline.
10
+ *
11
+ * `owner_owned_check` appears here as the ladder's last RUNG rather than as a
12
+ * separate field, because it is not a separate switch: it is the rung that
13
+ * decides whether the residue is owner-owned at all, and lifting it out would
14
+ * suggest it can be toggled independently of the order it sits in.
15
+ */
16
+
17
+ import {
18
+ executionPostureFromOverrides,
19
+ resolveExecutionPosture,
20
+ } from '../../shared/missionExecution.js';
21
+ import {
22
+ forgeProtectionRows,
23
+ protectionActions,
24
+ type ForgeReading,
25
+ } from '../_lib/forge_protection.js';
26
+ import {
27
+ FORGE_TOTAL_BUDGET_MS,
28
+ budgetOf,
29
+ forgeReadingFor,
30
+ liveForgeApi,
31
+ originUrl,
32
+ resolveForgeRepo,
33
+ type Runner,
34
+ } from '../_lib/forge_reader.js';
35
+
36
+ type Dict = Record<string, unknown>;
37
+
38
+ /** A settings-override stream, in the shape `iter_setting_overrides` yields. */
39
+ export type OverrideStream = Iterable<readonly [string, unknown, string]>;
40
+
41
+ /**
42
+ * Build the payload block from a settings-override stream.
43
+ *
44
+ * A stream that throws yields the defaults rather than propagating — a
45
+ * diagnostic that cannot report because its own input is malformed is the one
46
+ * shape `doctor` must never take.
47
+ */
48
+ export function executionJson(overrides: () => OverrideStream): Dict {
49
+ let posture;
50
+ try {
51
+ posture = executionPostureFromOverrides(overrides());
52
+ } catch {
53
+ posture = resolveExecutionPosture({});
54
+ }
55
+ return {
56
+ fix_loop_max: posture.fix_loop_max,
57
+ escalation: [...posture.escalation],
58
+ };
59
+ }
60
+
61
+ /**
62
+ * The `forge_protection` block of `doctor --json` — Phase 3.2.
63
+ *
64
+ * **THIS function does not reach the network; `doctor` now does.** The mapper
65
+ * stays pure and takes an INJECTED reading — a caller that queried the forge
66
+ * passes it, one that did not passes the all-null reading, which produces five
67
+ * `unread` rows that still name the call each value would come from. What
68
+ * changed is the caller: `forgeProtectionJsonFor` below acquires that reading,
69
+ * so `doctor --json` does make `gh` calls. Phase 3.2's "`doctor` does not reach
70
+ * the network" is SUPERSEDED, and this header said otherwise for three review
71
+ * rounds while the function forty lines down called it a reversal — the third
72
+ * copy of a refuted argument in this diff, each found by a different round.
73
+ * Corrected here for the reason the others were: a header is where a dead
74
+ * argument gets reused.
75
+ *
76
+ * That is the honest shape for *read, never guessed*: the block is always
77
+ * present, a value appears only when a named call produced it, and `unread` is a
78
+ * third state rather than a quiet `false`. A row that was never looked at and a
79
+ * row that was looked at and failed are different repairs.
80
+ *
81
+ * `actions` carries the human ACTION lines — the step's own words are that a
82
+ * missing row is a blocker entry and NOT a halt, so this reports and returns.
83
+ */
84
+ export function forgeProtectionJson(reading: ForgeReading, repo: string | null = null): Dict {
85
+ const rows = forgeProtectionRows(reading);
86
+ const readFromForge = rows.some((r) => r.state !== 'unread');
87
+ // **The slug is reported only when something was actually read, and that
88
+ // invariant is structural rather than a caller's promise.** The first
89
+ // version reported whatever the git remote resolved to, which is a LOCAL
90
+ // read that succeeds with no network — so an ordinary offline run (GitHub
91
+ // remote present, no connectivity, no opt-out) emitted a named repository
92
+ // and substituted sources while every row was `unread`. That made the
93
+ // claim this change rests on — offline output is what Phase 3.2 shipped —
94
+ // false on exactly the failed-live path the council condition names. The
95
+ // earlier verification only ever exercised the opt-out switch and read it
96
+ // as offline; the two are not the same path.
97
+ const anonymous = repo === null || !readFromForge;
98
+ const name = (s: string): string =>
99
+ anonymous ? s : s.replace(/\{owner\}\/\{repo\}/g, () => repo);
100
+ return {
101
+ repository: readFromForge ? repo : null,
102
+ rows: rows.map((r) => ({
103
+ id: r.id,
104
+ state: r.state,
105
+ source: name(r.source),
106
+ detail: r.detail,
107
+ })),
108
+ actions: protectionActions(rows).map(name),
109
+ read_from_forge: readFromForge,
110
+ };
111
+ }
112
+
113
+ /**
114
+ * The block as `doctor` itself builds it — AC-5.
115
+ *
116
+ * Phase 3.2 left `forgeProtectionJson` with no production caller, so the
117
+ * command the criterion names reported five `unread` rows while the forge
118
+ * satisfied all five, and the rows were only ever established by a human
119
+ * running `gh api` and reading the mapper in a test. This is the wiring that
120
+ * makes the named command answer for itself.
121
+ *
122
+ * **This IS a reversal of Phase 3.2's module boundary, and the roadmap records
123
+ * the supersession.** An earlier draft of this comment argued the opposite —
124
+ * "an addition rather than a reversal" — which a 2/2 convergent council pass
125
+ * refuted: that note recorded two boundaries, `doctor` does not reach the
126
+ * network AND the reading is injected, and this reverses both. The refuted
127
+ * argument is corrected here rather than left standing, because a comment is
128
+ * what the next reader of this module finds first and is where a refuted
129
+ * reasoning would get reused.
130
+ *
131
+ * What survives is the AVAILABILITY property, which is narrower than the
132
+ * earlier claim and is the one the supersession rests on: every failure path in
133
+ * `forgeReadingFor` — opt-out switch, no GitHub remote, no `gh`, no
134
+ * credentials, timeout, unparseable payload, a throw — returns the same
135
+ * `UNREAD_FORGE` reading, so offline the ROWS, their `source` templates and the
136
+ * action lines are what Phase 3.2 printed. Not the whole document: the block
137
+ * gained a top-level `repository` key, which is `null` on every such path. A
138
+ * consumer validating `forge_protection` against a closed schema sees that one
139
+ * added key; "prints exactly what it printed before" was too strong and is not
140
+ * claimed.
141
+ *
142
+ * `process.env` and the git remote are read HERE rather than inside the reader,
143
+ * so the reader stays injectable and every branch above is reachable from a
144
+ * test without spawning anything.
145
+ */
146
+ export interface ForgeDeps {
147
+ readonly env?: Readonly<Record<string, string | undefined>>;
148
+ /** The subprocess runner for both `git` and `gh`. */
149
+ readonly run?: Runner;
150
+ }
151
+
152
+ export function forgeProtectionJsonFor(root: string, deps: ForgeDeps = {}): Dict {
153
+ // The composition root — budget, thunk, host and cwd wired together — had
154
+ // no seam and therefore no test, so the opt-out-before-spawn and host
155
+ // binding were asserted one layer down against fakes while a regression in
156
+ // the real wiring stayed invisible. `deps` is that seam; production passes
157
+ // nothing and gets `process.env` plus the real spawn.
158
+ const env = deps.env ?? process.env;
159
+ const run = deps.run;
160
+ const remaining = budgetOf(FORGE_TOTAL_BUDGET_MS);
161
+ const read = forgeReadingFor({
162
+ env,
163
+ // A thunk, so the opt-out short-circuits before `git` spawns.
164
+ resolveRepo: () => resolveForgeRepo(originUrl(root, run)),
165
+ // Built from the RESOLVED target, so `gh` is addressed at the host and
166
+ // directory the slug came from. The per-call ceiling is whatever is
167
+ // left of the whole-read budget, so a call admitted near the deadline
168
+ // cannot run past it.
169
+ apiFor: (t) => liveForgeApi(remaining, run, { host: t.host, cwd: root }),
170
+ remaining,
171
+ });
172
+ return forgeProtectionJson(read.reading, read.repo);
173
+ }
@@ -0,0 +1,226 @@
1
+ /**
2
+ * What this install does on the network — the two `doctor` surfaces that
3
+ * answer that question, in one module under the source-size cap.
4
+ *
5
+ * `road-to-host-traffic-knobs-that-ship` Phases 2.1 and 2.2. Its own module
6
+ * rather than a function inside `cmd_doctor.ts` for the reason
7
+ * `_lib/doctor_runtime_checks.ts` states for itself: that file is ~3,600 lines
8
+ * and `check_source_size_budget` counts every line above 1,500, so a change
9
+ * that adds lines there pays for them by taking lines away. Wiring the traffic
10
+ * section in costs two lines; `checkOfflineReadiness` moving here returns more
11
+ * than that, and lands beside a cohesive sibling rather than in an arbitrary
12
+ * bin — "can this install work with no registry" and "which host traffic is
13
+ * switched off" are the same question asked from two ends.
14
+ *
15
+ * `checkOfflineReadiness` is a PURE MOVE: same id, same statuses, same message
16
+ * and remedy strings. Its `pathExists` is `fs.statSync` in a try, matching the
17
+ * helper it used in `cmd_doctor.ts` — `existsSync` would differ on a path whose
18
+ * parent denies traversal, and this is a move, not a repair.
19
+ *
20
+ * Why the traffic section reports rather than decides: the variables below belong to the HOST, not to this package. Writing one into
21
+ * a consumer environment changes behaviour the consumer never asked to change,
22
+ * and — per the mapping measured in `docs/setup/host-traffic-environment.md` —
23
+ * could stop their background security updates as a side effect of a telemetry
24
+ * preference. So this module reads `env` and returns; it writes nothing, opens
25
+ * no socket, and touches no settings file. Two consecutive calls return equal
26
+ * payloads and leave the tree byte-identical.
27
+ *
28
+ * Why an inapplicable row is PRESENT and says so: the obvious implementation lists only the variables that resolve on the
29
+ * current host, which produces a short, clean section on a host that documents
30
+ * none of them. An operator reading that concludes their traffic is governed,
31
+ * when in fact the package simply had nothing to say. An omission that reads as
32
+ * a clean bill of health is the precise failure this surface exists to prevent,
33
+ * so a row that does not apply is emitted with the literal state
34
+ * {@link NOT_APPLICABLE} instead of being dropped.
35
+ *
36
+ * A variable that is SET on a host that does not document it still reports its
37
+ * value beside that state. The state says "this host is not known to read it";
38
+ * dropping the value as well would hide a fact the reader has.
39
+ */
40
+ import * as fs from 'node:fs';
41
+ import * as path from 'node:path';
42
+
43
+ /** The doctor's structured check row. Mirrors `cmd_doctor`'s internal `Dict`. */
44
+ export interface NetworkCheck {
45
+ id: string;
46
+ status: 'ok' | 'warn' | 'fail' | 'skipped';
47
+ message: string;
48
+ remedy: string;
49
+ /** Structural compatibility with `cmd_doctor`'s `Dict` row type. */
50
+ [k: string]: string;
51
+ }
52
+
53
+ /** The literal a row carries where the host has no documented meaning for it. */
54
+ export const NOT_APPLICABLE = 'not applicable on this host';
55
+
56
+ /** The documentation surface every row points at. One copy of the mapping. */
57
+ export const TRAFFIC_DOC = 'docs/setup/host-traffic-environment.md';
58
+
59
+ /** Host id used when nothing in the environment identifies the host. */
60
+ export const UNKNOWN_HOST = 'unknown';
61
+
62
+ /**
63
+ * One documented host traffic variable.
64
+ *
65
+ * `hosts` lists the host ids whose shipped build was actually READ for this
66
+ * variable — never a host somebody expects to behave the same way. A host
67
+ * absent from the list gets {@link NOT_APPLICABLE}, which is the honest answer
68
+ * and also the safe one.
69
+ */
70
+ export interface TrafficVariable {
71
+ readonly variable: string;
72
+ readonly hosts: readonly string[];
73
+ /** Host build and date the row was read from, e.g. `claude-code 2.1.284 · 2026-09-29`. */
74
+ readonly checked_against: string;
75
+ /**
76
+ * May THIS PACKAGE write the variable into the host env block?
77
+ *
78
+ * `false` on both traffic variables and it is not a policy setting — it is a
79
+ * structural fact: `install.ts`'s `WRITABLE_HOST_ENV` is a two-row allow
80
+ * table and the settings schema admits only those two keys, so neither
81
+ * traffic variable is expressible anywhere in the write path. Reported
82
+ * because a consumer reading `set` on a row deserves to know whether this
83
+ * package could have been the one that set it.
84
+ */
85
+ readonly writable_by_this_package: boolean;
86
+ }
87
+
88
+ /** The host build every row below was read from. One place to bump on a re-check. */
89
+ const CHECKED = 'claude-code 2.1.284 · 2026-09-29';
90
+
91
+ /**
92
+ * The documented set, in the order `docs/setup/host-traffic-environment.md`
93
+ * lists it. What each one governs — and does not — lives in that page and is
94
+ * deliberately not duplicated here: a second copy is a second thing to keep
95
+ * true, and this one would be the copy nobody re-reads.
96
+ */
97
+ export const TRAFFIC_VARIABLES: readonly TrafficVariable[] = [
98
+ // Both traffic variables reach the host's update-disabled resolver, the
99
+ // blanket one as its third rung, so neither is writable by this package —
100
+ // owner-decided 2026-09-30.
101
+ { variable: 'CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC', hosts: ['claude-code'], checked_against: CHECKED, writable_by_this_package: false },
102
+ { variable: 'DISABLE_AUTOUPDATER', hosts: ['claude-code'], checked_against: CHECKED, writable_by_this_package: false },
103
+ // Size caps. Neither reaches the updater resolver, and neither suppresses a
104
+ // call, an update check or a download.
105
+ { variable: 'BASH_MAX_OUTPUT_LENGTH', hosts: ['claude-code'], checked_against: CHECKED, writable_by_this_package: true },
106
+ { variable: 'MAX_MCP_OUTPUT_TOKENS', hosts: ['claude-code'], checked_against: CHECKED, writable_by_this_package: true },
107
+ ];
108
+
109
+ /** An environment map, in the shape `process.env` has. */
110
+ export type EnvMap = Readonly<Record<string, string | undefined>>;
111
+
112
+ /** Which host this process is running under, and whether that was observed. */
113
+ export interface TrafficHost {
114
+ host: string;
115
+ observed: boolean;
116
+ }
117
+
118
+ /**
119
+ * Resolve the host from the environment it exported.
120
+ *
121
+ * `observed` carries the same distinction `routing:doctor` draws for its own
122
+ * platform field: a host that identified itself is a fact, and the absence of
123
+ * any marker is NOT evidence of a different host — only evidence that nobody
124
+ * said. An unidentified host resolves to {@link UNKNOWN_HOST}, which documents
125
+ * no variable, so every row reads {@link NOT_APPLICABLE} rather than reporting
126
+ * against a host this code guessed at.
127
+ */
128
+ export function resolveTrafficHost(env: EnvMap): TrafficHost {
129
+ const claude =
130
+ (env['CLAUDECODE'] ?? '').trim() !== '' || (env['CLAUDE_CODE_SESSION_ID'] ?? '').trim() !== '';
131
+ if (claude) return { host: 'claude-code', observed: true };
132
+ return { host: UNKNOWN_HOST, observed: false };
133
+ }
134
+
135
+ /** One emitted row: the variable, its state on this host, and its value if set. */
136
+ export interface TrafficRow {
137
+ variable: string;
138
+ state: string;
139
+ value: string | null;
140
+ checked_against: string;
141
+ writable_by_this_package: boolean;
142
+ }
143
+
144
+ /**
145
+ * Build one row. A variable the host does not document reports
146
+ * {@link NOT_APPLICABLE} whether or not it happens to be exported.
147
+ */
148
+ function trafficRow(spec: TrafficVariable, env: EnvMap, host: string): TrafficRow {
149
+ const raw = env[spec.variable];
150
+ const present = raw !== undefined && raw !== '';
151
+ const applicable = spec.hosts.includes(host);
152
+ return {
153
+ variable: spec.variable,
154
+ state: applicable ? (present ? 'set' : 'unset') : NOT_APPLICABLE,
155
+ value: present ? String(raw) : null,
156
+ checked_against: spec.checked_against,
157
+ writable_by_this_package: spec.writable_by_this_package,
158
+ };
159
+ }
160
+
161
+ /**
162
+ * The `traffic_environment` block of `agent-config doctor --json`.
163
+ *
164
+ * Read-only by construction: the only input is the injected `env` map, and the
165
+ * only output is a fresh object. `hostOverride` is the test seam Phase 2.2's
166
+ * non-Claude fixture needs, and is never passed by the production call site.
167
+ *
168
+ * `reporting_read_only` replaced a flat `read_only: true` on 2026-09-30, and the
169
+ * rename is the point rather than cosmetics: this REPORT is still read-only, but
170
+ * the PACKAGE is no longer, so the old key had become a true statement about the
171
+ * wrong subject. Two of the four rows are now writable by the installer when the
172
+ * consumer sets a cap, and `writable_by_this_package` says which — a consumer
173
+ * reading `set` deserves to know whether we could have been the one who set it.
174
+ */
175
+ export function trafficEnvironmentJson(
176
+ env: EnvMap,
177
+ hostOverride?: TrafficHost,
178
+ ): Record<string, unknown> {
179
+ const resolved = hostOverride ?? resolveTrafficHost(env);
180
+ return {
181
+ host: resolved.host,
182
+ host_observed: resolved.observed,
183
+ doc: TRAFFIC_DOC,
184
+ reporting_read_only: true,
185
+ writable_by_this_package: TRAFFIC_VARIABLES.filter((v) => v.writable_by_this_package).map(
186
+ (v) => v.variable,
187
+ ),
188
+ rows: TRAFFIC_VARIABLES.map((spec) => trafficRow(spec, env, resolved.host)),
189
+ };
190
+ }
191
+
192
+ /** `fs.statSync` in a try — the `cmd_doctor.ts` helper this move preserves. */
193
+ function pathExists(p: string): boolean {
194
+ try {
195
+ fs.statSync(p);
196
+ return true;
197
+ } catch {
198
+ return false;
199
+ }
200
+ }
201
+
202
+ /**
203
+ * The `offline-readiness` check — a pure move out of `cmd_doctor.ts`.
204
+ *
205
+ * `packageRoot` is passed IN rather than resolved here for the reason
206
+ * `doctor_runtime_checks.ts` gives for its `which` parameter: `_package_root`
207
+ * lives in `cmd_doctor.ts` and importing it back would make the two modules
208
+ * circular.
209
+ */
210
+ export function checkOfflineReadiness(packageRoot: string): NetworkCheck {
211
+ const script = path.join(packageRoot, 'src', 'scripts', 'hermetic-install.sh');
212
+ if (!pathExists(script)) {
213
+ return {
214
+ id: 'offline-readiness',
215
+ status: 'warn',
216
+ message: 'src/scripts/hermetic-install.sh not found in package',
217
+ remedy: 'reinstall @event4u/agent-config or pull missing files',
218
+ };
219
+ }
220
+ return {
221
+ id: 'offline-readiness',
222
+ status: 'ok',
223
+ message: 'verified-offline install entrypoint present',
224
+ remedy: '',
225
+ };
226
+ }
@@ -0,0 +1,247 @@
1
+ /**
2
+ * The runtime activation payload — what a trigger match charges per fire.
3
+ *
4
+ * The third of the three numbers `road-to-the-delivery-flip-that-tells-the-truth`
5
+ * Phase 3 separates. The other two already have names and a record: ADR-270
6
+ * calls them `source_corpus` (what the source tree could deliver) and
7
+ * `host_payload` (what one host actually receives at rest), and requires them to
8
+ * be structurally separate fields because "until the two are named apart, every
9
+ * ceiling discussion risks comparing unlike quantities". After a per-host
10
+ * projection flip a third quantity diverges from both: the bytes a delivery
11
+ * concern injects when a rule's trigger fires. A standing reduction published
12
+ * without it is a saving published without its cost.
13
+ *
14
+ * MEASURED THROUGH THE CONCERN'S OWN SELECTION, never a second model of it.
15
+ * `matchTierRules` + `selectForInjection` are the functions the runtime concern
16
+ * calls; an offline figure computed by a different matcher would price a set the
17
+ * concern does not deliver. That is the same single-definition rule
18
+ * `_lib/rule_injection.ts` was written for, applied one layer out.
19
+ *
20
+ * THE CAP IS A PARAMETER, not an import. The value lives on the concern
21
+ * (`hooks/rule_inject_hook.ts::CAP_BYTES`) and every caller passes it, so this
22
+ * module stays free of the hook's import closure and can be read from a gate, a
23
+ * report, or a bundled path without dragging a hook into it.
24
+ *
25
+ * Moved here from `report_standing_payload_by_host.ts`, which had the only
26
+ * implementation and is still its largest caller — same move, and for the same
27
+ * reason, as `censusRuleDir` into `_lib/carrier_divergence.ts`: a second reader
28
+ * needed it and a second copy is how two numbers start disagreeing.
29
+ */
30
+ import * as fs from 'node:fs';
31
+ import * as path from 'node:path';
32
+
33
+ import { loadRouter, matchTierRules, selectForInjection } from './rule_injection.js';
34
+
35
+ /** The frozen corpus every fire figure in this module is sampled from. */
36
+ export const ROUTING_MATRIX_REL = path.join('tests', 'eval', 'routing-matrix');
37
+
38
+ /** One positive prompt of the frozen corpus, with the open files it declares. */
39
+ export interface CorpusPrompt {
40
+ prompt: string;
41
+ openFiles: string[] | null;
42
+ }
43
+
44
+ /**
45
+ * Every YAML shape inside `positives:` this hand parser cannot read.
46
+ *
47
+ * `readCorpusPositives` accepts only `- prompt: "…"` with a double-quoted
48
+ * same-line scalar and an inline `open_files: [...]`. Any other legal shape —
49
+ * single quotes, an unquoted scalar, a folded block, a block sequence for
50
+ * `open_files` — is SILENTLY SKIPPED, which drops fires out of the distribution
51
+ * a budget row is derived from. A measurement that governs a budget must fail
52
+ * loudly on a shape it cannot read rather than under-count, so callers refuse on
53
+ * a non-empty result here.
54
+ *
55
+ * Reported as a shape problem rather than fixed by widening the parser: this
56
+ * module must not grow a second YAML implementation, and the corpus is frozen,
57
+ * so the honest answer to an unreadable shape is to say which file carries it.
58
+ */
59
+ export function corpusShapeProblems(root: string): string[] {
60
+ const dir = path.join(root, ROUTING_MATRIX_REL);
61
+ const problems: string[] = [];
62
+ if (!fs.existsSync(dir)) return problems;
63
+ for (const f of fs.readdirSync(dir).filter((n) => n.endsWith('.yaml')).sort()) {
64
+ let inPositives = false;
65
+ let lineNo = 0;
66
+ for (const raw of fs.readFileSync(path.join(dir, f), 'utf-8').split('\n')) {
67
+ lineNo += 1;
68
+ if (/^positives:/u.test(raw)) { inPositives = true; continue; }
69
+ if (/^near_misses:/u.test(raw)) { inPositives = false; continue; }
70
+ if (!inPositives) continue;
71
+ if (/^\s*-\s*prompt:/u.test(raw) && !/^\s*-\s*prompt:\s*"(.*)"\s*$/u.test(raw)) {
72
+ problems.push(
73
+ `${f}:${String(lineNo)}: a \`- prompt:\` this parser cannot read — only a ` +
74
+ `double-quoted same-line scalar is accepted: ${JSON.stringify(raw.trim())}`,
75
+ );
76
+ continue;
77
+ }
78
+ if (/^\s*-\s*/u.test(raw) && !/^\s*-\s*(prompt|command|open_files):/u.test(raw)
79
+ && raw.trim() !== '-' && raw.trim() !== '') {
80
+ // A bare sequence item under `positives:` is a shape with no
81
+ // `prompt:` key on its first line — folded or nested.
82
+ if (!/^\s{4,}/u.test(raw)) {
83
+ problems.push(
84
+ `${f}:${String(lineNo)}: a positives entry whose first line carries no ` +
85
+ `\`prompt:\` key: ${JSON.stringify(raw.trim())}`,
86
+ );
87
+ }
88
+ }
89
+ if (/^\s*open_files:\s*$/u.test(raw)) {
90
+ problems.push(
91
+ `${f}:${String(lineNo)}: a BLOCK-sequence \`open_files:\` — only the inline ` +
92
+ '`[...]` form is read, so this entry\'s files would be dropped',
93
+ );
94
+ }
95
+ }
96
+ }
97
+ return problems;
98
+ }
99
+
100
+ /** Every positive prompt in the frozen routing-matrix corpus. Near-misses are not fires. */
101
+ export function readCorpusPositives(root: string): CorpusPrompt[] {
102
+ const dir = path.join(root, ROUTING_MATRIX_REL);
103
+ const out: CorpusPrompt[] = [];
104
+ if (!fs.existsSync(dir)) return out;
105
+ for (const f of fs.readdirSync(dir).filter((n) => n.endsWith('.yaml')).sort()) {
106
+ let inPositives = false;
107
+ let cur: CorpusPrompt | null = null;
108
+ for (const raw of fs.readFileSync(path.join(dir, f), 'utf-8').split('\n')) {
109
+ if (/^positives:/u.test(raw)) { inPositives = true; continue; }
110
+ if (/^near_misses:/u.test(raw)) { inPositives = false; continue; }
111
+ if (!inPositives) continue;
112
+ const p = /^\s*-\s*prompt:\s*"(.*)"\s*$/u.exec(raw);
113
+ if (p !== null) {
114
+ cur = { prompt: p[1] as string, openFiles: null };
115
+ out.push(cur);
116
+ continue;
117
+ }
118
+ const of = /^\s*open_files:\s*\[(.*)\]\s*$/u.exec(raw);
119
+ if (of !== null && cur !== null) {
120
+ cur.openFiles = (of[1] as string)
121
+ .split(',')
122
+ .map((x) => x.trim().replace(/^["']|["']$/gu, ''))
123
+ .filter((x) => x !== '');
124
+ }
125
+ }
126
+ }
127
+ return out;
128
+ }
129
+
130
+ /** Nearest-rank percentile over an unsorted sample. Empty sample → 0. */
131
+ export function percentile(xs: readonly number[], q: number): number {
132
+ if (xs.length === 0) return 0;
133
+ const s = [...xs].sort((a, b) => a - b);
134
+ return s[Math.min(s.length - 1, Math.floor(q * (s.length - 1)))] as number;
135
+ }
136
+
137
+ export interface SlotFireSizes {
138
+ readonly slot: string;
139
+ readonly fires: number;
140
+ readonly p50: number;
141
+ readonly p90: number;
142
+ readonly max: number;
143
+ }
144
+
145
+ /**
146
+ * Gate-open per-fire emission sizes for the delivery concern, per slot.
147
+ *
148
+ * `pre_compact` is 0 by construction rather than by measurement: that branch of
149
+ * `rule_inject_hook` clears the seen-set and returns allow without writing to
150
+ * stdout, so there is no emission to sample.
151
+ */
152
+ export function slotFireSizes(root: string, capBytes: number): SlotFireSizes[] {
153
+ const router = loadRouter(root);
154
+ const prompts = readCorpusPositives(root);
155
+ const sample = (mode: 'prompt' | 'file'): number[] => {
156
+ const out: number[] = [];
157
+ for (const r of prompts) {
158
+ if (mode === 'file' && (r.openFiles === null || r.openFiles.length === 0)) continue;
159
+ const matches =
160
+ mode === 'prompt'
161
+ ? matchTierRules(router, r.prompt, null, null)
162
+ : matchTierRules(router, '', r.openFiles, null);
163
+ if (matches.length === 0) continue;
164
+ const sel = selectForInjection(root, matches, capBytes);
165
+ if (sel.selected.length > 0) out.push(sel.bytes);
166
+ }
167
+ return out;
168
+ };
169
+ const row = (slot: string, xs: number[]): SlotFireSizes => ({
170
+ slot,
171
+ fires: xs.length,
172
+ p50: percentile(xs, 0.5),
173
+ p90: percentile(xs, 0.9),
174
+ max: xs.length === 0 ? 0 : Math.max(...xs),
175
+ });
176
+ return [
177
+ row('user_prompt_submit', sample('prompt')),
178
+ row('pre_tool_use', sample('file')),
179
+ row('pre_compact', []),
180
+ ];
181
+ }
182
+
183
+ /** The third labelled number, or the reason it could not be taken on this tree. */
184
+ export interface ActivationPayload {
185
+ /** Always the literal `activation-payload` — the label a reader and a caller key on. */
186
+ readonly scope: 'activation-payload';
187
+ /** `false` when the corpus or the router is absent; every figure is then 0. */
188
+ readonly measured: boolean;
189
+ /** Why it is unmeasured, or `null`. Never an estimate in place of a number. */
190
+ readonly unmeasured_reason: string | null;
191
+ /** The cap the sampled selection was taken at — the concern's `CAP_BYTES`. */
192
+ readonly cap_bytes: number;
193
+ readonly corpus: string;
194
+ readonly slots: readonly SlotFireSizes[];
195
+ readonly basis: string;
196
+ }
197
+
198
+ /**
199
+ * The runtime activation payload, or an honestly unmeasured reading.
200
+ *
201
+ * Never throws and never estimates: a missing corpus or router yields
202
+ * `measured: false` with the reason named, because a fabricated distribution
203
+ * published beside a standing saving is the exact defect this number exists to
204
+ * prevent.
205
+ */
206
+ export function measureActivationPayload(root: string, capBytes: number): ActivationPayload {
207
+ const basis =
208
+ 'Gate-open per-fire emission of the `rule-inject` concern over the frozen ' +
209
+ '`tests/eval/routing-matrix` positives, measured through the same ' +
210
+ '`matchTierRules` + `selectForInjection` the runtime concern calls, at the ' +
211
+ 'concern\'s own CAP_BYTES. Bytes per fire, never tokens — the unit ' +
212
+ '`hook-token-budget.json` enforces.';
213
+ const empty = (reason: string): ActivationPayload => ({
214
+ scope: 'activation-payload',
215
+ measured: false,
216
+ unmeasured_reason: reason,
217
+ cap_bytes: capBytes,
218
+ corpus: ROUTING_MATRIX_REL,
219
+ slots: [],
220
+ basis,
221
+ });
222
+ if (!fs.existsSync(path.join(root, ROUTING_MATRIX_REL))) {
223
+ return empty(`the frozen corpus ${ROUTING_MATRIX_REL} is absent under ${root}`);
224
+ }
225
+ const shape = corpusShapeProblems(root);
226
+ if (shape.length > 0) {
227
+ return empty(
228
+ `${String(shape.length)} corpus entry/entries are in a shape the reader cannot parse, ` +
229
+ `so the distribution would be under-counted — first: ${shape[0] as string}`,
230
+ );
231
+ }
232
+ let slots: SlotFireSizes[];
233
+ try {
234
+ slots = slotFireSizes(root, capBytes);
235
+ } catch (err) {
236
+ return empty(`the fire sample could not be taken: ${(err as Error).message}`);
237
+ }
238
+ return {
239
+ scope: 'activation-payload',
240
+ measured: true,
241
+ unmeasured_reason: null,
242
+ cap_bytes: capBytes,
243
+ corpus: ROUTING_MATRIX_REL,
244
+ slots,
245
+ basis,
246
+ };
247
+ }
@@ -53,6 +53,7 @@ import { fileURLToPath } from 'node:url';
53
53
 
54
54
  import * as user_global_paths from './user_global_paths.js';
55
55
  import { carveOutKeys } from '../../shared/settingsCarveOut.js';
56
+ import { applyRenamedKeys } from './settings_renamed_keys.js';
56
57
  import type * as YamlModule from 'yaml';
57
58
 
58
59
  // ESM has no `require`; `createRequire(import.meta.url)` restores it so the
@@ -956,9 +957,9 @@ export function load_agent_settings(
956
957
  // precedence here is the inverse of the server family's, so the order of
957
958
  // these three statements is the whole contract.
958
959
  const merged: SettingsDict = template_defaults(template_path ?? undefined);
959
- _deep_merge(merged, user_global_filtered);
960
+ _deep_merge(merged, applyRenamedKeys(user_global_filtered));
960
961
  for (const p of cascade) {
961
- const layer = _read_yaml(p) ?? {};
962
+ const layer = applyRenamedKeys(_read_yaml(p) ?? {});
962
963
  if (Object.keys(layer).length > 0) {
963
964
  _deep_merge(merged, layer);
964
965
  }
@@ -967,6 +968,7 @@ export function load_agent_settings(
967
968
  return merged;
968
969
  }
969
970
 
971
+
970
972
  /**
971
973
  * Settings keys this package has DELETED. A leftover value from an older
972
974
  * install is ignored — never applied by any reader — and surfaced with ONE