@event4u/agent-config 14.12.0 → 14.13.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 (466) 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 +234 -0
  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 +109 -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-provenance.md +4 -0
  30. package/dist/agent-src/rules/design-fidelity.md +1 -1
  31. package/dist/agent-src/rules/domain-safety-pii.md +4 -0
  32. package/dist/agent-src/rules/domain-safety-retention.md +4 -0
  33. package/dist/agent-src/rules/engineering-safety-floor.md +2 -0
  34. package/dist/agent-src/rules/external-code-graph-interop.md +14 -12
  35. package/dist/agent-src/rules/improve-before-implement.md +6 -8
  36. package/dist/agent-src/rules/laravel-routing.md +1 -1
  37. package/dist/agent-src/rules/lethal-trifecta-guard.md +4 -0
  38. package/dist/agent-src/rules/secret-vcs-guard.md +2 -0
  39. package/dist/agent-src/rules/security-sensitive-stop.md +2 -0
  40. package/dist/agent-src/rules/source-confidentiality.md +12 -34
  41. package/dist/agent-src/rules/symfony-routing.md +1 -1
  42. package/dist/agent-src/rules/token-efficiency.md +14 -0
  43. package/dist/agent-src/rules/tool-safety.md +4 -0
  44. package/dist/agent-src/rules/untrusted-input-defense.md +4 -0
  45. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +247 -3
  46. package/dist/agent-src/scripts/guarded_baseline.ts +328 -0
  47. package/dist/agent-src/scripts/roadmap_set_step.ts +253 -0
  48. package/dist/agent-src/scripts/stub_queue.ts +82 -0
  49. package/dist/agent-src/scripts/stubs_due.ts +400 -0
  50. package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
  51. package/dist/agent-src/scripts/update_roadmap_progress.ts +8 -4
  52. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +17 -4
  53. package/dist/agent-src/skills/brand-audit/SKILL.md +33 -0
  54. package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -0
  55. package/dist/agent-src/skills/database/SKILL.md +8 -0
  56. package/dist/agent-src/skills/dependency-upgrade/SKILL.md +27 -0
  57. package/dist/agent-src/skills/design-review/SKILL.md +1 -1
  58. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
  59. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +17 -1
  60. package/dist/agent-src/skills/feature-planning/SKILL.md +9 -2
  61. package/dist/agent-src/skills/frontend-render-security/SKILL.md +44 -0
  62. package/dist/agent-src/skills/git-workflow/SKILL.md +1 -1
  63. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +38 -4
  64. package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +2 -2
  65. package/dist/agent-src/skills/laravel/SKILL.md +35 -0
  66. package/dist/agent-src/skills/laravel-migration/SKILL.md +57 -3
  67. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +26 -0
  68. package/dist/agent-src/skills/playbook-authoring/SKILL.md +28 -1
  69. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  70. package/dist/agent-src/skills/skill-writing/references/procedure.md +5 -5
  71. package/dist/agent-src/skills/sql-writing/SKILL.md +7 -1
  72. package/dist/agent-src/skills/standards-from-config/SKILL.md +27 -4
  73. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +11 -4
  74. package/dist/agent-src/skills/symfony-workflow/SKILL.md +35 -0
  75. package/dist/agent-src/skills/test-case-discovery/SKILL.md +85 -0
  76. package/dist/agent-src/skills/test-driven-development/SKILL.md +33 -9
  77. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
  78. package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +37 -0
  79. package/dist/agent-src/skills/ui-component-architect/SKILL.md +45 -2
  80. package/dist/agent-src/skills/upstream-contribute/SKILL.md +38 -1
  81. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +9 -4
  82. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  83. package/dist/agent-src/templates/roadmaps.md +97 -3
  84. package/dist/agent-src/templates/scripts/check_memory.ts +258 -17
  85. package/dist/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  86. package/dist/agent-src/templates/scripts/memory_lookup.ts +86 -0
  87. package/dist/agent-src/templates/scripts/memory_signal.ts +44 -0
  88. package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  89. package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  90. package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  91. package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  92. package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  93. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  94. package/dist/cli/commands/uiAudit.js +124 -5
  95. package/dist/cli/registry.js +2 -0
  96. package/dist/cli-delegate/{chunk-HYWSRNUX.js → chunk-2DK2VJWG.js} +3 -3
  97. package/dist/cli-delegate/{chunk-JCW7ZLHK.js → chunk-4FS4WRXP.js} +5 -0
  98. package/dist/cli-delegate/{chunk-OMIVVCG2.js → chunk-A4QJ6ENT.js} +24 -0
  99. package/dist/cli-delegate/{chunk-JJA2QEWA.js → chunk-AKJGUQNO.js} +466 -285
  100. package/dist/cli-delegate/{chunk-E46KPN6K.js → chunk-BTWUYDGN.js} +424 -363
  101. package/dist/cli-delegate/{chunk-K4FFODTS.js → chunk-ILMUPLGW.js} +1227 -316
  102. package/dist/cli-delegate/{chunk-FF7WAFMR.js → chunk-KPBWFOPZ.js} +5 -1
  103. package/dist/cli-delegate/cmd_adr_effective.js +102 -0
  104. package/dist/cli-delegate/cmd_conformance.js +42 -10
  105. package/dist/cli-delegate/cmd_doctor.js +3 -3
  106. package/dist/cli-delegate/cmd_export.js +3 -2
  107. package/dist/cli-delegate/cmd_fleet.js +2 -2
  108. package/dist/cli-delegate/cmd_handoff.js +1 -1
  109. package/dist/cli-delegate/cmd_preflight.js +2 -2
  110. package/dist/cli-delegate/cmd_prune.js +3 -2
  111. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  112. package/dist/cli-delegate/cmd_settings_migrate.js +3 -2
  113. package/dist/cli-delegate/cmd_settings_set.js +2 -2
  114. package/dist/cli-delegate/cmd_sync.js +3 -2
  115. package/dist/cli-delegate/cmd_uninstall.js +3 -2
  116. package/dist/cli-delegate/cmd_validate.js +3 -2
  117. package/dist/discovery/deprecation-report.md +1 -1
  118. package/dist/discovery/discovery-manifest.json +57 -57
  119. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  120. package/dist/discovery/discovery-manifest.summary.md +1 -1
  121. package/dist/discovery/dormancy-report.md +1 -1
  122. package/dist/discovery/orphan-report.md +1 -1
  123. package/dist/discovery/packs.json +2 -2
  124. package/dist/discovery/trust-report.md +1 -1
  125. package/dist/discovery/workspaces.json +2 -2
  126. package/dist/hooks/dispatch.js +1836 -712
  127. package/dist/install/claudeRuleRewrite.js +254 -0
  128. package/dist/install/detect.js +29 -16
  129. package/dist/install/detect_php_shape.js +159 -0
  130. package/dist/install/install.mjs +634 -428
  131. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  132. package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
  133. package/dist/mcp/registry-manifest.json +3 -3
  134. package/dist/mcp/server.json +3 -3
  135. package/dist/mcp/server.mjs +4818 -2645
  136. package/dist/server/schemas/settings.js +3 -0
  137. package/dist/ui/assets/index-D0jaCRPM.js +29 -0
  138. package/dist/ui/index.html +1 -1
  139. package/docs/MIGRATION.md +1 -1
  140. package/docs/THIRD-PARTY-NOTICES.md +25 -0
  141. package/docs/contracts/provider-lifecycle.md +1 -1
  142. package/docs/contracts/settings-classes.md +10 -4
  143. package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
  144. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -0
  145. package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +58 -3
  146. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +2 -2
  147. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
  148. package/docs/guidelines/agent-infra/break-glass-usage.md +7 -7
  149. package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
  150. package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
  151. package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
  152. package/docs/guidelines/agent-infra/direct-answers-demos.md +2 -2
  153. package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +1 -1
  154. package/docs/guidelines/agent-infra/engineering-memory-data-format.md +3 -3
  155. package/docs/guidelines/agent-infra/existence-question-verdicts.md +80 -0
  156. package/docs/guidelines/agent-infra/first-principles.md +2 -2
  157. package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +2 -2
  158. package/docs/guidelines/agent-infra/guarded-baseline.md +39 -0
  159. package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
  160. package/docs/guidelines/agent-infra/language-and-tone-examples.md +1 -1
  161. package/docs/guidelines/agent-infra/layered-settings.md +10 -10
  162. package/docs/guidelines/agent-infra/memory-access.md +1 -1
  163. package/docs/guidelines/agent-infra/mental-models.md +3 -3
  164. package/docs/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
  165. package/docs/guidelines/agent-infra/review-routing-data-format.md +7 -7
  166. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +13 -7
  167. package/docs/guidelines/agent-infra/role-contracts.md +2 -2
  168. package/docs/guidelines/agent-infra/role-mode-router.md +3 -3
  169. package/docs/guidelines/agent-infra/rule-type-governance.md +2 -2
  170. package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
  171. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +6 -6
  172. package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +2 -2
  173. package/docs/guidelines/agent-infra/six-hats.md +3 -3
  174. package/docs/guidelines/agent-infra/skill-quality-checklist.md +6 -6
  175. package/docs/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
  176. package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
  177. package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
  178. package/docs/guidelines/augment-portability-patterns.md +6 -4
  179. package/docs/guidelines/component-oriented-and-oop-development.md +3 -2
  180. package/docs/guidelines/cross-role-handoff.md +2 -2
  181. package/docs/guidelines/design-fidelity-mechanics.md +1 -1
  182. package/docs/guidelines/docs/readme-size-and-splitting.md +3 -3
  183. package/docs/guidelines/php/database.md +90 -7
  184. package/docs/guidelines/prompt-templates.md +7 -7
  185. package/llms.txt +2 -2
  186. package/package.json +5 -2
  187. package/src/agent-src/scripts/archive_completed_roadmaps.ts +247 -3
  188. package/src/agent-src/scripts/guarded_baseline.ts +328 -0
  189. package/src/agent-src/scripts/roadmap_set_step.ts +253 -0
  190. package/src/agent-src/scripts/stub_queue.ts +82 -0
  191. package/src/agent-src/scripts/stubs_due.ts +400 -0
  192. package/src/agent-src/scripts/ticket_bundles.ts +84 -0
  193. package/src/agent-src/scripts/update_roadmap_progress.ts +8 -4
  194. package/src/agent-src/templates/scripts/check_memory.ts +258 -17
  195. package/src/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  196. package/src/agent-src/templates/scripts/memory_lookup.ts +86 -0
  197. package/src/agent-src/templates/scripts/memory_signal.ts +44 -0
  198. package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  199. package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  200. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  201. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  202. package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  203. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  204. package/src/config/agent-settings.template.yml +32 -3
  205. package/src/config/assurance-capability-registry.json +21 -9
  206. package/src/config/canonical-terms.yml +119 -0
  207. package/src/config/capability-native-outcome-bars.json +81 -0
  208. package/src/config/ci-local-parity.yml +80 -0
  209. package/src/config/drafting-channels.yml +43 -0
  210. package/src/config/estate-count-budget.json +38 -36
  211. package/src/config/evaluator-budgets.json +14 -14
  212. package/src/config/gate-coverage.yml +579 -63
  213. package/src/config/gate-reachability-exemptions.json +21 -0
  214. package/src/config/gate-violation-baselines.json +37 -19
  215. package/src/config/harness-evolution-budget.json +25 -0
  216. package/src/config/lapsed-beta-baseline.json +96 -0
  217. package/src/config/memory-twin-verdicts.yml +129 -0
  218. package/src/config/metric-registry.yml +124 -0
  219. package/src/config/pack-size-budget.json +16 -15
  220. package/src/config/preamble-payload-budget.json +8 -8
  221. package/src/config/profiles/balanced.ini +27 -0
  222. package/src/config/profiles/full.ini +27 -0
  223. package/src/config/profiles/minimal.ini +27 -0
  224. package/src/config/publish-surface.json +9 -2
  225. package/src/config/routing-coverage-seed.json +16 -2
  226. package/src/config/rule-stub-ceilings.json +126 -112
  227. package/src/config/turnaround-budget.json +66 -0
  228. package/src/install/claudeRuleRewrite.ts +288 -0
  229. package/src/install/detect.ts +60 -17
  230. package/src/install/detect_php_shape.ts +191 -0
  231. package/src/scripts/_cli/cmd_doctor.ts +27 -112
  232. package/src/scripts/_dispatch.bash +27 -0
  233. package/src/scripts/_lib/activation_ladder.ts +211 -0
  234. package/src/scripts/_lib/activation_states.ts +88 -0
  235. package/src/scripts/_lib/adherence_detectors.ts +143 -0
  236. package/src/scripts/_lib/arith_claims.ts +181 -0
  237. package/src/scripts/_lib/arm_ranking.ts +62 -0
  238. package/src/scripts/_lib/asset_delivery_ledger.ts +303 -0
  239. package/src/scripts/_lib/audit_field_provenance.ts +54 -0
  240. package/src/scripts/_lib/auto_dispatch.ts +32 -3
  241. package/src/scripts/_lib/bench_ab_size_claim.ts +98 -4
  242. package/src/scripts/_lib/benchmark_cache_fields.ts +158 -0
  243. package/src/scripts/_lib/candidate_proposer.ts +402 -0
  244. package/src/scripts/_lib/candidate_record.ts +601 -0
  245. package/src/scripts/_lib/capture_rate.ts +319 -0
  246. package/src/scripts/_lib/collector_denominator.ts +771 -0
  247. package/src/scripts/_lib/collector_record.ts +340 -0
  248. package/src/scripts/_lib/collector_store.ts +664 -0
  249. package/src/scripts/_lib/collector_supervision.ts +827 -0
  250. package/src/scripts/_lib/concern_estate.ts +77 -0
  251. package/src/scripts/_lib/config_chain.ts +477 -0
  252. package/src/scripts/_lib/config_cost.ts +209 -0
  253. package/src/scripts/_lib/council_settings_block.ts +6 -0
  254. package/src/scripts/_lib/curator_ops.ts +172 -0
  255. package/src/scripts/_lib/delivery_arm_experiment.ts +266 -0
  256. package/src/scripts/_lib/delivery_criticality.ts +126 -0
  257. package/src/scripts/_lib/doctor_runtime_checks.ts +70 -0
  258. package/src/scripts/_lib/empty_cycles.ts +88 -0
  259. package/src/scripts/_lib/eval_publication.ts +354 -0
  260. package/src/scripts/_lib/evaluation_vector.ts +283 -0
  261. package/src/scripts/_lib/evaluator_promotion.ts +225 -0
  262. package/src/scripts/_lib/evidence_basis.ts +118 -0
  263. package/src/scripts/_lib/exec_evidence.ts +8 -0
  264. package/src/scripts/_lib/experience_card.ts +272 -0
  265. package/src/scripts/_lib/experience_report.ts +151 -0
  266. package/src/scripts/_lib/experiment_freeze.ts +112 -0
  267. package/src/scripts/_lib/generated_by.ts +66 -0
  268. package/src/scripts/_lib/harness_evolution_guards.ts +229 -0
  269. package/src/scripts/_lib/hook_effect_probe.ts +141 -0
  270. package/src/scripts/_lib/host_denominator.ts +687 -0
  271. package/src/scripts/_lib/host_projection_reach.ts +157 -0
  272. package/src/scripts/_lib/ignored_blocker.ts +148 -0
  273. package/src/scripts/_lib/install_reach_checks.ts +495 -0
  274. package/src/scripts/_lib/json_duplicate_keys.ts +150 -0
  275. package/src/scripts/_lib/judge_hygiene.ts +228 -0
  276. package/src/scripts/_lib/legacy_boundary_map.ts +228 -0
  277. package/src/scripts/_lib/loop_guards.ts +299 -0
  278. package/src/scripts/_lib/loss_class.ts +129 -0
  279. package/src/scripts/_lib/machine_wake.ts +51 -0
  280. package/src/scripts/_lib/md_prose_lines.ts +177 -0
  281. package/src/scripts/_lib/minimality_tiebreak.ts +168 -0
  282. package/src/scripts/_lib/one_resolver_invariant.ts +449 -0
  283. package/src/scripts/_lib/orchestration_record.ts +253 -5
  284. package/src/scripts/_lib/outcome_envelope.ts +227 -0
  285. package/src/scripts/_lib/outcome_vocabularies.ts +125 -0
  286. package/src/scripts/_lib/paired_stats.ts +245 -0
  287. package/src/scripts/_lib/paired_verdict.ts +226 -0
  288. package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
  289. package/src/scripts/_lib/privacy_class.ts +47 -0
  290. package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
  291. package/src/scripts/_lib/repeated_failure.ts +105 -0
  292. package/src/scripts/_lib/repo_root.ts +111 -0
  293. package/src/scripts/_lib/review_skipped_record.ts +37 -0
  294. package/src/scripts/_lib/role_split.ts +338 -0
  295. package/src/scripts/_lib/runtime_journal.ts +1499 -0
  296. package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
  297. package/src/scripts/_lib/skill_catalogue.ts +11 -1
  298. package/src/scripts/_lib/source_digest.ts +200 -0
  299. package/src/scripts/_lib/source_redact.ts +260 -0
  300. package/src/scripts/_lib/source_shape.ts +502 -0
  301. package/src/scripts/_lib/source_snapshot_dedup.ts +199 -0
  302. package/src/scripts/_lib/strip_comments.d.mts +8 -0
  303. package/src/scripts/_lib/strip_comments.mjs +65 -0
  304. package/src/scripts/_lib/test_red_state.ts +154 -0
  305. package/src/scripts/_lib/trigger_shift.ts +144 -0
  306. package/src/scripts/_lib/untrusted_content.ts +82 -7
  307. package/src/scripts/adoption_report.ts +1 -1
  308. package/src/scripts/adr/evidence_census.ts +1 -1
  309. package/src/scripts/adr/regenerate_index.ts +26 -2
  310. package/src/scripts/adr_cite_check.ts +164 -1
  311. package/src/scripts/ai_council/blind_review.ts +11 -1
  312. package/src/scripts/ai_council/clients.ts +4 -0
  313. package/src/scripts/ai_council/config.ts +3 -0
  314. package/src/scripts/ai_council/consensus.ts +28 -8
  315. package/src/scripts/ai_council/consensus_round.ts +226 -0
  316. package/src/scripts/ai_council/disagreement_signal.ts +338 -0
  317. package/src/scripts/ai_council/inline_findings.ts +340 -0
  318. package/src/scripts/ai_council/judge_position_bias.ts +197 -0
  319. package/src/scripts/ai_council/orchestrator.ts +16 -203
  320. package/src/scripts/ai_council/orchestrator_results.ts +23 -3
  321. package/src/scripts/ai_council/pricing.ts +106 -0
  322. package/src/scripts/ai_council/prompts.ts +74 -7
  323. package/src/scripts/ai_council/provider_leakage_bench.ts +327 -0
  324. package/src/scripts/ai_council/py_format.ts +14 -3
  325. package/src/scripts/ai_council/recouncil_guard.ts +293 -0
  326. package/src/scripts/ai_council/response_record.ts +50 -0
  327. package/src/scripts/ai_council/topology_bench_manifest.ts +860 -0
  328. package/src/scripts/ai_council/topology_vocabulary.ts +175 -0
  329. package/src/scripts/asset_delivery_ledger.ts +157 -0
  330. package/src/scripts/attest_artifact.ts +193 -0
  331. package/src/scripts/audit_auto_rules.ts +2 -1
  332. package/src/scripts/audit_command_surface.ts +1 -1
  333. package/src/scripts/audit_mcp_tools.ts +2 -2
  334. package/src/scripts/audit_skill_overlap_allowlist.json +6 -1
  335. package/src/scripts/audit_user_type_axis.ts +2 -1
  336. package/src/scripts/bench_ab_clone.ts +215 -10
  337. package/src/scripts/bench_ab_integrity.ts +119 -5
  338. package/src/scripts/bench_ab_v2_stats.ts +40 -213
  339. package/src/scripts/build_archive_index.ts +1 -1
  340. package/src/scripts/build_linear_digest.ts +1 -1
  341. package/src/scripts/build_proof.ts +11 -4
  342. package/src/scripts/build_rule_trigger_matrix.ts +1 -1
  343. package/src/scripts/build_source_digests.ts +157 -0
  344. package/src/scripts/cache_realization_report.ts +103 -0
  345. package/src/scripts/check_adr_frontmatter.ts +126 -0
  346. package/src/scripts/check_benchmark_report_fields.ts +207 -0
  347. package/src/scripts/check_beta_review_markers.ts +235 -6
  348. package/src/scripts/check_bundle_path_leakage.ts +34 -1
  349. package/src/scripts/check_claims.ts +576 -6
  350. package/src/scripts/check_composite_arming.ts +35 -0
  351. package/src/scripts/check_concern_admissions.ts +365 -0
  352. package/src/scripts/check_enforcement_coverage.ts +28 -0
  353. package/src/scripts/check_estate_count.ts +142 -1
  354. package/src/scripts/check_gate_reachability.ts +383 -0
  355. package/src/scripts/check_host_loadability.ts +104 -0
  356. package/src/scripts/check_loss_class_declared.ts +308 -0
  357. package/src/scripts/check_md_language.ts +15 -98
  358. package/src/scripts/check_memory_proposal.ts +18 -11
  359. package/src/scripts/check_no_currency_in_cost_surfaces.ts +225 -0
  360. package/src/scripts/check_no_external_sources.ts +281 -6
  361. package/src/scripts/check_pack_conformance_fixture.ts +11 -1
  362. package/src/scripts/check_pack_size.ts +59 -2
  363. package/src/scripts/check_preamble_payload_budget.ts +114 -3
  364. package/src/scripts/check_prefix_stable_mutation.ts +372 -0
  365. package/src/scripts/check_publish_surface.ts +10 -1
  366. package/src/scripts/check_references.ts +24 -1
  367. package/src/scripts/check_rule_evidence_declaration.ts +316 -0
  368. package/src/scripts/check_rule_projection_integrity.ts +14 -4
  369. package/src/scripts/check_score_contract.ts +26 -3
  370. package/src/scripts/check_static_parity.ts +285 -0
  371. package/src/scripts/check_supervision_claim_atomicity.ts +498 -0
  372. package/src/scripts/check_suppression_hygiene.ts +15 -0
  373. package/src/scripts/ci_settle.ts +39 -2
  374. package/src/scripts/code_graph/build.ts +60 -3
  375. package/src/scripts/code_graph/extract.ts +44 -0
  376. package/src/scripts/code_graph/types.ts +24 -0
  377. package/src/scripts/collector_daemon.ts +714 -0
  378. package/src/scripts/config_cost_report.ts +302 -0
  379. package/src/scripts/consumer_matrix.ts +74 -1
  380. package/src/scripts/cost/budget.mjs +10 -3
  381. package/src/scripts/cost/track.mjs +10 -3
  382. package/src/scripts/council_cli.ts +37 -54
  383. package/src/scripts/dispatch_r2_reviewer.ts +46 -5
  384. package/src/scripts/evolution_lab.ts +980 -0
  385. package/src/scripts/external_sources_denylist.json +5 -18
  386. package/src/scripts/extract_audit_patterns.ts +21 -0
  387. package/src/scripts/fold_intake.ts +12 -1
  388. package/src/scripts/gen_discovery_baseline.ts +1 -1
  389. package/src/scripts/generate_capabilities_index.ts +12 -5
  390. package/src/scripts/generate_capability_matrix.ts +3 -3
  391. package/src/scripts/generate_command_flows.ts +2 -2
  392. package/src/scripts/generate_cookbook.ts +2 -2
  393. package/src/scripts/generate_index.ts +8 -1
  394. package/src/scripts/generate_knowledge_index.ts +2 -1
  395. package/src/scripts/generate_ownership_matrix.ts +2 -1
  396. package/src/scripts/generate_pack_manifests.ts +10 -2
  397. package/src/scripts/generate_role_experiences_catalog.ts +2 -2
  398. package/src/scripts/generate_settings_reference.ts +1 -1
  399. package/src/scripts/git_authorization_hook.ts +22 -1
  400. package/src/scripts/grade_target_readiness.ts +48 -5
  401. package/src/scripts/hook_effect_doctor.ts +261 -0
  402. package/src/scripts/hook_manifest.json +1 -1
  403. package/src/scripts/hook_manifest.yaml +98 -11
  404. package/src/scripts/hooks/block_speaking_inbox_dir.ts +271 -0
  405. package/src/scripts/hooks/block_unauthorized_git.ts +18 -0
  406. package/src/scripts/hooks/concern_registry.ts +4 -0
  407. package/src/scripts/hooks/dispatch_hook.ts +32 -0
  408. package/src/scripts/hooks/journal_record_hook.ts +345 -0
  409. package/src/scripts/hooks/prepush_metadata_sources.sh +110 -0
  410. package/src/scripts/hooks/run_continuation_hook.ts +44 -9
  411. package/src/scripts/hooks/shims/install.sh +61 -0
  412. package/src/scripts/hooks/shims/php +101 -0
  413. package/src/scripts/hooks/suggestion_capture_hook.ts +10 -0
  414. package/src/scripts/hot_context_hook.ts +16 -0
  415. package/src/scripts/install-hooks.sh +20 -5
  416. package/src/scripts/install.ts +17 -35
  417. package/src/scripts/inventory_frontmatter.ts +2 -1
  418. package/src/scripts/lint_adr_sweep_routing.ts +12 -0
  419. package/src/scripts/lint_canonical_terms.ts +604 -0
  420. package/src/scripts/lint_composition_review.ts +619 -0
  421. package/src/scripts/lint_consolidation_lineage.ts +666 -0
  422. package/src/scripts/lint_eval_specs.ts +593 -0
  423. package/src/scripts/lint_hook_manifest.ts +19 -0
  424. package/src/scripts/lint_host_portability.ts +373 -0
  425. package/src/scripts/lint_judge_prompt_expectation.ts +27 -1
  426. package/src/scripts/lint_memory_twin_parity.ts +335 -0
  427. package/src/scripts/lint_metric_consumers.ts +355 -0
  428. package/src/scripts/lint_skill_descriptions.ts +18 -1
  429. package/src/scripts/lint_skill_frontmatter_safety.ts +58 -0
  430. package/src/scripts/lint_skill_link_reach.ts +252 -0
  431. package/src/scripts/lint_skill_trigger_corpus.ts +426 -23
  432. package/src/scripts/lint_ticket_buildable.ts +17 -1
  433. package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -1
  434. package/src/scripts/mcp_server/tool_catalog_source.ts +1 -1
  435. package/src/scripts/measure_docs_dead_links.ts +348 -0
  436. package/src/scripts/measure_host_capture.ts +461 -0
  437. package/src/scripts/migration_status.ts +3 -3
  438. package/src/scripts/model_rule_injection.ts +60 -0
  439. package/src/scripts/orchestration_record.ts +14 -0
  440. package/src/scripts/preamble_byte_census.ts +139 -10
  441. package/src/scripts/prepack-check.mjs +4 -1
  442. package/src/scripts/probe_turnaround.ts +384 -0
  443. package/src/scripts/probe_unblocked_ask.ts +279 -0
  444. package/src/scripts/render_benchmark_md.ts +1 -1
  445. package/src/scripts/rule_activation_census.ts +70 -9
  446. package/src/scripts/rule_backlinks.ts +1 -1
  447. package/src/scripts/run_lifecycle_suite.ts +208 -0
  448. package/src/scripts/run_skill_evals.ts +40 -0
  449. package/src/scripts/schemas/delivery-manifest.schema.json +43 -0
  450. package/src/scripts/schemas/drafting-channels.schema.json +43 -0
  451. package/src/scripts/schemas/evals.schema.json +24 -1
  452. package/src/scripts/schemas/rule.schema.json +52 -1
  453. package/src/scripts/schemas/skill.schema.json +17 -2
  454. package/src/scripts/skill_overlap.ts +7 -1
  455. package/src/scripts/skill_tools/run_block_d_eval.ts +8 -1
  456. package/src/scripts/skill_tools/score_skill_relevance.ts +84 -3
  457. package/src/scripts/skill_tools/suggest_skill_for_task.ts +8 -1
  458. package/src/scripts/skill_usage_report.ts +2 -1
  459. package/src/scripts/stubs_due.ts +211 -0
  460. package/src/scripts/sweep_source_surfaces.ts +678 -0
  461. package/src/scripts/sync_pr_branch.ts +3 -3
  462. package/src/scripts/trigger_eval_grandfather.json +202 -222
  463. package/src/scripts/utilization_report.ts +22 -2
  464. package/src/server/schemas/settings.ts +5 -0
  465. package/src/templates/marketing-copy.yml +1 -1
  466. package/dist/ui/assets/index-Cxgy63kz.js +0 -26
@@ -0,0 +1,402 @@
1
+ /**
2
+ * The deterministic candidate proposer — fixed recipes, no model in the loop.
3
+ *
4
+ * `road-to-governed-harness-evolution` Phase 3, step 3.5.
5
+ *
6
+ * > *Ship a deterministic proposer first. Fixed recipes for known defect
7
+ * > classes, so the loop is validated without model quality as a confound.*
8
+ * > verify: **the same input produces byte-identical candidates across two
9
+ * > runs.**
10
+ *
11
+ * The seam this plugs into already existed: `bench_ab_clone --candidate-record`
12
+ * consumes a validated candidate record file, so a proposer's whole job is to
13
+ * PRODUCE those files. Nothing here materialises a clone, spawns a process, or
14
+ * calls a model.
15
+ *
16
+ * ## What is being claimed, and what is not
17
+ *
18
+ * Claimed: the mapping from an observation set to a byte string is a pure
19
+ * function of that set plus the subject bytes it reads. Two runs over the same
20
+ * input produce the same bytes, on any machine, in any order, at any time.
21
+ *
22
+ * NOT claimed: that these three recipes improve anything. Whether a candidate
23
+ * is better than the baseline is the paired verdict's question in Phase 4, and
24
+ * a proposer that asserted its own efficacy would be answering it in the wrong
25
+ * place. The recipes are deliberately blunt, total, and idempotent — that is
26
+ * what makes them a control condition rather than a competitor.
27
+ *
28
+ * ## The four things that would break determinism, and where each is closed
29
+ *
30
+ * 1. **Wall-clock.** No timestamp is written into a record, and the id is not
31
+ * derived from one. {@link candidateId} hashes content.
32
+ * 2. **Filesystem iteration order.** The proposer never reads a directory.
33
+ * Its input is an explicit, ordered list; {@link proposeCandidates} sorts
34
+ * it before emitting.
35
+ * 3. **Locale-dependent ordering.** Every sort here is a byte-wise comparison
36
+ * via {@link byteCompare}. `String.prototype.localeCompare` is deliberately
37
+ * not used — it is ICU-dependent, so two machines can disagree about the
38
+ * order of two ids and produce two different files.
39
+ * 4. **Object key order.** {@link serialiseCandidateRecord} routes through
40
+ * `candidateRecordToJson`, which fixes key order in one place.
41
+ *
42
+ * A fifth would be randomness or a counter; there is neither.
43
+ */
44
+
45
+ import { createHash } from 'node:crypto';
46
+
47
+ import {
48
+ CANDIDATE_RECORD_VERSION,
49
+ type CandidateRecord,
50
+ CandidateSchemaError,
51
+ type Mutation,
52
+ type MutationDimension,
53
+ assertMutationPathsOwned,
54
+ candidateRecordToJson,
55
+ isCandidateOwnedPath,
56
+ } from './candidate_record.js';
57
+
58
+ // --- The defect classes -----------------------------------------------------
59
+
60
+ /**
61
+ * The three defect classes with a fixed recipe, one per mutation dimension.
62
+ *
63
+ * One per dimension is not a coincidence and is not a rule either: it is what
64
+ * makes the first proposer exercise all three arms of the alphabet step 3.3
65
+ * fixed. A fourth class would be legal as long as it lands on one of the three
66
+ * dimensions; a class needing a fourth DIMENSION is refused upstream by
67
+ * `parseCandidateRecord`, not here.
68
+ */
69
+ export const DEFECT_CLASSES = [
70
+ 'over-broad-activation',
71
+ 'unrouted-obligation',
72
+ 'unbacked-enforcement-claim',
73
+ ] as const;
74
+ export type DefectClass = (typeof DEFECT_CLASSES)[number];
75
+
76
+ export function isDefectClass(v: unknown): v is DefectClass {
77
+ return typeof v === 'string' && (DEFECT_CLASSES as readonly string[]).includes(v);
78
+ }
79
+
80
+ /** The pointer a truncated artefact carries, so the mutation is not a silent deletion. */
81
+ export const BAND_POINTER =
82
+ '<!-- candidate: leading band only; the full artefact is unchanged in the baseline clone -->';
83
+
84
+ /** The fixed honest-enforcement block the content recipe appends. */
85
+ export const HONEST_ENFORCEMENT_BLOCK =
86
+ '## Honest enforcement\n\n' +
87
+ 'Nothing observes whether this obligation was met. It is model-carried, and\n' +
88
+ 'saying so is cheaper than a check that would have to guess.';
89
+
90
+ /**
91
+ * One fixed recipe: a defect class, the dimension it mutates, and a TOTAL,
92
+ * IDEMPOTENT rewrite of the subject's bytes.
93
+ *
94
+ * Total: defined for every string, including the empty one. A recipe that can
95
+ * fail on some input makes the proposer's output depend on which subjects
96
+ * happen to be well-formed, which is a second determinism hazard wearing the
97
+ * costume of a validation error.
98
+ *
99
+ * Idempotent: `rewrite(rewrite(x)) === rewrite(x)`. Pinned by a test rather
100
+ * than by a comment, because it is the property that lets the same observation
101
+ * be re-proposed after a partial run without producing a different id.
102
+ */
103
+ export interface Recipe {
104
+ readonly defectClass: DefectClass;
105
+ readonly dimension: MutationDimension;
106
+ /** Why this class is a defect, in one line, for the `explain` verb. */
107
+ readonly summary: string;
108
+ /** Does this class require an explicit route target on the observation? */
109
+ readonly needsRouteTo: boolean;
110
+ readonly rewrite: (body: string, routeTo: string) => string;
111
+ }
112
+
113
+ /**
114
+ * Keep the leading band, drop the rest.
115
+ *
116
+ * The band is everything before the first `## ` heading — this tree's own
117
+ * "rich artifacts lead with a non-negotiable band" shape. An artefact with no
118
+ * `## ` heading is already all band, so it comes back unchanged apart from the
119
+ * pointer.
120
+ *
121
+ * This is an ACTIVATION mutation and not a content one: it changes how much of
122
+ * the artefact is delivered per session, not what the delivered part says. The
123
+ * two are easy to confuse, which is exactly why step 3.2 refuses a candidate
124
+ * that does both.
125
+ */
126
+ export function keepLeadingBand(body: string): string {
127
+ if (body.includes(BAND_POINTER)) {
128
+ return body;
129
+ }
130
+ const lines = body.split('\n');
131
+ let cut = lines.length;
132
+ for (let i = 0; i < lines.length; i += 1) {
133
+ if ((lines[i] as string).startsWith('## ')) {
134
+ cut = i;
135
+ break;
136
+ }
137
+ }
138
+ const band = lines.slice(0, cut).join('\n').replace(/\s+$/, '');
139
+ return `${band}\n\n${BAND_POINTER}\n`;
140
+ }
141
+
142
+ /**
143
+ * Append a route pointer naming where the obligation is discharged.
144
+ *
145
+ * The target comes from the observation, never from the subject's name. A
146
+ * proposer that guessed the route target from a filename would be inventing a
147
+ * claim about the tree, and an invented route reads exactly like a verified one
148
+ * once it is in the file.
149
+ */
150
+ export function appendRoutePointer(body: string, routeTo: string): string {
151
+ const line = `- Routed to \`${routeTo}\` — the obligation above is discharged there.`;
152
+ if (body.includes(line)) {
153
+ return body;
154
+ }
155
+ return `${body.replace(/\s+$/, '')}\n\n## See also\n\n${line}\n`;
156
+ }
157
+
158
+ /** Append the fixed honest-enforcement block, once. */
159
+ export function appendHonestEnforcement(body: string): string {
160
+ if (body.includes(HONEST_ENFORCEMENT_BLOCK)) {
161
+ return body;
162
+ }
163
+ return `${body.replace(/\s+$/, '')}\n\n${HONEST_ENFORCEMENT_BLOCK}\n`;
164
+ }
165
+
166
+ export const RECIPES: Readonly<Record<DefectClass, Recipe>> = {
167
+ 'over-broad-activation': {
168
+ defectClass: 'over-broad-activation',
169
+ dimension: 'activation',
170
+ summary:
171
+ 'the whole artefact is delivered every session when only its leading band is load-bearing',
172
+ needsRouteTo: false,
173
+ rewrite: (body) => keepLeadingBand(body),
174
+ },
175
+ 'unrouted-obligation': {
176
+ defectClass: 'unrouted-obligation',
177
+ dimension: 'routing',
178
+ summary: 'the artefact states an obligation and names no artefact that discharges it',
179
+ needsRouteTo: true,
180
+ rewrite: (body, routeTo) => appendRoutePointer(body, routeTo),
181
+ },
182
+ 'unbacked-enforcement-claim': {
183
+ defectClass: 'unbacked-enforcement-claim',
184
+ dimension: 'content',
185
+ summary: 'the artefact reads as enforced while nothing can observe a violation',
186
+ needsRouteTo: false,
187
+ rewrite: (body) => appendHonestEnforcement(body),
188
+ },
189
+ };
190
+
191
+ // --- Observations -----------------------------------------------------------
192
+
193
+ /**
194
+ * One observed defect: which class, which artefact, and (for `routing`) where
195
+ * the obligation is discharged.
196
+ *
197
+ * `subject` is repo-relative and must sit inside the candidate surface. That is
198
+ * checked HERE as well as in `parseCandidateRecord` and again in
199
+ * `apply_candidate_mutations`, because a proposer that emits an out-of-surface
200
+ * mutation has already written a bad record to disk by the time the clone
201
+ * refuses it, and an operator then holds a file that no verb will accept.
202
+ */
203
+ export interface DefectObservation {
204
+ readonly defectClass: DefectClass;
205
+ readonly subject: string;
206
+ readonly routeTo?: string;
207
+ }
208
+
209
+ function requireString(obj: Record<string, unknown>, key: string): string {
210
+ const v = obj[key];
211
+ if (typeof v !== 'string' || v.trim() === '') {
212
+ throw new CandidateSchemaError(`observation '${key}' must be a non-empty string`);
213
+ }
214
+ return v;
215
+ }
216
+
217
+ /**
218
+ * Validate an untrusted observation list — the REFUSING path.
219
+ *
220
+ * Refuses, each with its own message: a non-array input; a class outside
221
+ * {@link DEFECT_CLASSES}; a subject outside the candidate surface; a missing
222
+ * `routeTo` on a class whose recipe needs one; a `routeTo` on a class whose
223
+ * recipe does not read it; and a duplicate `(defectClass, subject)` pair.
224
+ *
225
+ * The duplicate refusal is load-bearing rather than tidy: a duplicate pair
226
+ * hashes to the same id, so it would write the same filename twice. Silently
227
+ * de-duplicating would make the count of proposed candidates depend on the
228
+ * input's redundancy, and refusing says so.
229
+ *
230
+ * @throws {CandidateSchemaError} on the first violation.
231
+ */
232
+ export function parseObservations(input: unknown): DefectObservation[] {
233
+ if (!Array.isArray(input)) {
234
+ throw new CandidateSchemaError(
235
+ 'observations must be a JSON array of {defectClass, subject[, routeTo]} objects',
236
+ );
237
+ }
238
+ const out: DefectObservation[] = [];
239
+ const seen = new Set<string>();
240
+ for (const item of input) {
241
+ if (typeof item !== 'object' || item === null || Array.isArray(item)) {
242
+ throw new CandidateSchemaError('each observation must be a JSON object');
243
+ }
244
+ const obj = item as Record<string, unknown>;
245
+ const cls = requireString(obj, 'defectClass');
246
+ if (!isDefectClass(cls)) {
247
+ throw new CandidateSchemaError(
248
+ `'defectClass' must be one of ${DEFECT_CLASSES.join(', ')} (got ${JSON.stringify(cls)}). ` +
249
+ 'A class with no fixed recipe has no deterministic proposal, and inventing one ' +
250
+ 'is the model-quality confound this step exists to remove',
251
+ );
252
+ }
253
+ const subject = requireString(obj, 'subject');
254
+ if (!isCandidateOwnedPath(subject)) {
255
+ throw new CandidateSchemaError(
256
+ `observation subject '${subject}' is outside the candidate surface — a proposal ` +
257
+ 'that rewrites a task-target file is a different experiment, not a harness variant',
258
+ );
259
+ }
260
+ const key = `${cls} ${subject}`;
261
+ if (seen.has(key)) {
262
+ throw new CandidateSchemaError(
263
+ `duplicate observation (${cls}, ${subject}) — it hashes to one candidate id, so the ` +
264
+ 'second would silently overwrite the first',
265
+ );
266
+ }
267
+ seen.add(key);
268
+ const recipe = RECIPES[cls];
269
+ if (recipe.needsRouteTo) {
270
+ out.push({ defectClass: cls, subject, routeTo: requireString(obj, 'routeTo') });
271
+ } else {
272
+ if ('routeTo' in obj) {
273
+ throw new CandidateSchemaError(
274
+ `observation (${cls}, ${subject}) carries 'routeTo', which only the routing ` +
275
+ 'recipe reads. An ignored field is an instruction the operator believes was followed',
276
+ );
277
+ }
278
+ out.push({ defectClass: cls, subject });
279
+ }
280
+ }
281
+ return out;
282
+ }
283
+
284
+ // --- Proposing --------------------------------------------------------------
285
+
286
+ /** Reads a repo-relative subject's current bytes. Injected so tests need no tree. */
287
+ export type SubjectReader = (subject: string) => string;
288
+
289
+ /** Byte-wise, locale-independent string order. Never `localeCompare`. */
290
+ export function byteCompare(a: string, b: string): number {
291
+ if (a < b) {
292
+ return -1;
293
+ }
294
+ if (a > b) {
295
+ return 1;
296
+ }
297
+ return 0;
298
+ }
299
+
300
+ /** Short, stable per-dimension id tag, so an id says which arm it sits on. */
301
+ const DIMENSION_TAG: Readonly<Record<MutationDimension, string>> = {
302
+ activation: 'act',
303
+ routing: 'rou',
304
+ content: 'con',
305
+ };
306
+
307
+ /**
308
+ * The candidate id: a content hash, never a counter and never a clock.
309
+ *
310
+ * Hashed inputs are the defect class, the subject, and the exact bytes each
311
+ * mutation writes. Two consequences worth stating because both are relied on:
312
+ * re-proposing an unchanged observation over an unchanged tree yields the SAME
313
+ * id (so `run --refresh` rebuilds the same clone rather than accumulating
314
+ * near-duplicates), and a changed subject yields a DIFFERENT id (so a candidate
315
+ * built from stale bytes cannot be mistaken for one built from current bytes).
316
+ *
317
+ * Twelve hex characters is 48 bits. At the roadmap's exit-criterion scale —
318
+ * five candidates — a collision is ~5e-13 likely; the id is a directory name,
319
+ * not a security boundary, and `bench_ab_clone` refuses a repeated id outright
320
+ * rather than merging two candidates into one clone.
321
+ */
322
+ export function candidateId(
323
+ defectClass: DefectClass,
324
+ subject: string,
325
+ mutations: readonly Mutation[],
326
+ ): string {
327
+ const h = createHash('sha256');
328
+ h.update(defectClass);
329
+ h.update(' ');
330
+ h.update(subject);
331
+ for (const m of [...mutations].sort((x, y) => byteCompare(x.path, y.path))) {
332
+ h.update(' ');
333
+ h.update(m.path);
334
+ h.update(' ');
335
+ h.update(m.content);
336
+ }
337
+ return `${DIMENSION_TAG[RECIPES[defectClass].dimension]}-${h.digest('hex').slice(0, 12)}`;
338
+ }
339
+
340
+ /**
341
+ * Turn observations into candidate records. Pure given the same reader.
342
+ *
343
+ * Ordering is fixed EXACTLY ONCE, here, on the input. There is deliberately no
344
+ * second sort of the output: a run of the seen-red sweep showed that with the
345
+ * input sorted, neutralising an output sort changed nothing observable — it was
346
+ * a guard whose red could not be produced, which is indistinguishable from a
347
+ * guard that does not work. One ordering site, one guard, one red.
348
+ *
349
+ * Two properties follow from that single sort, and they are tested separately
350
+ * because they are different failures: the RETURNED order is independent of the
351
+ * caller's order, and the order subjects are READ in is too (read order is
352
+ * observable — with a throwing reader it decides whose error message surfaces).
353
+ *
354
+ * Every emitted record is `lifecycle: 'proposed'`, with no way to ask for
355
+ * another state. A proposer that could emit `promotion-eligible` would be
356
+ * grading its own output, which is the confusion step 3.4's lifecycle enum
357
+ * exists to make impossible.
358
+ *
359
+ * @throws {CandidateSchemaError} if a recipe produces an out-of-surface mutation.
360
+ */
361
+ export function proposeCandidates(
362
+ observations: readonly DefectObservation[],
363
+ read: SubjectReader,
364
+ ): CandidateRecord[] {
365
+ const ordered = [...observations].sort(
366
+ (a, b) => byteCompare(a.defectClass, b.defectClass) || byteCompare(a.subject, b.subject),
367
+ );
368
+ const records: CandidateRecord[] = [];
369
+ for (const obs of ordered) {
370
+ const recipe = RECIPES[obs.defectClass];
371
+ const before = read(obs.subject);
372
+ const after = recipe.rewrite(before, obs.routeTo ?? '');
373
+ const mutations: Mutation[] = [{ path: obs.subject, content: after }];
374
+ assertMutationPathsOwned(mutations);
375
+ records.push({
376
+ kind: 'candidate',
377
+ version: CANDIDATE_RECORD_VERSION,
378
+ id: candidateId(obs.defectClass, obs.subject, mutations),
379
+ dimension: recipe.dimension,
380
+ lifecycle: 'proposed',
381
+ mutations,
382
+ });
383
+ }
384
+ return records;
385
+ }
386
+
387
+ /**
388
+ * The bytes written for one record.
389
+ *
390
+ * Two-space indent plus one trailing newline, matching what `bench_ab_clone`
391
+ * writes into the clone. The byte-identity acceptance test compares the output
392
+ * of THIS function, so the serialiser is part of the determinism claim rather
393
+ * than an incidental formatting choice at the call site.
394
+ */
395
+ export function serialiseCandidateRecord(record: CandidateRecord): string {
396
+ return `${JSON.stringify(candidateRecordToJson(record), null, 2)}\n`;
397
+ }
398
+
399
+ /** `<id>.json` — the filename a record is written under. */
400
+ export function candidateRecordFilename(record: CandidateRecord): string {
401
+ return `${record.id}.json`;
402
+ }