@event4u/agent-config 14.12.0 → 14.14.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 (521) 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 +118 -155
  5. package/CONTRIBUTING.md +38 -0
  6. package/CREDITS.md +135 -0
  7. package/NOTICE +13 -0
  8. package/README.md +8 -6
  9. package/dist/agent-src/commands/analyze/inbox.md +145 -2
  10. package/dist/agent-src/commands/feature/dev.md +7 -2
  11. package/dist/agent-src/commands/ghostwriter/write.md +5 -1
  12. package/dist/agent-src/commands/implement-ticket.md +1 -1
  13. package/dist/agent-src/commands/mission/upgrade.md +1 -1
  14. package/dist/agent-src/commands/orchestrate.md +2 -2
  15. package/dist/agent-src/commands/post-as/me.md +5 -1
  16. package/dist/agent-src/commands/pr/merge.md +19 -6
  17. package/dist/agent-src/commands/roadmap/process-full.md +19 -5
  18. package/dist/agent-src/commands/tdd/red.md +12 -2
  19. package/dist/agent-src/commands/work.md +1 -1
  20. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +40 -0
  21. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -2
  22. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +21 -0
  23. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -0
  24. package/dist/agent-src/contexts/execution/subagent-response-contract.md +40 -0
  25. package/dist/agent-src/contexts/execution/subagent-steering.md +13 -1
  26. package/dist/agent-src/contexts/execution/terminal-states.md +96 -0
  27. package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
  28. package/dist/agent-src/rules/broken-access-control.md +4 -0
  29. package/dist/agent-src/rules/code-comment-discipline.md +6 -0
  30. package/dist/agent-src/rules/code-provenance.md +4 -0
  31. package/dist/agent-src/rules/design-fidelity.md +1 -1
  32. package/dist/agent-src/rules/domain-safety-pii.md +4 -0
  33. package/dist/agent-src/rules/domain-safety-retention.md +4 -0
  34. package/dist/agent-src/rules/engineering-safety-floor.md +2 -0
  35. package/dist/agent-src/rules/external-code-graph-interop.md +14 -12
  36. package/dist/agent-src/rules/improve-before-implement.md +6 -8
  37. package/dist/agent-src/rules/laravel-routing.md +1 -1
  38. package/dist/agent-src/rules/lethal-trifecta-guard.md +4 -0
  39. package/dist/agent-src/rules/secret-vcs-guard.md +2 -0
  40. package/dist/agent-src/rules/security-sensitive-stop.md +2 -0
  41. package/dist/agent-src/rules/source-confidentiality.md +12 -34
  42. package/dist/agent-src/rules/symfony-routing.md +1 -1
  43. package/dist/agent-src/rules/token-efficiency.md +14 -0
  44. package/dist/agent-src/rules/tool-safety.md +4 -0
  45. package/dist/agent-src/rules/untrusted-input-defense.md +4 -0
  46. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +252 -8
  47. package/dist/agent-src/scripts/guarded_baseline.ts +343 -0
  48. package/dist/agent-src/scripts/roadmap_set_step.ts +253 -0
  49. package/dist/agent-src/scripts/stub_queue.ts +82 -0
  50. package/dist/agent-src/scripts/stubs_due.ts +516 -0
  51. package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
  52. package/dist/agent-src/scripts/update_roadmap_progress.ts +16 -12
  53. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +17 -4
  54. package/dist/agent-src/skills/brand-audit/SKILL.md +33 -0
  55. package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -0
  56. package/dist/agent-src/skills/database/SKILL.md +8 -0
  57. package/dist/agent-src/skills/dependency-upgrade/SKILL.md +27 -0
  58. package/dist/agent-src/skills/design-review/SKILL.md +1 -1
  59. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
  60. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +17 -1
  61. package/dist/agent-src/skills/feature-planning/SKILL.md +9 -2
  62. package/dist/agent-src/skills/frontend-render-security/SKILL.md +44 -0
  63. package/dist/agent-src/skills/git-workflow/SKILL.md +1 -1
  64. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +38 -4
  65. package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +2 -2
  66. package/dist/agent-src/skills/laravel/SKILL.md +35 -0
  67. package/dist/agent-src/skills/laravel-migration/SKILL.md +57 -3
  68. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +26 -0
  69. package/dist/agent-src/skills/playbook-authoring/SKILL.md +28 -1
  70. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  71. package/dist/agent-src/skills/skill-writing/references/procedure.md +5 -5
  72. package/dist/agent-src/skills/sql-writing/SKILL.md +7 -1
  73. package/dist/agent-src/skills/standards-from-config/SKILL.md +27 -4
  74. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +11 -4
  75. package/dist/agent-src/skills/symfony-workflow/SKILL.md +35 -0
  76. package/dist/agent-src/skills/test-case-discovery/SKILL.md +85 -0
  77. package/dist/agent-src/skills/test-driven-development/SKILL.md +33 -9
  78. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
  79. package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +37 -0
  80. package/dist/agent-src/skills/ui-component-architect/SKILL.md +45 -2
  81. package/dist/agent-src/skills/upstream-contribute/SKILL.md +38 -1
  82. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +9 -4
  83. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  84. package/dist/agent-src/templates/roadmaps.md +97 -3
  85. package/dist/agent-src/templates/scripts/check_memory.ts +258 -17
  86. package/dist/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  87. package/dist/agent-src/templates/scripts/memory_lookup.ts +86 -0
  88. package/dist/agent-src/templates/scripts/memory_signal.ts +44 -0
  89. package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  90. package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  91. package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  92. package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  93. package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  94. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  95. package/dist/cli/commands/uiAudit.js +124 -5
  96. package/dist/cli/registry.js +2 -0
  97. package/dist/cli-delegate/{chunk-HYWSRNUX.js → chunk-2DK2VJWG.js} +3 -3
  98. package/dist/cli-delegate/{chunk-JCW7ZLHK.js → chunk-4FS4WRXP.js} +5 -0
  99. package/dist/cli-delegate/{chunk-OMIVVCG2.js → chunk-A4QJ6ENT.js} +24 -0
  100. package/dist/cli-delegate/{chunk-JJA2QEWA.js → chunk-AKJGUQNO.js} +466 -285
  101. package/dist/cli-delegate/{chunk-E46KPN6K.js → chunk-BTWUYDGN.js} +424 -363
  102. package/dist/cli-delegate/{chunk-K4FFODTS.js → chunk-ILMUPLGW.js} +1227 -316
  103. package/dist/cli-delegate/{chunk-FF7WAFMR.js → chunk-KPBWFOPZ.js} +5 -1
  104. package/dist/cli-delegate/cmd_adr_effective.js +102 -0
  105. package/dist/cli-delegate/cmd_conformance.js +80 -11
  106. package/dist/cli-delegate/cmd_doctor.js +3 -3
  107. package/dist/cli-delegate/cmd_export.js +3 -2
  108. package/dist/cli-delegate/cmd_fleet.js +2 -2
  109. package/dist/cli-delegate/cmd_handoff.js +1 -1
  110. package/dist/cli-delegate/cmd_preflight.js +2 -2
  111. package/dist/cli-delegate/cmd_prune.js +3 -2
  112. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  113. package/dist/cli-delegate/cmd_settings_migrate.js +3 -2
  114. package/dist/cli-delegate/cmd_settings_set.js +2 -2
  115. package/dist/cli-delegate/cmd_sync.js +3 -2
  116. package/dist/cli-delegate/cmd_uninstall.js +3 -2
  117. package/dist/cli-delegate/cmd_validate.js +3 -2
  118. package/dist/discovery/deprecation-report.md +1 -1
  119. package/dist/discovery/discovery-manifest.json +58 -58
  120. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  121. package/dist/discovery/discovery-manifest.summary.md +1 -1
  122. package/dist/discovery/dormancy-report.md +1 -1
  123. package/dist/discovery/orphan-report.md +1 -1
  124. package/dist/discovery/packs.json +2 -2
  125. package/dist/discovery/trust-report.md +1 -1
  126. package/dist/discovery/workspaces.json +2 -2
  127. package/dist/hooks/dispatch.js +2900 -1049
  128. package/dist/install/claudeRuleRewrite.js +254 -0
  129. package/dist/install/detect.js +29 -16
  130. package/dist/install/detect_php_shape.js +159 -0
  131. package/dist/install/install.mjs +634 -428
  132. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  133. package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
  134. package/dist/mcp/registry-manifest.json +3 -3
  135. package/dist/mcp/server.json +3 -3
  136. package/dist/mcp/server.mjs +4895 -2627
  137. package/dist/server/schemas/settings.js +3 -0
  138. package/dist/ui/assets/index-D0jaCRPM.js +29 -0
  139. package/dist/ui/index.html +1 -1
  140. package/docs/MIGRATION.md +1 -1
  141. package/docs/THIRD-PARTY-NOTICES.md +25 -0
  142. package/docs/contracts/provider-lifecycle.md +1 -1
  143. package/docs/contracts/settings-classes.md +10 -4
  144. package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
  145. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -0
  146. package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +58 -3
  147. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +2 -2
  148. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
  149. package/docs/guidelines/agent-infra/break-glass-usage.md +7 -7
  150. package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
  151. package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
  152. package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
  153. package/docs/guidelines/agent-infra/direct-answers-demos.md +2 -2
  154. package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +1 -1
  155. package/docs/guidelines/agent-infra/engineering-memory-data-format.md +3 -3
  156. package/docs/guidelines/agent-infra/existence-question-verdicts.md +80 -0
  157. package/docs/guidelines/agent-infra/first-principles.md +2 -2
  158. package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +2 -2
  159. package/docs/guidelines/agent-infra/guarded-baseline.md +39 -0
  160. package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
  161. package/docs/guidelines/agent-infra/language-and-tone-examples.md +1 -1
  162. package/docs/guidelines/agent-infra/layered-settings.md +10 -10
  163. package/docs/guidelines/agent-infra/memory-access.md +1 -1
  164. package/docs/guidelines/agent-infra/mental-models.md +3 -3
  165. package/docs/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
  166. package/docs/guidelines/agent-infra/review-routing-data-format.md +7 -7
  167. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +13 -7
  168. package/docs/guidelines/agent-infra/role-contracts.md +2 -2
  169. package/docs/guidelines/agent-infra/role-mode-router.md +3 -3
  170. package/docs/guidelines/agent-infra/rule-type-governance.md +2 -2
  171. package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
  172. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +6 -6
  173. package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +2 -2
  174. package/docs/guidelines/agent-infra/six-hats.md +3 -3
  175. package/docs/guidelines/agent-infra/skill-quality-checklist.md +6 -6
  176. package/docs/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
  177. package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
  178. package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
  179. package/docs/guidelines/augment-portability-patterns.md +6 -4
  180. package/docs/guidelines/code-clarity.md +18 -0
  181. package/docs/guidelines/component-oriented-and-oop-development.md +3 -2
  182. package/docs/guidelines/cross-role-handoff.md +2 -2
  183. package/docs/guidelines/design-fidelity-mechanics.md +1 -1
  184. package/docs/guidelines/docs/readme-size-and-splitting.md +3 -3
  185. package/docs/guidelines/php/database.md +90 -7
  186. package/docs/guidelines/prompt-templates.md +7 -7
  187. package/llms.txt +2 -2
  188. package/package.json +5 -2
  189. package/src/agent-src/scripts/archive_completed_roadmaps.ts +252 -8
  190. package/src/agent-src/scripts/guarded_baseline.ts +343 -0
  191. package/src/agent-src/scripts/roadmap_set_step.ts +253 -0
  192. package/src/agent-src/scripts/stub_queue.ts +82 -0
  193. package/src/agent-src/scripts/stubs_due.ts +516 -0
  194. package/src/agent-src/scripts/ticket_bundles.ts +84 -0
  195. package/src/agent-src/scripts/update_roadmap_progress.ts +16 -12
  196. package/src/agent-src/templates/scripts/check_memory.ts +258 -17
  197. package/src/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  198. package/src/agent-src/templates/scripts/memory_lookup.ts +86 -0
  199. package/src/agent-src/templates/scripts/memory_signal.ts +44 -0
  200. package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  201. package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  202. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  203. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  204. package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  205. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  206. package/src/config/agent-settings.template.yml +32 -3
  207. package/src/config/assurance-capability-registry.json +21 -9
  208. package/src/config/canonical-terms.yml +119 -0
  209. package/src/config/capability-native-outcome-bars.json +81 -0
  210. package/src/config/ci-local-parity.yml +80 -0
  211. package/src/config/drafting-channels.yml +43 -0
  212. package/src/config/estate-count-budget.json +57 -36
  213. package/src/config/evaluator-budgets.json +14 -14
  214. package/src/config/gate-coverage.yml +729 -63
  215. package/src/config/gate-reachability-exemptions.json +21 -0
  216. package/src/config/gate-violation-baselines.json +42 -19
  217. package/src/config/harness-evolution-budget.json +25 -0
  218. package/src/config/lapsed-beta-baseline.json +96 -0
  219. package/src/config/memory-twin-verdicts.yml +129 -0
  220. package/src/config/metric-registry.yml +124 -0
  221. package/src/config/pack-size-budget.json +16 -15
  222. package/src/config/preamble-payload-budget.json +12 -4
  223. package/src/config/profiles/balanced.ini +27 -0
  224. package/src/config/profiles/full.ini +27 -0
  225. package/src/config/profiles/minimal.ini +27 -0
  226. package/src/config/publish-surface.json +9 -2
  227. package/src/config/routing-coverage-seed.json +16 -2
  228. package/src/config/rule-stub-ceilings.json +133 -112
  229. package/src/config/turnaround-budget.json +66 -0
  230. package/src/install/claudeRuleRewrite.ts +288 -0
  231. package/src/install/detect.ts +60 -17
  232. package/src/install/detect_php_shape.ts +191 -0
  233. package/src/scripts/_cli/cmd_doctor.ts +27 -112
  234. package/src/scripts/_dispatch.bash +23 -0
  235. package/src/scripts/_lib/activation_ladder.ts +255 -0
  236. package/src/scripts/_lib/activation_receipt_producer.ts +341 -0
  237. package/src/scripts/_lib/activation_states.ts +88 -0
  238. package/src/scripts/_lib/adherence_detectors.ts +143 -0
  239. package/src/scripts/_lib/adr_frontmatter.ts +26 -0
  240. package/src/scripts/_lib/arith_claims.ts +181 -0
  241. package/src/scripts/_lib/arm_ranking.ts +62 -0
  242. package/src/scripts/_lib/asset_delivery_ledger.ts +303 -0
  243. package/src/scripts/_lib/audit_field_provenance.ts +54 -0
  244. package/src/scripts/_lib/auto_dispatch.ts +32 -3
  245. package/src/scripts/_lib/bench_ab_size_claim.ts +98 -4
  246. package/src/scripts/_lib/benchmark_cache_fields.ts +158 -0
  247. package/src/scripts/_lib/candidate_pair_delta.ts +349 -0
  248. package/src/scripts/_lib/candidate_proposer.ts +402 -0
  249. package/src/scripts/_lib/candidate_record.ts +601 -0
  250. package/src/scripts/_lib/capture_rate.ts +319 -0
  251. package/src/scripts/_lib/carrier_status.ts +118 -0
  252. package/src/scripts/_lib/cascade_stage_enumeration.ts +92 -0
  253. package/src/scripts/_lib/collector_denominator.ts +771 -0
  254. package/src/scripts/_lib/collector_record.ts +340 -0
  255. package/src/scripts/_lib/collector_store.ts +664 -0
  256. package/src/scripts/_lib/collector_supervision.ts +827 -0
  257. package/src/scripts/_lib/concern_estate.ts +77 -0
  258. package/src/scripts/_lib/config_chain.ts +477 -0
  259. package/src/scripts/_lib/config_cost.ts +209 -0
  260. package/src/scripts/_lib/corpus_manifest.ts +726 -0
  261. package/src/scripts/_lib/council_settings_block.ts +6 -0
  262. package/src/scripts/_lib/curator_ops.ts +172 -0
  263. package/src/scripts/_lib/delivery_arm_experiment.ts +282 -0
  264. package/src/scripts/_lib/delivery_criticality.ts +126 -0
  265. package/src/scripts/_lib/doctor_runtime_checks.ts +70 -0
  266. package/src/scripts/_lib/empty_cycles.ts +88 -0
  267. package/src/scripts/_lib/estate_carrier_cases.ts +72 -0
  268. package/src/scripts/_lib/eval_publication.ts +354 -0
  269. package/src/scripts/_lib/evaluation_cascade.ts +452 -0
  270. package/src/scripts/_lib/evaluation_vector.ts +283 -0
  271. package/src/scripts/_lib/evaluator_promotion.ts +225 -0
  272. package/src/scripts/_lib/evidence_basis.ts +118 -0
  273. package/src/scripts/_lib/evolution_roi.ts +562 -0
  274. package/src/scripts/_lib/exec_evidence.ts +8 -0
  275. package/src/scripts/_lib/experience_card.ts +272 -0
  276. package/src/scripts/_lib/experience_report.ts +151 -0
  277. package/src/scripts/_lib/experiment_freeze.ts +112 -0
  278. package/src/scripts/_lib/generated_by.ts +66 -0
  279. package/src/scripts/_lib/harness_evolution_guards.ts +239 -0
  280. package/src/scripts/_lib/hook_effect_probe.ts +141 -0
  281. package/src/scripts/_lib/host_denominator.ts +687 -0
  282. package/src/scripts/_lib/host_projection_reach.ts +157 -0
  283. package/src/scripts/_lib/ignored_blocker.ts +148 -0
  284. package/src/scripts/_lib/install_reach_checks.ts +495 -0
  285. package/src/scripts/_lib/json_duplicate_keys.ts +150 -0
  286. package/src/scripts/_lib/judge_hygiene.ts +228 -0
  287. package/src/scripts/_lib/legacy_boundary_map.ts +228 -0
  288. package/src/scripts/_lib/lexical_shortlist.ts +215 -0
  289. package/src/scripts/_lib/llm_candidate_proposer.ts +461 -0
  290. package/src/scripts/_lib/llm_proposer_transport.ts +153 -0
  291. package/src/scripts/_lib/loop_guards.ts +299 -0
  292. package/src/scripts/_lib/loss_class.ts +129 -0
  293. package/src/scripts/_lib/machine_wake.ts +51 -0
  294. package/src/scripts/_lib/md_prose_lines.ts +177 -0
  295. package/src/scripts/_lib/minimality_tiebreak.ts +168 -0
  296. package/src/scripts/_lib/one_resolver_invariant.ts +449 -0
  297. package/src/scripts/_lib/orchestration_record.ts +253 -5
  298. package/src/scripts/_lib/outcome_envelope.ts +227 -0
  299. package/src/scripts/_lib/outcome_vocabularies.ts +125 -0
  300. package/src/scripts/_lib/paired_stats.ts +245 -0
  301. package/src/scripts/_lib/paired_verdict.ts +226 -0
  302. package/src/scripts/_lib/pathology_archive.ts +393 -0
  303. package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
  304. package/src/scripts/_lib/privacy_class.ts +47 -0
  305. package/src/scripts/_lib/promotion_capability.ts +315 -0
  306. package/src/scripts/_lib/promotion_evidence.ts +414 -0
  307. package/src/scripts/_lib/promotion_review.ts +294 -0
  308. package/src/scripts/_lib/prompt_shape.ts +92 -0
  309. package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
  310. package/src/scripts/_lib/release_highlights.ts +70 -1
  311. package/src/scripts/_lib/release_material.ts +125 -2
  312. package/src/scripts/_lib/repeated_failure.ts +105 -0
  313. package/src/scripts/_lib/repo_root.ts +111 -0
  314. package/src/scripts/_lib/review_skipped_record.ts +37 -0
  315. package/src/scripts/_lib/role_split.ts +338 -0
  316. package/src/scripts/_lib/routing_corpus.ts +307 -0
  317. package/src/scripts/_lib/routing_index_input.ts +104 -0
  318. package/src/scripts/_lib/rule_injection.ts +22 -1
  319. package/src/scripts/_lib/runtime_journal.ts +1499 -0
  320. package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
  321. package/src/scripts/_lib/semantic_noop.ts +167 -0
  322. package/src/scripts/_lib/skill_catalogue.ts +11 -1
  323. package/src/scripts/_lib/source_digest.ts +200 -0
  324. package/src/scripts/_lib/source_redact.ts +260 -0
  325. package/src/scripts/_lib/source_shape.ts +502 -0
  326. package/src/scripts/_lib/source_snapshot_dedup.ts +199 -0
  327. package/src/scripts/_lib/strip_comments.d.mts +8 -0
  328. package/src/scripts/_lib/strip_comments.mjs +65 -0
  329. package/src/scripts/_lib/test_red_state.ts +154 -0
  330. package/src/scripts/_lib/trigger_shift.ts +144 -0
  331. package/src/scripts/_lib/untrusted_content.ts +82 -7
  332. package/src/scripts/activation_receipt.ts +258 -0
  333. package/src/scripts/adoption_report.ts +1 -1
  334. package/src/scripts/adr/evidence_census.ts +1 -1
  335. package/src/scripts/adr/regenerate_index.ts +26 -2
  336. package/src/scripts/adr_cite_check.ts +164 -1
  337. package/src/scripts/ai_council/blind_review.ts +11 -1
  338. package/src/scripts/ai_council/clients.ts +4 -0
  339. package/src/scripts/ai_council/config.ts +3 -0
  340. package/src/scripts/ai_council/consensus.ts +28 -8
  341. package/src/scripts/ai_council/consensus_round.ts +226 -0
  342. package/src/scripts/ai_council/cross_exam.ts +128 -0
  343. package/src/scripts/ai_council/disagreement_signal.ts +338 -0
  344. package/src/scripts/ai_council/explain_route.ts +157 -0
  345. package/src/scripts/ai_council/information_gain.ts +293 -0
  346. package/src/scripts/ai_council/inline_findings.ts +340 -0
  347. package/src/scripts/ai_council/judge_position_bias.ts +197 -0
  348. package/src/scripts/ai_council/leakage_corpus.ts +385 -0
  349. package/src/scripts/ai_council/leakage_patterns.ts +453 -0
  350. package/src/scripts/ai_council/minority_retention.ts +171 -0
  351. package/src/scripts/ai_council/orchestrator.ts +16 -203
  352. package/src/scripts/ai_council/orchestrator_results.ts +23 -3
  353. package/src/scripts/ai_council/pricing.ts +106 -0
  354. package/src/scripts/ai_council/prompts.ts +74 -7
  355. package/src/scripts/ai_council/provider_leakage_bench.ts +327 -0
  356. package/src/scripts/ai_council/py_format.ts +14 -3
  357. package/src/scripts/ai_council/recouncil_guard.ts +293 -0
  358. package/src/scripts/ai_council/recouncil_savings.ts +299 -0
  359. package/src/scripts/ai_council/replay_route.ts +223 -0
  360. package/src/scripts/ai_council/response_record.ts +50 -0
  361. package/src/scripts/ai_council/reviewer_assignment.ts +279 -0
  362. package/src/scripts/ai_council/routing_training_row.ts +197 -0
  363. package/src/scripts/ai_council/synthesis_strategy.ts +159 -0
  364. package/src/scripts/ai_council/topology_bench_manifest.ts +860 -0
  365. package/src/scripts/ai_council/topology_vocabulary.ts +175 -0
  366. package/src/scripts/asset_delivery_ledger.ts +157 -0
  367. package/src/scripts/attest_artifact.ts +193 -0
  368. package/src/scripts/audit_auto_rules.ts +2 -1
  369. package/src/scripts/audit_command_surface.ts +1 -1
  370. package/src/scripts/audit_mcp_tools.ts +2 -2
  371. package/src/scripts/audit_skill_overlap_allowlist.json +6 -1
  372. package/src/scripts/audit_user_type_axis.ts +2 -1
  373. package/src/scripts/bench_ab_clone.ts +215 -10
  374. package/src/scripts/bench_ab_integrity.ts +119 -5
  375. package/src/scripts/bench_ab_v2_stats.ts +40 -213
  376. package/src/scripts/build_archive_index.ts +1 -1
  377. package/src/scripts/build_linear_digest.ts +1 -1
  378. package/src/scripts/build_proof.ts +11 -4
  379. package/src/scripts/build_rule_trigger_matrix.ts +1 -1
  380. package/src/scripts/build_source_digests.ts +157 -0
  381. package/src/scripts/cache_realization_report.ts +103 -0
  382. package/src/scripts/check_adr_frontmatter.ts +131 -10
  383. package/src/scripts/check_benchmark_report_fields.ts +207 -0
  384. package/src/scripts/check_beta_review_markers.ts +235 -6
  385. package/src/scripts/check_bundle_path_leakage.ts +34 -1
  386. package/src/scripts/check_claims.ts +576 -6
  387. package/src/scripts/check_composite_arming.ts +35 -0
  388. package/src/scripts/check_concern_admissions.ts +365 -0
  389. package/src/scripts/check_enforcement_coverage.ts +28 -0
  390. package/src/scripts/check_estate_count.ts +347 -25
  391. package/src/scripts/check_gate_reachability.ts +383 -0
  392. package/src/scripts/check_host_loadability.ts +104 -0
  393. package/src/scripts/check_loss_class_declared.ts +308 -0
  394. package/src/scripts/check_md_language.ts +15 -98
  395. package/src/scripts/check_memory_proposal.ts +18 -11
  396. package/src/scripts/check_no_currency_in_cost_surfaces.ts +225 -0
  397. package/src/scripts/check_no_external_sources.ts +281 -6
  398. package/src/scripts/check_pack_conformance_fixture.ts +11 -1
  399. package/src/scripts/check_pack_size.ts +59 -2
  400. package/src/scripts/check_preamble_payload_budget.ts +114 -3
  401. package/src/scripts/check_prefix_stable_mutation.ts +372 -0
  402. package/src/scripts/check_publish_surface.ts +10 -1
  403. package/src/scripts/check_references.ts +24 -1
  404. package/src/scripts/check_release_highlights.ts +96 -13
  405. package/src/scripts/check_roadmap_trackable.ts +17 -2
  406. package/src/scripts/check_rule_evidence_declaration.ts +316 -0
  407. package/src/scripts/check_rule_projection_integrity.ts +14 -4
  408. package/src/scripts/check_score_contract.ts +26 -3
  409. package/src/scripts/check_static_parity.ts +285 -0
  410. package/src/scripts/check_supervision_claim_atomicity.ts +498 -0
  411. package/src/scripts/check_suppression_hygiene.ts +15 -0
  412. package/src/scripts/ci_settle.ts +39 -2
  413. package/src/scripts/code_graph/build.ts +60 -3
  414. package/src/scripts/code_graph/extract.ts +44 -0
  415. package/src/scripts/code_graph/types.ts +24 -0
  416. package/src/scripts/collector_daemon.ts +714 -0
  417. package/src/scripts/config_cost_report.ts +302 -0
  418. package/src/scripts/consumer_matrix.ts +74 -1
  419. package/src/scripts/corpus_manifest.ts +235 -0
  420. package/src/scripts/cost/budget.mjs +10 -3
  421. package/src/scripts/cost/track.mjs +10 -3
  422. package/src/scripts/council_cli.ts +37 -54
  423. package/src/scripts/dispatch_r2_reviewer.ts +46 -5
  424. package/src/scripts/evolution_lab.ts +1153 -0
  425. package/src/scripts/external_sources_denylist.json +5 -18
  426. package/src/scripts/extract_audit_patterns.ts +21 -0
  427. package/src/scripts/fold_intake.ts +12 -1
  428. package/src/scripts/gen_discovery_baseline.ts +1 -1
  429. package/src/scripts/generate_capabilities_index.ts +12 -5
  430. package/src/scripts/generate_capability_matrix.ts +3 -3
  431. package/src/scripts/generate_command_flows.ts +2 -2
  432. package/src/scripts/generate_cookbook.ts +2 -2
  433. package/src/scripts/generate_index.ts +8 -1
  434. package/src/scripts/generate_knowledge_index.ts +2 -1
  435. package/src/scripts/generate_ownership_matrix.ts +2 -1
  436. package/src/scripts/generate_pack_manifests.ts +10 -2
  437. package/src/scripts/generate_role_experiences_catalog.ts +2 -2
  438. package/src/scripts/generate_settings_reference.ts +1 -1
  439. package/src/scripts/git_authorization_hook.ts +22 -1
  440. package/src/scripts/grade_target_readiness.ts +48 -5
  441. package/src/scripts/hook_effect_doctor.ts +261 -0
  442. package/src/scripts/hook_manifest.json +1 -1
  443. package/src/scripts/hook_manifest.yaml +125 -16
  444. package/src/scripts/hooks/block_speaking_inbox_dir.ts +271 -0
  445. package/src/scripts/hooks/block_unauthorized_git.ts +18 -0
  446. package/src/scripts/hooks/comment_discipline_hook.ts +146 -0
  447. package/src/scripts/hooks/concern_registry.ts +6 -0
  448. package/src/scripts/hooks/dispatch_hook.ts +32 -0
  449. package/src/scripts/hooks/journal_record_hook.ts +345 -0
  450. package/src/scripts/hooks/prepush_metadata_sources.sh +110 -0
  451. package/src/scripts/hooks/run_continuation_hook.ts +44 -9
  452. package/src/scripts/hooks/shims/install.sh +61 -0
  453. package/src/scripts/hooks/shims/php +101 -0
  454. package/src/scripts/hooks/suggestion_capture_hook.ts +10 -0
  455. package/src/scripts/hooks/turn_end_gate_hook.ts +9 -1
  456. package/src/scripts/hot_context_hook.ts +16 -0
  457. package/src/scripts/install-hooks.sh +20 -5
  458. package/src/scripts/install.ts +17 -35
  459. package/src/scripts/inventory_frontmatter.ts +2 -1
  460. package/src/scripts/language_mirror_hook.ts +14 -2
  461. package/src/scripts/lint_adr_sweep_routing.ts +12 -0
  462. package/src/scripts/lint_canonical_terms.ts +604 -0
  463. package/src/scripts/lint_carrier_integrity.ts +820 -0
  464. package/src/scripts/lint_code_comments.ts +643 -0
  465. package/src/scripts/lint_composition_review.ts +619 -0
  466. package/src/scripts/lint_consolidation_lineage.ts +666 -0
  467. package/src/scripts/lint_eval_specs.ts +593 -0
  468. package/src/scripts/lint_hook_manifest.ts +19 -0
  469. package/src/scripts/lint_host_portability.ts +373 -0
  470. package/src/scripts/lint_judge_prompt_expectation.ts +27 -1
  471. package/src/scripts/lint_memory_twin_parity.ts +335 -0
  472. package/src/scripts/lint_metric_consumers.ts +355 -0
  473. package/src/scripts/lint_plan_risk_register.ts +39 -19
  474. package/src/scripts/lint_promotion_paths.ts +779 -0
  475. package/src/scripts/lint_skill_descriptions.ts +18 -1
  476. package/src/scripts/lint_skill_frontmatter_safety.ts +58 -0
  477. package/src/scripts/lint_skill_link_reach.ts +252 -0
  478. package/src/scripts/lint_skill_trigger_corpus.ts +426 -23
  479. package/src/scripts/lint_ticket_buildable.ts +17 -1
  480. package/src/scripts/llm_propose.ts +256 -0
  481. package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -1
  482. package/src/scripts/mcp_server/tool_catalog_source.ts +1 -1
  483. package/src/scripts/measure_delivery_sets.ts +361 -0
  484. package/src/scripts/measure_docs_dead_links.ts +348 -0
  485. package/src/scripts/measure_host_capture.ts +461 -0
  486. package/src/scripts/measure_routing_signal.ts +307 -0
  487. package/src/scripts/migration_status.ts +3 -3
  488. package/src/scripts/model_rule_injection.ts +76 -0
  489. package/src/scripts/orchestration_record.ts +14 -0
  490. package/src/scripts/preamble_byte_census.ts +139 -10
  491. package/src/scripts/prepack-check.mjs +4 -1
  492. package/src/scripts/probe_council_retention.ts +495 -0
  493. package/src/scripts/probe_turnaround.ts +384 -0
  494. package/src/scripts/probe_unblocked_ask.ts +279 -0
  495. package/src/scripts/release.ts +21 -37
  496. package/src/scripts/release_drill.ts +143 -0
  497. package/src/scripts/release_env.ts +35 -0
  498. package/src/scripts/release_publication.ts +84 -0
  499. package/src/scripts/render_benchmark_md.ts +1 -1
  500. package/src/scripts/rule_activation_census.ts +70 -9
  501. package/src/scripts/rule_backlinks.ts +1 -1
  502. package/src/scripts/run_lifecycle_suite.ts +208 -0
  503. package/src/scripts/run_skill_evals.ts +40 -0
  504. package/src/scripts/schemas/delivery-manifest.schema.json +43 -0
  505. package/src/scripts/schemas/drafting-channels.schema.json +43 -0
  506. package/src/scripts/schemas/evals.schema.json +24 -1
  507. package/src/scripts/schemas/rule.schema.json +52 -1
  508. package/src/scripts/schemas/skill.schema.json +17 -2
  509. package/src/scripts/skill_overlap.ts +7 -1
  510. package/src/scripts/skill_tools/run_block_d_eval.ts +8 -1
  511. package/src/scripts/skill_tools/score_skill_relevance.ts +84 -3
  512. package/src/scripts/skill_tools/suggest_skill_for_task.ts +8 -1
  513. package/src/scripts/skill_usage_report.ts +2 -1
  514. package/src/scripts/stubs_due.ts +211 -0
  515. package/src/scripts/sweep_source_surfaces.ts +678 -0
  516. package/src/scripts/sync_pr_branch.ts +3 -3
  517. package/src/scripts/trigger_eval_grandfather.json +202 -222
  518. package/src/scripts/utilization_report.ts +22 -2
  519. package/src/server/schemas/settings.ts +5 -0
  520. package/src/templates/marketing-copy.yml +1 -1
  521. package/dist/ui/assets/index-Cxgy63kz.js +0 -26
@@ -17,6 +17,16 @@
17
17
  */
18
18
 
19
19
  import type { LookupClass } from './auto_dispatch.js';
20
+ import type { EvidenceBasis } from './evidence_basis.js';
21
+ // TYPE-ONLY on purpose. `runtime_journal.ts` imports `node:sqlite` at runtime,
22
+ // and this module is loaded by a PreToolUse-adjacent CLI path where opening a
23
+ // database would be both wrong and slow. A `import type` is erased at compile
24
+ // time, so the guard costs nothing at runtime while still being one definition
25
+ // rather than a second copy of the key list -- the duplicate-enum failure step
26
+ // 9.1 exists to prevent.
27
+ import type { NoFreeForm } from './runtime_journal.js';
28
+ import { type PrivacyClass } from './privacy_class.js';
29
+ import type { PhaseOutcome } from './outcome_vocabularies.js';
20
30
 
21
31
  export type DispatchOutcome = 'DONE' | 'DONE_WITH_CONCERNS' | 'NEEDS_CONTEXT' | 'BLOCKED' | 'killed';
22
32
  /** Which route the rung took: deterministic primitive (lean-init L0),
@@ -24,12 +34,30 @@ export type DispatchOutcome = 'DONE' | 'DONE_WITH_CONCERNS' | 'NEEDS_CONTEXT' |
24
34
  * subagent spawn. */
25
35
  export type RouteTaken = 'primitive' | 'subagent' | 'ask';
26
36
  export type VerifyMode = 'deterministic' | 'judge' | 'none';
27
- export type Provenance = 'measured' | 'estimated';
37
+ /**
38
+ * Migrated onto the shared evidence-basis vocabulary
39
+ * (`road-to-delivered-cost-truth` 4.1). The two literals are unchanged on the
40
+ * wire — `measured` and `estimated` mean here exactly what the contract says
41
+ * they mean — but they are no longer declared privately, so this surface and
42
+ * the census can no longer drift apart on what "measured" is.
43
+ *
44
+ * Narrowed to the two values this field can actually take: an orchestration
45
+ * record's floor is either read from the transcript ledger or arithmetic over
46
+ * it, and admitting `model-judged` here would be widening a type to match a
47
+ * vocabulary rather than a fact.
48
+ */
49
+ export type Provenance = Extract<EvidenceBasis, 'measured' | 'estimated'>;
28
50
  export type TierChosen = 'lite' | 'medium' | 'high';
29
51
  export type TierSource = 'static' | 'inferred' | 'inherit';
30
52
  export type Band = 'low' | 'medium' | 'high';
31
53
  export type LinePhase = 'refine' | 'memory' | 'analyze' | 'plan' | 'implement' | 'test' | 'verify' | 'report';
32
- export type LineOutcome = 'success' | 'blocked' | 'skipped' | 'error';
54
+ /**
55
+ * Outcome of this audit-log line. Alias of the registry's `PhaseOutcome` —
56
+ * the name `LineOutcome` is kept because two modules import it, and the
57
+ * single definition now lives in `outcome_vocabularies.ts` so the contract
58
+ * table can be checked against it (`road-to-experience-loop-broadening` 1.3).
59
+ */
60
+ export type LineOutcome = PhaseOutcome;
33
61
  /** Which capsule-emission trigger arm fired first (Phase 1 shadow comparison). */
34
62
  export type TriggerArm = 'watermark' | 'saturation' | 'tie';
35
63
  /** The orchestration form the form-gate selected (road-to-opt-subagent-harvest P2). */
@@ -58,6 +86,45 @@ export interface RecordInput {
58
86
  task_class?: string | null | undefined;
59
87
  /** Form-gate outcome: which of the seven modes (or 'none') the gate selected. */
60
88
  dispatch_mode?: DispatchModeId | null | undefined;
89
+ /**
90
+ * Stable skill ids that were APPLIED during this phase — the skills
91
+ * counterpart of `rules_applied`, which `audit-log-v1` has carried since v1
92
+ * while carrying no skills field at all.
93
+ *
94
+ * ABSENT and EMPTY mean different things, and the distinction is
95
+ * load-bearing rather than stylistic: the field OMITTED means *not
96
+ * recorded* (the producer had no skill observation to offer), while `[]`
97
+ * means *recorded, and none applied*. Folding the two together is what
98
+ * makes a per-asset report unable to tell "no signal" from "a negative
99
+ * signal", which is the failure `unknown != 0` exists to prevent
100
+ * downstream.
101
+ *
102
+ * Ids only, never bodies — privacy by construction, same as
103
+ * `rules_applied`. Bounded to <= 32; the remainder is dropped, mirroring
104
+ * the rules bound in the contract.
105
+ */
106
+ skills_applied?: string[] | null | undefined;
107
+ /**
108
+ * What this dispatch was supposed to produce. Drives the anti-forgery gate
109
+ * in `envelopeOutcome`. Absent or `unknown` disables the gate for this
110
+ * line, which is the safe default: a producer that cannot say what it
111
+ * expected must not have its outcome downgraded on a guess.
112
+ */
113
+ expected_output?: ExpectedOutput | null | undefined;
114
+ /**
115
+ * Measured lines changed by this dispatch. `null` means NOT MEASURED and is
116
+ * never read as zero — an unmeasured diff must not become a failure.
117
+ */
118
+ diff_lines?: number | null | undefined;
119
+ /**
120
+ * Trigger fires suppressed as duplicates since the last outcome record.
121
+ *
122
+ * Reported as its own quantity, never folded into a success rate's
123
+ * numerator or denominator: a duplicate is not an outcome, and it is also
124
+ * not nothing — a rising count is what an idle loop looks like from
125
+ * outside. See `src/scripts/_lib/empty_cycles.ts`.
126
+ */
127
+ empty_cycles?: number | null | undefined;
61
128
  task_size_estimate?: number | undefined;
62
129
  wall_clock_ms?: number | undefined;
63
130
  /** Absolute measured tokens the dispatched slice consumed (feeds the modeled cost-%). */
@@ -178,12 +245,148 @@ const PAYLOAD_HASH_RE = /^[a-f0-9]{8,64}$/i;
178
245
  /** Id-shaped origin tag — enum-ish, never free-form prose. */
179
246
  const ORIGIN_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
180
247
 
248
+ /**
249
+ * Upper bound on an applied-id array, mirroring the `rules_applied` bound the
250
+ * contract has carried since v1 ("Bounded to <= 32; remainder dropped
251
+ * silently"). Stated as a named constant so the contract row and the code can
252
+ * be checked against one another instead of against a literal.
253
+ */
254
+ const MAX_APPLIED_IDS = 32;
255
+
256
+ /**
257
+ * What THIS producer's lines carry. `ids-only` and not `counts-only` because
258
+ * every line carries `rules_applied`, and some carry `skills_applied`.
259
+ */
260
+ const PRODUCER_PRIVACY_CLASS: PrivacyClass = 'ids-only';
261
+
262
+ type Assert<T extends true> = T;
263
+
264
+ /**
265
+ * PRIVACY BY CONSTRUCTION, enforced rather than asserted.
266
+ *
267
+ * Until 2026-08-30 the privacy floor on this module was a docstring, and
268
+ * `docs/contracts/audit-log-v1.md` said so in its own words: "No test enforces
269
+ * this floor". A docstring cannot stop the next author adding a `payload` or a
270
+ * `detail` field, and `audit-log-v1`'s forward-compat rule means readers would
271
+ * silently carry it.
272
+ *
273
+ * This assertion makes that a COMPILE error. If {@link RecordInput} ever grows
274
+ * a key from `FREE_FORM_KEYS` -- `prompt`, `body`, `file_path`, `stdout`,
275
+ * `reason`, `payload` and the rest of the set an author reaches for when they
276
+ * want to stash content -- `NoFreeForm` resolves to `never`, this becomes
277
+ * `Assert<false>`, and the build stops. The type cannot be widened back without
278
+ * deleting this line, which is a visible act in a diff.
279
+ */
280
+ type _RecordInputCarriesNoFreeFormField = Assert<
281
+ [NoFreeForm<RecordInput>] extends [never] ? false : true
282
+ >;
283
+
284
+ /**
285
+ * The NEGATIVE fixture, and it is the half that is easy to leave out.
286
+ *
287
+ * The assertion above proves the guard ACCEPTS the current type. On its own
288
+ * that is satisfied just as well by a guard that accepts everything -- a
289
+ * `NoFreeForm` that had been broken into `type NoFreeForm<T> = T` would keep it
290
+ * green forever. This fixture proves the guard REJECTS, which is the direction
291
+ * that actually protects anything.
292
+ *
293
+ * The `@ts-expect-error` is itself the assertion: the line below is required to
294
+ * be a type error. If the guard ever stops rejecting a free-form key, the error
295
+ * disappears, the directive becomes unused, and `tsc` fails on the unused
296
+ * directive. Either way the build stops -- so `npm run typecheck` checks both
297
+ * directions, not only the flattering one.
298
+ *
299
+ * NOTE for whoever runs this by hand: `tsc -p tsconfig.json` does NOT cover
300
+ * this file. That config includes only `src/cli`, `src/server`, `src/shared`
301
+ * and `src/install`; `src/scripts/**` is reached solely by
302
+ * `tsconfig.scripts.json`. Use `npm run typecheck`, which runs both. A bare
303
+ * `tsc -p tsconfig.json` over this module is a gate that scans nothing and
304
+ * exits green.
305
+ */
306
+ interface _RecordInputWithForbiddenField extends RecordInput {
307
+ prompt?: string | undefined;
308
+ }
309
+ type _Rejected = [NoFreeForm<_RecordInputWithForbiddenField>] extends [never] ? false : true;
310
+ // @ts-expect-error — a type carrying a free-form key must make this Assert<false>
311
+ type _ForbiddenFieldIsRejected = Assert<_Rejected>;
312
+
181
313
  /** Map a dispatch outcome to the audit-log envelope outcome enum. */
182
- function envelopeOutcome(d: DispatchOutcome): LineOutcome {
314
+ /**
315
+ * What a dispatch was supposed to produce. The gate below reads THIS, never the
316
+ * diff alone.
317
+ *
318
+ * The unconditional rule -- claimed success x empty diff => never `success` --
319
+ * is the form this step deliberately does NOT ship. Analysis, review and
320
+ * read-only research dispatches are a large share of this repository's subagent
321
+ * traffic and legitimately produce no diff; marking them all as failures would
322
+ * poison the very aggregation the gate exists to protect, in the opposite
323
+ * direction. Zero diff may be valid, so "zero diff = failure" must not be
324
+ * global.
325
+ */
326
+ export const EXPECTED_OUTPUTS = ['code-change', 'analysis', 'review', 'unknown'] as const;
327
+ export type ExpectedOutput = (typeof EXPECTED_OUTPUTS)[number];
328
+
329
+ /**
330
+ * Version of the DispatchOutcome -> phase-outcome mapping that produced a line.
331
+ *
332
+ * Required by the AI council (2026-08-30, anthropic + openai, 2/2) as the
333
+ * condition on proceeding at all, and it addresses an asymmetry worth stating:
334
+ * a bad enforcement gate rolls back, a bad LABELLING change poisons historical
335
+ * analysis permanently, because audit-log-v1 lines are append-only and cannot
336
+ * be rewritten. A reader aggregating across the cutover must be able to see
337
+ * which semantics produced each line rather than infer it from a date.
338
+ *
339
+ * `1` -- unconditional: DONE / DONE_WITH_CONCERNS always mapped to `success`.
340
+ * Every line written before 2026-08-30 carries these semantics and
341
+ * carries NO `outcome_semantics` field, so an absent field reads as 1.
342
+ * `2` -- contract-gated: a `code-change` dispatch claiming success with a
343
+ * measured empty diff no longer maps to `success`.
344
+ */
345
+ export const OUTCOME_SEMANTICS_VERSION = 2;
346
+
347
+ /**
348
+ * Translate a dispatch outcome into an audit-log phase outcome.
349
+ *
350
+ * This is the tree's ONLY cross-domain outcome mapping
351
+ * (`src/scripts/_lib/outcome_vocabularies.ts` CROSS_DOMAIN_MAPPINGS), so a
352
+ * change here reaches every downstream aggregation. It was audited before
353
+ * changing: `envelopeOutcome` has no caller outside this module, the only
354
+ * reader of `outcome` is `src/scripts/extract_audit_patterns.ts` -- read-only,
355
+ * stdout, whose sole non-zero exit is argument validation -- and that script is
356
+ * wired into no Taskfile, no gate-coverage entry and no workflow. The label
357
+ * therefore enters no automated control path, which is the condition the
358
+ * council set for this being a labelling change rather than an enforcement one.
359
+ *
360
+ * The anti-forgery clause fires only when ALL THREE hold: the dispatch declared
361
+ * itself a `code-change`, it claimed success, and the diff was MEASURED at
362
+ * zero. `diff_lines == null` means not measured, and an unmeasured diff must
363
+ * never become a failure -- that would manufacture the forgery in the other
364
+ * direction, which is the same defect wearing the opposite sign.
365
+ */
366
+ function envelopeOutcome(d: DispatchOutcome, ctx?: OutcomeContext): LineOutcome {
183
367
  if (d === 'BLOCKED') return 'blocked';
184
368
  if (d === 'NEEDS_CONTEXT') return 'skipped';
185
369
  if (d === 'killed') return 'error';
186
- return 'success'; // DONE / DONE_WITH_CONCERNS
370
+
371
+ const claimsSuccess = d === 'DONE' || d === 'DONE_WITH_CONCERNS';
372
+ if (
373
+ claimsSuccess &&
374
+ ctx?.expected_output === 'code-change' &&
375
+ typeof ctx.diff_lines === 'number' &&
376
+ ctx.diff_lines === 0
377
+ ) {
378
+ // A code dispatch that claims success and demonstrably changed nothing
379
+ // is an unverified self-report, not a result. `error` rather than
380
+ // `blocked`: nothing prevented it from running, and `blocked` is
381
+ // already the value for a dispatch that never got to try.
382
+ return 'error';
383
+ }
384
+ return 'success';
385
+ }
386
+
387
+ interface OutcomeContext {
388
+ expected_output?: ExpectedOutput | null | undefined;
389
+ diff_lines?: number | null | undefined;
187
390
  }
188
391
 
189
392
  function isInt(n: unknown): n is number {
@@ -288,7 +491,23 @@ export function buildOrchestrationLine(input: RecordInput): BuiltLine {
288
491
  if (input.origin != null && !ORIGIN_RE.test(input.origin)) {
289
492
  errors.push("origin must be an id-shaped tag like 'lean-init-2026' (lowercase alnum + hyphens)");
290
493
  }
494
+ if (input.expected_output != null && !EXPECTED_OUTPUTS.includes(input.expected_output)) {
495
+ errors.push(`expected_output must be one of ${EXPECTED_OUTPUTS.join(' | ')} (or omitted)`);
496
+ }
497
+ if (input.diff_lines != null && (!isInt(input.diff_lines) || input.diff_lines < 0)) {
498
+ errors.push('diff_lines must be a non-negative integer count, null for not-measured, or omitted');
499
+ }
500
+ if (input.skills_applied != null) {
501
+ if (!Array.isArray(input.skills_applied)) {
502
+ errors.push('skills_applied must be an array of skill ids, [] , or omitted');
503
+ } else if (!input.skills_applied.every((v) => typeof v === 'string' && ORIGIN_RE.test(v))) {
504
+ errors.push(
505
+ "skills_applied entries must be id-shaped skill names like 'code-review' (lowercase alnum + hyphens) — ids only, never bodies",
506
+ );
507
+ }
508
+ }
291
509
  for (const [key, v] of [
510
+ ['empty_cycles', input.empty_cycles],
292
511
  ['rules_carried', input.rules_carried],
293
512
  ['rules_used', input.rules_used],
294
513
  ['work_tokens', input.work_tokens],
@@ -336,6 +555,9 @@ export function buildOrchestrationLine(input: RecordInput): BuiltLine {
336
555
  const orchestration: Record<string, unknown> = {
337
556
  task_size_estimate: input.task_size_estimate ?? 0,
338
557
  spawn_count: input.spawn_count,
558
+ // Its OWN quantity, never folded into a rate. `null` = not tracked by
559
+ // this producer, which is not the same as zero duplicates observed.
560
+ empty_cycles: input.empty_cycles ?? null,
339
561
  tiers: input.tiers ?? [],
340
562
  token_delta: input.token_delta,
341
563
  token_delta_provenance: prov,
@@ -388,12 +610,38 @@ export function buildOrchestrationLine(input: RecordInput): BuiltLine {
388
610
  ts: input.ts,
389
611
  work_id: input.work_id ?? `orchestration-${input.ts}`,
390
612
  phase,
391
- outcome: input.outcome ?? envelopeOutcome(dOutcome),
613
+ outcome:
614
+ input.outcome ??
615
+ envelopeOutcome(dOutcome, {
616
+ expected_output: input.expected_output,
617
+ diff_lines: input.diff_lines,
618
+ }),
619
+ // The cutover marker. An ABSENT field means semantics 1 (unconditional),
620
+ // which is every line written before 2026-08-30 -- so a reader
621
+ // aggregating across the boundary can segment rather than infer from a
622
+ // date. Emitted unconditionally because this producer always applies
623
+ // the current mapping.
624
+ outcome_semantics: OUTCOME_SEMANTICS_VERSION,
392
625
  confidence_band: band,
393
626
  risk_class: risk,
394
627
  memory: { asks: 0, hits: 0 },
395
628
  verify: { claims: 0, first_try_passes: 0 },
396
629
  rules_applied: ['delegation-policy'],
630
+ // MANDATORY, never optional and never derived by the reader. This line
631
+ // carries `rules_applied` and may carry `skills_applied`, both of which
632
+ // are stable artefact ids, so the class it declares is `ids-only`
633
+ // rather than `counts-only`. A consumer deciding whether this stream is
634
+ // safe to aggregate or export reads this field instead of re-deriving
635
+ // the answer from the producer's source.
636
+ privacy_class: PRODUCER_PRIVACY_CLASS,
637
+ // Emitted ONLY when the producer offered one. An omitted key means "not
638
+ // recorded"; `[]` means "recorded, none applied". Writing `null` or `[]`
639
+ // unconditionally would erase that distinction for every existing
640
+ // producer that has no skill observation to give, which is the whole
641
+ // reason the field is optional rather than defaulted.
642
+ ...(input.skills_applied != null
643
+ ? { skills_applied: input.skills_applied.slice(0, MAX_APPLIED_IDS) }
644
+ : {}),
397
645
  persona: input.persona ?? null,
398
646
  input_kind: 'orchestration',
399
647
  type: 'phase',
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Machine-decidable outcomes: the terminal state, whether a retry can help, and
3
+ * whether a finding list is complete.
4
+ *
5
+ * `road-to-skill-ecosystem-runtime-enforcement` Phase 4, Steps 4-5. Two
6
+ * distinctions that an agent currently has to JUDGE from prose, and gets wrong
7
+ * in the same direction each time:
8
+ *
9
+ * 1. **Is this worth retrying?** A missing credential, a permission denial, a
10
+ * spend cap and an upstream 5xx are all "the command failed", and retrying
11
+ * any of them burns an iteration against a gap the loop cannot close. The
12
+ * rules already say so — `context-hygiene`'s hard-blocker classes — and
13
+ * nothing a script emits lets an agent decide it without reading English.
14
+ * 2. **Is this list complete?** A capped finding list reads as a complete one.
15
+ * A gate that reports "3 findings" after truncating at 3 has said something
16
+ * false, and the reader has no way to know.
17
+ *
18
+ * PER-CATEGORY caps rather than one global cap, because a single cap lets one
19
+ * high-volume check fill the budget and hide every other category behind it —
20
+ * which is the failure a cap is supposed to prevent, arriving through the cap.
21
+ */
22
+
23
+ import type { RunTerminalState } from './outcome_vocabularies.js';
24
+
25
+ /**
26
+ * The six terminal states. Contract: `contexts/execution/terminal-states.md`.
27
+ *
28
+ * Alias of the registry's `RunTerminalState`. This module stays the public
29
+ * surface — `runtime_journal.test.ts:212` pins the import path and `:215`
30
+ * asserts no second declaration — while the single definition moved to
31
+ * `outcome_vocabularies.ts` so the contract's table can be checked against it
32
+ * (`road-to-experience-loop-broadening` 1.3).
33
+ */
34
+ export type TerminalState = RunTerminalState;
35
+
36
+ /** States that are NOT success. An error or an exhausted budget never reports as one. */
37
+ export const NON_SUCCESS_STATES: ReadonlySet<TerminalState> = new Set([
38
+ 'blocked',
39
+ 'approval-required',
40
+ 'exhausted',
41
+ 'stagnated',
42
+ ]);
43
+
44
+ /**
45
+ * Why a failure is or is not worth retrying.
46
+ *
47
+ * `hard-blocker` is the load-bearing value: it says *stop now and surface*,
48
+ * not *try twice more first*. `context-hygiene` names the classes — missing
49
+ * credential, permission denied, quota or rate limit reached, upstream 5xx —
50
+ * and a first occurrence of any of them skips the retry budget entirely.
51
+ */
52
+ export type RetryClass = 'retryable' | 'hard-blocker' | 'not-applicable';
53
+
54
+ /**
55
+ * What the orchestrator did with a return — the acknowledgment half of the
56
+ * channel (`road-to-runtime-event-journal` Phase 3.1).
57
+ *
58
+ * The envelope already refuses to report a failure as a success. What it could
59
+ * not record is whether the *reader* did anything with that failure: a
60
+ * `blocked` return the orchestrator dropped on the floor is byte-identical to
61
+ * one it read, weighed, and deliberately set aside. Both are "a blocked return
62
+ * exists"; only one of them is a defect, and no field distinguished them.
63
+ *
64
+ * Three values, and the absent case is the fourth and the load-bearing one:
65
+ * ABSENT means nobody recorded a decision, which is exactly the ignored
66
+ * blocker `_lib/ignored_blocker.ts` reports.
67
+ */
68
+ export type ConsumptionState = 'consumed' | 'partially-consumed' | 'rejected-with-reason';
69
+
70
+ /**
71
+ * The acknowledgment record. A discriminated union, so the reason that
72
+ * `rejected-with-reason` needs is enforced by the TYPE rather than by a
73
+ * runtime check the caller meets or does not: `{ consumption:
74
+ * 'rejected-with-reason' }` with no `reason` does not compile.
75
+ *
76
+ * The other two states may carry a reason and are not required to — a
77
+ * consumed return needs no justification, and demanding one would make the
78
+ * cheap path expensive, which is how a field stops being filled at all
79
+ * (Risk 5).
80
+ */
81
+ export type Acknowledgment =
82
+ | { readonly consumption: 'consumed'; readonly reason?: string }
83
+ | { readonly consumption: 'partially-consumed'; readonly reason?: string }
84
+ | { readonly consumption: 'rejected-with-reason'; readonly reason: string };
85
+
86
+ export interface OutcomeEnvelope<T = unknown> {
87
+ state: TerminalState;
88
+ /** Whether a retry can plausibly change the outcome. */
89
+ retry: RetryClass;
90
+ /**
91
+ * What to do next, in the imperative, naming the thing to change. Required
92
+ * on every non-success state: a state without a next action is a report the
93
+ * reader must translate.
94
+ */
95
+ suggestion: string;
96
+ /** True when the payload was capped. A capped list without this reads as complete. */
97
+ truncated: boolean;
98
+ /** Per-category counts BEFORE capping, so a reader sees what was dropped. */
99
+ totals: Record<string, number>;
100
+ payload: T;
101
+ /**
102
+ * What the orchestrator did with this return, when it recorded anything.
103
+ *
104
+ * OPTIONAL on purpose, and the optionality is the measurement surface: an
105
+ * absent acknowledgment on a non-success state is a detectable ignored
106
+ * blocker, not a defaulted-to-fine one. Never default it to `consumed` —
107
+ * that would make every unread return look read, which is the exact
108
+ * failure the field exists to expose.
109
+ */
110
+ acknowledgment?: Acknowledgment;
111
+ }
112
+
113
+ /** Raised when an envelope is constructed in a state its own contract forbids. */
114
+ export class EnvelopeContractError extends Error {}
115
+
116
+ /**
117
+ * Build an envelope, refusing the two shapes that make one useless.
118
+ *
119
+ * A non-success state with no `suggestion` is refused, and so is `truncated`
120
+ * with empty `totals`: both are the "capped list reads as complete" failure in
121
+ * different clothes — one hides the next action, the other hides the drop.
122
+ */
123
+ export function envelope<T>(init: {
124
+ state: TerminalState;
125
+ retry?: RetryClass;
126
+ suggestion?: string;
127
+ truncated?: boolean;
128
+ totals?: Record<string, number>;
129
+ payload: T;
130
+ /**
131
+ * Optional at construction. A producer almost never knows what its reader
132
+ * will do, so the normal path is {@link acknowledge} at the consuming end;
133
+ * this entry exists so a caller that IS both ends does not have to
134
+ * round-trip through a second call.
135
+ */
136
+ acknowledgment?: Acknowledgment;
137
+ }): OutcomeEnvelope<T> {
138
+ const state = init.state;
139
+ const suggestion = init.suggestion ?? '';
140
+ if (NON_SUCCESS_STATES.has(state) && suggestion.trim() === '') {
141
+ throw new EnvelopeContractError(
142
+ `terminal state "${state}" requires a suggestion — a non-success outcome with no ` +
143
+ 'named next action is a report the reader has to translate, which is the ' +
144
+ 'judgement this envelope exists to remove.',
145
+ );
146
+ }
147
+ const truncated = init.truncated ?? false;
148
+ const totals = init.totals ?? {};
149
+ if (truncated && Object.keys(totals).length === 0) {
150
+ throw new EnvelopeContractError(
151
+ 'truncated: true requires per-category totals — a capped list whose pre-cap counts ' +
152
+ 'are unknown is indistinguishable from a complete one, which is the defect the ' +
153
+ 'flag exists to remove.',
154
+ );
155
+ }
156
+ return {
157
+ state,
158
+ retry: init.retry ?? (state === 'success' || state === 'clean-no-op' ? 'not-applicable' : 'retryable'),
159
+ suggestion,
160
+ truncated,
161
+ totals,
162
+ payload: init.payload,
163
+ // Spread rather than assigned: under `exactOptionalPropertyTypes` an
164
+ // explicit `undefined` is NOT the same as an absent key, and the whole
165
+ // detector rests on absence meaning "nobody decided".
166
+ ...(init.acknowledgment === undefined ? {} : { acknowledgment: init.acknowledgment }),
167
+ };
168
+ }
169
+
170
+ /**
171
+ * Record what a reader did with a return, without mutating the original.
172
+ *
173
+ * Returns a NEW envelope. The producer's value stays as it was emitted, so an
174
+ * acknowledgment can never be mistaken for something the producer claimed
175
+ * about its own output — which is the same author-is-not-the-evaluator
176
+ * boundary the rest of this tree keeps.
177
+ */
178
+ export function acknowledge<T>(env: OutcomeEnvelope<T>, ack: Acknowledgment): OutcomeEnvelope<T> {
179
+ return { ...env, acknowledgment: ack };
180
+ }
181
+
182
+ /**
183
+ * Cap a finding list PER CATEGORY and report what was dropped.
184
+ *
185
+ * @returns the kept items, the pre-cap totals per category, and whether
186
+ * anything was dropped. The caller passes `totals` straight into
187
+ * {@link envelope}, so the flag and the counts cannot drift apart.
188
+ */
189
+ export function capPerCategory<T>(
190
+ items: readonly T[],
191
+ categoryOf: (item: T) => string,
192
+ perCategoryCap: number,
193
+ ): { kept: T[]; totals: Record<string, number>; truncated: boolean } {
194
+ const totals: Record<string, number> = {};
195
+ const seen: Record<string, number> = {};
196
+ const kept: T[] = [];
197
+ for (const item of items) {
198
+ const c = categoryOf(item);
199
+ totals[c] = (totals[c] ?? 0) + 1;
200
+ seen[c] = (seen[c] ?? 0) + 1;
201
+ if ((seen[c] ?? 0) <= perCategoryCap) kept.push(item);
202
+ }
203
+ return { kept, totals, truncated: kept.length < items.length };
204
+ }
205
+
206
+ /**
207
+ * Classify a failure into a retry class from what a command actually produced.
208
+ *
209
+ * Deliberately a small, named list rather than a general heuristic: every entry
210
+ * corresponds to a hard-blocker class the rules already name, and a classifier
211
+ * that guessed beyond them would turn a transient failure into a permanent one.
212
+ * Anything unmatched is `retryable`, which is the safe direction — a wasted
213
+ * retry costs one iteration, a wrongly-permanent verdict costs the whole task.
214
+ */
215
+ export function classifyFailure(text: string): RetryClass {
216
+ const t = text.toLowerCase();
217
+ const hard: readonly RegExp[] = [
218
+ /\b(permission denied|forbidden|403)\b/,
219
+ /\b(unauthorized|401|not authenticated|authentication (failed|required))\b/,
220
+ /\b(quota|rate limit|too many requests|429)\b/,
221
+ /\b(missing|unset|not set)\b[^\n]{0,40}\b(credential|token|api[_ -]?key|secret)\b/,
222
+ /\bcommand not found\b/,
223
+ /\bno such (file or directory|command)\b/,
224
+ /\bspend (cap|limit) reached\b/,
225
+ ];
226
+ return hard.some((re) => re.test(t)) ? 'hard-blocker' : 'retryable';
227
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * The three outcome vocabularies this repository actually produces, and the
3
+ * one crossing between them — in a single module, so a fourth cannot appear
4
+ * without a diff to this file.
5
+ *
6
+ * `road-to-experience-loop-broadening` step 1.3. That step was written on the
7
+ * premise that the tree holds **two** outcome enums and that one of them is
8
+ * documentation-only. Re-measured at `63d06b7eb`, both halves of that premise
9
+ * are wrong, and the corrected picture is why this module registers rather
10
+ * than unifies:
11
+ *
12
+ * | Vocabulary | Subject | Declared | Values |
13
+ * |---|---|---|---|
14
+ * | phase | one audit-log line — a `/work` PHASE | here, consumed by `orchestration_record` | 4 |
15
+ * | step | one work-engine STEP | `work_engine/delivery_state.ts` (template tree) | 3 |
16
+ * | run | one command or gate RUN | here, consumed by `outcome_envelope` | 6 |
17
+ *
18
+ * All three are declared in code AND emitted today. `skipped` and `error` are
19
+ * not aspirational: `envelopeOutcome` in `orchestration_record.ts` returns
20
+ * both, and `review_skipped_record.ts` writes `outcome: 'skipped'` onto a real
21
+ * audit line. An earlier reading of this tree concluded they "exist nowhere",
22
+ * because it grepped for enum MEMBER ASSIGNMENTS (`SKIPPED: 'skipped'`) and
23
+ * these are string-literal union members. The distinction cost a wrong premise
24
+ * once; it is written down here so it cannot cost it twice.
25
+ *
26
+ * **Why register and not unify.** AI council 2026-08-29 (anthropic + openai,
27
+ * 2 rounds, $0.00, both seats subscription-authed) split on the question and
28
+ * named the same discriminator: trace the producers before choosing. The trace
29
+ * settled it — the three subjects are genuinely different (a phase aggregates
30
+ * steps; a run is neither), all three are produced, and a cross-domain mapping
31
+ * already existed in the tree. A superset would admit states that are
32
+ * nonsense for their subject: a step ending `approval-required`, a run ending
33
+ * `partial`. So: separate vocabularies, one registry, mappings only where
34
+ * execution actually crosses.
35
+ *
36
+ * **Mappings are not written for symmetry.** Exactly one crossing exists
37
+ * (`DispatchOutcome` -> phase, in `orchestration_record.ts`). A total
38
+ * phase<->step<->run mapping would be nine relations of which one is real, and
39
+ * the eight invented ones would read as contract.
40
+ *
41
+ * `revisit-if`: a producer needs a value its vocabulary cannot express, or a
42
+ * second real crossing appears, or producer analysis shows two of the three
43
+ * subjects share identical terminal semantics with a lossless mapping — at
44
+ * which point unifying those two becomes the cheaper answer.
45
+ *
46
+ * Type-only + literal arrays. No `node:` import, so any surface may read it.
47
+ */
48
+
49
+ /**
50
+ * Outcome of one audit-log line — a `/work` phase.
51
+ *
52
+ * Authoritative for `docs/contracts/audit-log-v1.md`'s `outcome` row. The
53
+ * binding is a test, not an import, because a markdown contract cannot import:
54
+ * `tests/contracts/outcome_vocabularies.test.ts`.
55
+ */
56
+ export const PHASE_OUTCOMES = ['success', 'blocked', 'skipped', 'error'] as const;
57
+ export type PhaseOutcome = (typeof PHASE_OUTCOMES)[number];
58
+
59
+ /**
60
+ * Outcome of one work-engine step.
61
+ *
62
+ * Declared in `src/agent-src/templates/scripts/work_engine/delivery_state.ts`,
63
+ * which is a TEMPLATE and self-contained by contract — no template file
64
+ * imports from `src/scripts/`. So this is the lint-checked mirror, not the
65
+ * declaration, and the same test asserts the two agree.
66
+ */
67
+ export const STEP_OUTCOMES = ['success', 'blocked', 'partial'] as const;
68
+ export type StepOutcome = (typeof STEP_OUTCOMES)[number];
69
+
70
+ /**
71
+ * Terminal state of one command or gate run.
72
+ *
73
+ * Authoritative for `contexts/execution/terminal-states.md`. Re-exported by
74
+ * `outcome_envelope.ts` as `TerminalState`, which stays the public surface —
75
+ * `runtime_journal.test.ts` pins that import path, and an anti-fork assertion
76
+ * there already prevents a second declaration.
77
+ */
78
+ export const RUN_TERMINAL_STATES = [
79
+ 'success',
80
+ 'clean-no-op',
81
+ 'blocked',
82
+ 'approval-required',
83
+ 'exhausted',
84
+ 'stagnated',
85
+ ] as const;
86
+ export type RunTerminalState = (typeof RUN_TERMINAL_STATES)[number];
87
+
88
+ /**
89
+ * The crossings that exist. One row, because one crossing is real.
90
+ *
91
+ * Read as: code at `from` translates a value of `source` into a value of
92
+ * `target`. A row is added when execution starts crossing, never in advance.
93
+ */
94
+ export const CROSS_DOMAIN_MAPPINGS = [
95
+ {
96
+ source: 'DispatchOutcome',
97
+ target: 'phase',
98
+ at: 'src/scripts/_lib/orchestration_record.ts',
99
+ fn: 'envelopeOutcome',
100
+ /**
101
+ * The mapping is VERSIONED as of 2026-08-30
102
+ * (road-to-experience-loop-broadening 2.2). Version 1 was
103
+ * unconditional: DONE / DONE_WITH_CONCERNS always became `success`.
104
+ * Version 2 is contract-gated -- a `code-change` dispatch claiming
105
+ * success with a MEASURED empty diff no longer does.
106
+ *
107
+ * Recorded here rather than only at the call site because this registry
108
+ * is the one place a reader looks to learn that a crossing exists, and a
109
+ * crossing whose semantics changed silently is worse than one nobody
110
+ * documented. Lines carry `outcome_semantics`; an absent field is
111
+ * version 1.
112
+ */
113
+ semantics_version: 2,
114
+ },
115
+ ] as const;
116
+
117
+ /** Is this string a phase outcome? The guard the audit-log consumer was missing. */
118
+ export function isPhaseOutcome(v: unknown): v is PhaseOutcome {
119
+ return typeof v === 'string' && (PHASE_OUTCOMES as readonly string[]).includes(v);
120
+ }
121
+
122
+ /** Is this string a run terminal state? */
123
+ export function isRunTerminalState(v: unknown): v is RunTerminalState {
124
+ return typeof v === 'string' && (RUN_TERMINAL_STATES as readonly string[]).includes(v);
125
+ }