@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
@@ -24,6 +24,24 @@
24
24
  *
25
25
  * The clones tree (`internal/bench/ab/clones/`) is gitignored — only this script's
26
26
  * output schema is committed.
27
+ *
28
+ * ## The `candidate` variant
29
+ *
30
+ * `road-to-governed-harness-evolution` Phase 3 step 3.1. The roadmap's own
31
+ * `corrected-from-reproduction` note is why this is small: the master design
32
+ * described this script as living on a single "package present / absent" axis
33
+ * needing an axis extension, when `--variant` already carried three real
34
+ * variants whose third (`with-rdp`) sits on a different axis entirely. Adding a
35
+ * candidate is a new enum member on existing multi-variant machinery, NOT a new
36
+ * isolation mechanism.
37
+ *
38
+ * A candidate clone is `with` plus a validated set of mutations confined to the
39
+ * agent-config surface. Unlike the three fixed variants it is many-per-run, so
40
+ * it lands at `clones/candidate-<id>` and takes its id, dimension and lifecycle
41
+ * from a record file validated by `_lib/candidate_record.ts` BEFORE any bytes
42
+ * are copied. A mutation reaching outside the surface is refused there and
43
+ * again here against the resolved path; `bench_ab_integrity` is the third,
44
+ * independent check, over what actually landed on disk.
27
45
  */
28
46
 
29
47
  import { createHash } from 'node:crypto';
@@ -32,15 +50,53 @@ import * as path from 'node:path';
32
50
  import process from 'node:process';
33
51
  import { fileURLToPath, pathToFileURL } from 'node:url';
34
52
 
53
+ import {
54
+ type CandidateRecord,
55
+ PathOwnershipError,
56
+ assertMutationPathsOwned,
57
+ candidateRecordToJson,
58
+ parseCandidateRecord,
59
+ } from './_lib/candidate_record.js';
60
+
35
61
  const _HERE = fileURLToPath(import.meta.url);
36
62
  // Python: Path(__file__).resolve().parents[2] → repo root.
37
63
  const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
38
64
  const AB_ROOT = path.join(REPO_ROOT, 'internal', 'bench', 'ab');
39
65
  const FIXTURE = path.join(AB_ROOT, 'fixture');
40
- const CLONES = path.join(AB_ROOT, 'clones');
66
+ /**
67
+ * The clones tree. Exported so a caller can DISCOVER candidate clones without
68
+ * recomputing the path from the repo root — a fourth copy of that join is a
69
+ * fourth thing to keep in step with the two scripts that already hardcode it.
70
+ */
71
+ export const CLONES = path.join(AB_ROOT, 'clones');
41
72
 
42
73
  // Surfaces the `with` clone inherits from the package root.
43
- const WITH_SURFACES: readonly string[] = ['.claude', '.augment', 'AGENTS.md', 'CLAUDE.md'];
74
+ export const WITH_SURFACES: readonly string[] = ['.claude', '.augment', 'AGENTS.md', 'CLAUDE.md'];
75
+
76
+ /**
77
+ * Directory-name prefix for a candidate clone: `clones/candidate-<id>`.
78
+ *
79
+ * A candidate is NOT a fourth fixed variant sharing one directory the way
80
+ * `with` / `without` / `with-rdp` do — there are many candidates at once (the
81
+ * roadmap's exit criterion materialises five), so the id is part of the path.
82
+ * `bench_ab_integrity` discovers candidate roots by this prefix.
83
+ */
84
+ export const CANDIDATE_PREFIX = 'candidate-';
85
+
86
+ /**
87
+ * Filename of the candidate record dropped inside a candidate clone.
88
+ *
89
+ * Kept in sync with `bench_ab_integrity`'s `ALLOWED_DELTA_FILES` by
90
+ * `tests/scripts/candidate_surface_parity.test.ts` — a candidate clone
91
+ * legitimately carries a file the baseline does not, and integrity must know
92
+ * that before it can call anything else a violation.
93
+ */
94
+ export const CANDIDATE_RECORD_FILE = '.bench-ab-candidate.json';
95
+
96
+ /** Does this variant layer the agent-config surface onto the fixture? */
97
+ function _layersSurface(variant: string): boolean {
98
+ return variant === 'with' || variant === 'with-rdp' || variant === 'candidate';
99
+ }
44
100
 
45
101
  function die(msg: string): never {
46
102
  process.stderr.write(`bench_ab_clone: ${msg}\n`);
@@ -161,8 +217,8 @@ export function materialise_clone(variant: string, target: string): void {
161
217
  _copyStat(entry, dest);
162
218
  }
163
219
  }
164
- // Layer the agent-config surface onto the `with` + `with-rdp` variants
165
- if (variant === 'with' || variant === 'with-rdp') {
220
+ // Layer the agent-config surface onto the `with` + `with-rdp` + `candidate` variants
221
+ if (_layersSurface(variant)) {
166
222
  for (const surface of WITH_SURFACES) {
167
223
  const src = path.join(REPO_ROOT, surface);
168
224
  if (!_exists(src)) {
@@ -217,12 +273,115 @@ export function write_manifest(variant: string, target: string): void {
217
273
  variant,
218
274
  reasoning_enabled: variant === 'with-rdp',
219
275
  target_shape_hash: target_shape_hash(),
220
- with_surfaces: variant === 'with' || variant === 'with-rdp' ? [...WITH_SURFACES] : [],
276
+ with_surfaces: _layersSurface(variant) ? [...WITH_SURFACES] : [],
221
277
  fixture_relpath: path.relative(REPO_ROOT, FIXTURE).split(path.sep).join('/'),
222
278
  };
223
279
  fs.writeFileSync(path.join(target, '.bench-ab-manifest.json'), `${_pyJsonDumps(manifest, 2)}\n`, 'utf-8');
224
280
  }
225
281
 
282
+ /**
283
+ * Apply a candidate's mutations inside an already-materialised clone.
284
+ *
285
+ * Two refusals, and the order matters. `assertMutationPathsOwned` runs over the
286
+ * WHOLE set before the first byte is written, so a set whose third mutation
287
+ * escapes the surface leaves no half-mutated clone behind. Then each write is
288
+ * re-checked against the resolved absolute path, which catches the case the
289
+ * relative check cannot see: a symlink already inside `.claude/` pointing out
290
+ * of the clone. The relative form is what the record declares; the resolved
291
+ * form is what the filesystem would actually write, and a candidate that
292
+ * mutates the real package tree would corrupt the source of truth this whole
293
+ * programme is trying to evaluate.
294
+ *
295
+ * Throws rather than exiting so the resolved-path branch is reachable from a
296
+ * unit test — `main` turns it back into the CLI's exit 1. A guard that can only
297
+ * be exercised by killing the test process is a guard nobody has seen red.
298
+ *
299
+ * @throws {PathOwnershipError} on a declared or a resolved escape.
300
+ */
301
+ export function apply_candidate_mutations(record: CandidateRecord, target: string): void {
302
+ assertMutationPathsOwned(record.mutations);
303
+ const root = fs.realpathSync(target);
304
+ for (const m of record.mutations) {
305
+ const dest = path.join(target, m.path);
306
+ const parent = path.dirname(dest);
307
+ fs.mkdirSync(parent, { recursive: true });
308
+ const realParent = fs.realpathSync(parent);
309
+ if (realParent !== root && !realParent.startsWith(root + path.sep)) {
310
+ throw new PathOwnershipError(
311
+ `${m.path} (resolves to ${realParent}, outside candidate clone ${record.id})`,
312
+ );
313
+ }
314
+ fs.writeFileSync(dest, m.content, 'utf-8');
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Materialise ONE candidate clone at `clones/candidate-<id>`.
320
+ *
321
+ * The record is validated by `parseCandidateRecord` BEFORE anything is copied,
322
+ * so a candidate that violates the one-primary-dimension rule (3.2), names a
323
+ * fourth mutation dimension (3.3) or carries no lifecycle state (3.4) never
324
+ * reaches the filesystem. Validating after materialisation would leave a clone
325
+ * on disk that no schema admits.
326
+ *
327
+ * The clone's lifecycle state is recorded, never inferred: a candidate clone
328
+ * existing on disk says the candidate was MATERIALISED and nothing more.
329
+ */
330
+ export function clone_candidate(record: CandidateRecord, opts: { refresh: boolean; quiet?: boolean }): string {
331
+ const quiet = opts.quiet ?? false;
332
+ const target = path.join(CLONES, `${CANDIDATE_PREFIX}${record.id}`);
333
+ if (_exists(target) && !opts.refresh) {
334
+ if (!quiet) {
335
+ process.stdout.write(
336
+ `bench_ab_clone: candidate ${record.id} clone already present at ${target} (use --refresh to rebuild)\n`,
337
+ );
338
+ }
339
+ return target;
340
+ }
341
+ if (_exists(target)) {
342
+ fs.rmSync(target, { recursive: true, force: true });
343
+ }
344
+ materialise_clone('candidate', target);
345
+ apply_candidate_mutations(record, target);
346
+ write_manifest('candidate', target);
347
+ fs.writeFileSync(
348
+ path.join(target, CANDIDATE_RECORD_FILE),
349
+ `${_pyJsonDumps(candidateRecordToJson(record), 2)}\n`,
350
+ 'utf-8',
351
+ );
352
+ if (!quiet) {
353
+ process.stdout.write(`bench_ab_clone: built candidate ${record.id} clone at ${target}\n`);
354
+ }
355
+ return target;
356
+ }
357
+
358
+ /**
359
+ * Load and validate a candidate record file.
360
+ *
361
+ * A malformed record exits 1 with the schema's own message rather than a
362
+ * generic parse error — the schema messages name which invariant was broken,
363
+ * and an operator holding a rejected record needs that, not a line number.
364
+ */
365
+ export function load_candidate_record(file: string): CandidateRecord {
366
+ let raw: string;
367
+ try {
368
+ raw = fs.readFileSync(file, 'utf-8');
369
+ } catch {
370
+ die(`candidate record not readable at ${file}`);
371
+ }
372
+ let parsed: unknown;
373
+ try {
374
+ parsed = JSON.parse(raw);
375
+ } catch (e) {
376
+ die(`candidate record at ${file} is not valid JSON: ${(e as Error).message}`);
377
+ }
378
+ try {
379
+ return parseCandidateRecord(parsed);
380
+ } catch (e) {
381
+ die(`candidate record at ${file} rejected — ${(e as Error).message}`);
382
+ }
383
+ }
384
+
226
385
  export function clone(variant: string, opts: { refresh: boolean; quiet?: boolean }): string {
227
386
  const quiet = opts.quiet ?? false;
228
387
  const target = path.join(CLONES, variant);
@@ -245,18 +404,21 @@ export function clone(variant: string, opts: { refresh: boolean; quiet?: boolean
245
404
  return target;
246
405
  }
247
406
 
248
- type Variant = 'with' | 'without' | 'with-rdp' | 'both' | 'all';
407
+ type Variant = 'with' | 'without' | 'with-rdp' | 'candidate' | 'both' | 'all';
249
408
 
250
409
  interface ParsedArgs {
251
410
  refresh: boolean;
252
411
  variant: Variant;
253
412
  print_shape_hash: boolean;
413
+ /** Paths to candidate record files; only meaningful with `--variant candidate`. */
414
+ candidate_records: string[];
254
415
  }
255
416
 
256
417
  export function parse_args(argv: string[]): ParsedArgs {
257
418
  let refresh = false;
258
419
  let variant: Variant = 'both';
259
420
  let print_shape_hash = false;
421
+ const candidate_records: string[] = [];
260
422
  let i = 0;
261
423
  while (i < argv.length) {
262
424
  const arg = argv[i] as string;
@@ -284,23 +446,38 @@ export function parse_args(argv: string[]): ParsedArgs {
284
446
  i += 1;
285
447
  continue;
286
448
  }
449
+ if (arg === '--candidate-record') {
450
+ const next = argv[i + 1];
451
+ if (next === undefined) {
452
+ _argparseError('argument --candidate-record: expected one argument');
453
+ }
454
+ candidate_records.push(next);
455
+ i += 2;
456
+ continue;
457
+ }
458
+ if (arg.startsWith('--candidate-record=')) {
459
+ candidate_records.push(arg.slice('--candidate-record='.length));
460
+ i += 1;
461
+ continue;
462
+ }
287
463
  if (arg === '-h' || arg === '--help') {
288
464
  process.stdout.write(
289
- 'usage: bench_ab_clone [-h] [--refresh] [--variant {with,without,with-rdp,both,all}] [--print-shape-hash]\n',
465
+ 'usage: bench_ab_clone [-h] [--refresh] [--variant {with,without,with-rdp,candidate,both,all}] ' +
466
+ '[--candidate-record PATH] [--print-shape-hash]\n',
290
467
  );
291
468
  process.exit(0);
292
469
  }
293
470
  _argparseError(`unrecognized arguments: ${arg}`);
294
471
  }
295
- return { refresh, variant, print_shape_hash };
472
+ return { refresh, variant, print_shape_hash, candidate_records };
296
473
  }
297
474
 
298
475
  function _checkVariant(v: string): Variant {
299
- if (v === 'with' || v === 'without' || v === 'with-rdp' || v === 'both' || v === 'all') {
476
+ if (v === 'with' || v === 'without' || v === 'with-rdp' || v === 'candidate' || v === 'both' || v === 'all') {
300
477
  return v;
301
478
  }
302
479
  _argparseError(
303
- `argument --variant: invalid choice: ${_pyRepr(v)} (choose from 'with', 'without', 'with-rdp', 'both', 'all')`,
480
+ `argument --variant: invalid choice: ${_pyRepr(v)} (choose from 'with', 'without', 'with-rdp', 'candidate', 'both', 'all')`,
304
481
  );
305
482
  }
306
483
 
@@ -318,10 +495,38 @@ export function main(argv?: string[]): number {
318
495
  process.stdout.write(`${target_shape_hash()}\n`);
319
496
  return 0;
320
497
  }
498
+ if (args.candidate_records.length > 0 && args.variant !== 'candidate') {
499
+ _argparseError('--candidate-record requires --variant candidate');
500
+ }
501
+ if (args.variant === 'candidate') {
502
+ if (args.candidate_records.length === 0) {
503
+ _argparseError('--variant candidate requires at least one --candidate-record PATH');
504
+ }
505
+ const seen = new Set<string>();
506
+ for (const file of args.candidate_records) {
507
+ const record = load_candidate_record(file);
508
+ if (seen.has(record.id)) {
509
+ die(`candidate id '${record.id}' given twice — ids name clone directories and must be unique`);
510
+ }
511
+ seen.add(record.id);
512
+ try {
513
+ clone_candidate(record, { refresh: args.refresh });
514
+ } catch (e) {
515
+ if (e instanceof PathOwnershipError) {
516
+ die(`candidate ${record.id} rejected — ${e.message}`);
517
+ }
518
+ throw e;
519
+ }
520
+ }
521
+ return 0;
522
+ }
321
523
  let variants: readonly string[];
322
524
  if (args.variant === 'both') {
323
525
  variants = ['with', 'without'];
324
526
  } else if (args.variant === 'all') {
527
+ // Deliberately NOT extended with candidates: a candidate needs a record
528
+ // to know its dimension and lifecycle, so there is no blind aggregate
529
+ // that could produce one. `all` keeps meaning the three fixed variants.
325
530
  variants = ['with', 'without', 'with-rdp'];
326
531
  } else {
327
532
  variants = [args.variant];
@@ -21,6 +21,20 @@
21
21
  * 0 — clones are identical except at the allowed surface
22
22
  * 1 — clone is missing, or a task-target file diverges between variants
23
23
  * 2 — usage error
24
+ *
25
+ * ## Candidate clones
26
+ *
27
+ * `road-to-governed-harness-evolution` Phase 3 step 3.1 requires this check to
28
+ * keep asserting byte-wise once candidates exist. Every `clones/candidate-*`
29
+ * directory is compared against the SAME `without` baseline, by DISCOVERY
30
+ * rather than from a passed list — a candidate this script was never told about
31
+ * is precisely what a path-ownership check has to catch.
32
+ *
33
+ * This is the third and only independent check on candidate path ownership.
34
+ * `_lib/candidate_record.ts` refuses an unowned path in the record, and
35
+ * `bench_ab_clone` refuses one again against the resolved path at write time;
36
+ * both reason about what the candidate DECLARED. This one reads what is on
37
+ * disk, so it still fires when a mutation arrived by some other route.
24
38
  */
25
39
 
26
40
  import { createHash } from 'node:crypto';
@@ -36,10 +50,19 @@ const AB_ROOT = path.join(REPO_ROOT, 'internal', 'bench', 'ab');
36
50
  const CLONES = path.join(AB_ROOT, 'clones');
37
51
 
38
52
  // Surfaces where divergence is expected (variant-bearing).
39
- const ALLOWED_DELTA_PATHS: readonly string[] = ['.claude', '.augment', 'AGENTS.md', 'CLAUDE.md'];
40
- // Variant-distinguishing files written by bench_ab_clone (the manifest and the
41
- // RDP-toggle settings file — both legitimately differ between variants).
42
- const ALLOWED_DELTA_FILES: readonly string[] = ['.bench-ab-manifest.json', '.agent-settings.yml'];
53
+ export const ALLOWED_DELTA_PATHS: readonly string[] = ['.claude', '.augment', 'AGENTS.md', 'CLAUDE.md'];
54
+ // Variant-distinguishing files written by bench_ab_clone (the manifest, the
55
+ // RDP-toggle settings file and the candidate record — all three legitimately
56
+ // differ between variants). Kept in sync with bench_ab_clone's
57
+ // CANDIDATE_RECORD_FILE by tests/scripts/candidate_surface_parity.test.ts.
58
+ export const ALLOWED_DELTA_FILES: readonly string[] = [
59
+ '.bench-ab-manifest.json',
60
+ '.agent-settings.yml',
61
+ '.bench-ab-candidate.json',
62
+ ];
63
+
64
+ /** Directory-name prefix identifying a candidate clone (see bench_ab_clone). */
65
+ export const CANDIDATE_PREFIX = 'candidate-';
43
66
 
44
67
  export function is_under_allowed_path(rel: string): boolean {
45
68
  // Python: Path(rel).parts; head = parts[0].
@@ -111,6 +134,61 @@ function _argparseError(msg: string): never {
111
134
  process.exit(2);
112
135
  }
113
136
 
137
+ /** The three divergence classes between one variant and the baseline. */
138
+ export interface Divergence {
139
+ readonly onlyInVariant: string[];
140
+ readonly onlyInBaseline: string[];
141
+ readonly byteDivergent: string[];
142
+ }
143
+
144
+ /**
145
+ * Compare one variant's file index against the baseline's.
146
+ *
147
+ * Every returned path is already filtered through {@link is_under_allowed_path},
148
+ * so a non-empty list is a violation and not a delta to be judged again by the
149
+ * caller.
150
+ */
151
+ export function compare_indexes(
152
+ variant: Record<string, string>,
153
+ baseline: Record<string, string>,
154
+ ): Divergence {
155
+ const vKeys = Object.keys(variant);
156
+ const bKeys = Object.keys(baseline);
157
+ return {
158
+ onlyInVariant: _sortedDifference(vKeys, bKeys).filter((rel) => !is_under_allowed_path(rel)),
159
+ onlyInBaseline: _sortedDifference(bKeys, vKeys).filter((rel) => !is_under_allowed_path(rel)),
160
+ byteDivergent: _sortedIntersection(vKeys, bKeys).filter(
161
+ (rel) => variant[rel] !== baseline[rel] && !is_under_allowed_path(rel),
162
+ ),
163
+ };
164
+ }
165
+
166
+ export function divergence_is_clean(d: Divergence): boolean {
167
+ return d.onlyInVariant.length === 0 && d.onlyInBaseline.length === 0 && d.byteDivergent.length === 0;
168
+ }
169
+
170
+ /**
171
+ * Candidate clone directory names under `clones/`, sorted.
172
+ *
173
+ * Discovery by prefix rather than by a passed list is deliberate: the check
174
+ * must see a candidate clone that no caller told it about. A candidate written
175
+ * into the clones tree by a path this script does not know is exactly the
176
+ * failure a path-ownership check exists to catch, and an allowlist-driven
177
+ * discovery would look right while never enumerating it.
178
+ */
179
+ export function discover_candidate_clones(clonesRoot: string): string[] {
180
+ let entries: fs.Dirent[];
181
+ try {
182
+ entries = fs.readdirSync(clonesRoot, { withFileTypes: true });
183
+ } catch {
184
+ return [];
185
+ }
186
+ return entries
187
+ .filter((e) => e.isDirectory() && e.name.startsWith(CANDIDATE_PREFIX))
188
+ .map((e) => e.name)
189
+ .sort(_strCmp);
190
+ }
191
+
114
192
  export function main(argv?: string[]): number {
115
193
  const args = parse_args(argv ?? process.argv.slice(2));
116
194
 
@@ -152,7 +230,31 @@ export function main(argv?: string[]): number {
152
230
  );
153
231
  }
154
232
 
155
- if (bad_only_with.length === 0 && bad_only_without.length === 0 && bad_diff.length === 0) {
233
+ // Candidate clones (Phase 3 step 3.1). Each is compared against the SAME
234
+ // `without` baseline the `with` clone is compared against — not against
235
+ // `with`, which would let a candidate inherit an unnoticed `with` violation
236
+ // and read as clean.
237
+ const candidateFailures: { name: string; divergence: Divergence }[] = [];
238
+ for (const name of discover_candidate_clones(CLONES)) {
239
+ const root = path.join(CLONES, name);
240
+ const index = index_clone(root);
241
+ if (args.verbose) {
242
+ process.stdout.write(
243
+ `bench_ab_integrity: ${name}=${Object.keys(index).length} files (vs without)\n`,
244
+ );
245
+ }
246
+ const divergence = compare_indexes(index, without_index);
247
+ if (!divergence_is_clean(divergence)) {
248
+ candidateFailures.push({ name, divergence });
249
+ }
250
+ }
251
+
252
+ if (
253
+ bad_only_with.length === 0 &&
254
+ bad_only_without.length === 0 &&
255
+ bad_diff.length === 0 &&
256
+ candidateFailures.length === 0
257
+ ) {
156
258
  process.stdout.write(
157
259
  'bench_ab_integrity: clones differ only at the allowed surface (.claude, .augment, AGENTS.md, CLAUDE.md, manifest).\n',
158
260
  );
@@ -178,6 +280,18 @@ export function main(argv?: string[]): number {
178
280
  process.stderr.write(` ~ ${rel}\n`);
179
281
  }
180
282
  }
283
+ for (const { name, divergence } of candidateFailures) {
284
+ process.stderr.write(` candidate '${name}' escaped the candidate surface (vs without):\n`);
285
+ for (const rel of divergence.onlyInVariant) {
286
+ process.stderr.write(` + ${rel}\n`);
287
+ }
288
+ for (const rel of divergence.onlyInBaseline) {
289
+ process.stderr.write(` - ${rel}\n`);
290
+ }
291
+ for (const rel of divergence.byteDivergent) {
292
+ process.stderr.write(` ~ ${rel}\n`);
293
+ }
294
+ }
181
295
  return 1;
182
296
  }
183
297