@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
@@ -13,6 +13,8 @@
13
13
  * change to either has to touch the record and the code together.
14
14
  */
15
15
 
16
+ import { decidePairedVerdict, floorWarning, MIN_DISCORDANT } from './paired_verdict.js';
17
+
16
18
  /** T1 — median added lines must fall by at least this much. */
17
19
  export const T1_MEDIAN_LINES_PCT = -10;
18
20
  /** Two-sided significance for every endpoint in the pair. */
@@ -25,7 +27,15 @@ export interface PairedContinuous {
25
27
  /** `null` when the baseline median is 0 — no percent change exists. */
26
28
  median_delta_pct: number | null;
27
29
  median_delta: number;
30
+ /**
31
+ * Retained for TRIAGE and reporting. Since PREREG amendment v2 it decides
32
+ * nothing — see {@link evaluateSizeClaim}.
33
+ */
28
34
  wilcoxon_p: number;
35
+ /** Non-tied pairs in the direction of interest. Absent on a pre-amendment report. */
36
+ direction_wins?: number | undefined;
37
+ /** Non-tied pairs against the direction of interest. Absent on a pre-amendment report. */
38
+ direction_losses?: number | undefined;
29
39
  }
30
40
 
31
41
  /** A paired binary endpoint (the safety tier). */
@@ -56,6 +66,44 @@ export interface SizeClaimVerdict {
56
66
  safety_measured: boolean;
57
67
  }
58
68
 
69
+
70
+
71
+ /** One clause naming the directional evidence, printable in a verdict reason. */
72
+ function describeDirection(v: ReturnType<typeof decidePairedVerdict> | null): string {
73
+ if (v === null) {
74
+ return `no direction counts in the report — pre-amendment or unmeasured, so the direction bar is not met`;
75
+ }
76
+ if (v.kind === 'underpowered') {
77
+ return `underpowered: ${String(v.discordant)} non-tied pair(s) below the derived floor of ${String(MIN_DISCORDANT)}`;
78
+ }
79
+ const warn = floorWarning(v);
80
+ return `${String(v.wins)}/${String(v.discordant)} non-tied pairs, one-sided exact p=${v.p.toFixed(4)}` +
81
+ (warn === null ? '' : ` — ${warn}`);
82
+ }
83
+
84
+ /**
85
+ * The directional verdict for one endpoint, or `null` when it cannot be formed.
86
+ *
87
+ * `null` means the report carries no direction counts — a pre-amendment report,
88
+ * or an unmeasured endpoint. The caller treats that as "not significant" rather
89
+ * than reaching for `wilcoxon_p`, which is the whole point of the amendment.
90
+ *
91
+ * The counts are reconstructed into a delta vector of ±1 rather than carrying
92
+ * raw deltas through the report: the exact sign test needs direction only, and
93
+ * a council seat noted the raw deltas are preferable for auditability but not
94
+ * mathematically required. The raw values remain in the trial artifacts.
95
+ */
96
+ function directionVerdict(e: PairedContinuous): ReturnType<typeof decidePairedVerdict> | null {
97
+ if (!e.measured) return null;
98
+ const w = e.direction_wins;
99
+ const l = e.direction_losses;
100
+ if (w === undefined || l === undefined) return null;
101
+ return decidePairedVerdict({
102
+ deltas: [...Array<number>(w).fill(1), ...Array<number>(l).fill(-1)],
103
+ alpha: ALPHA,
104
+ });
105
+ }
106
+
59
107
  /**
60
108
  * Evaluate the size claim for one comparison — binding, and structurally unable
61
109
  * to report a win on size alone.
@@ -98,9 +146,52 @@ export function evaluateSizeClaim(input: SizeClaimInput): SizeClaimVerdict {
98
146
  };
99
147
  }
100
148
 
101
- const cx_rose = cx.measured && cx.median_delta > 0 && cx.wilcoxon_p < ALPHA;
149
+ // ── PREREG amendment v2, 2026-08-26 — direction decides significance ────
150
+ //
151
+ // The significance half of every endpoint below was a Wilcoxon signed-rank
152
+ // p, which ranks by |difference| and is therefore magnitude-weighted. That
153
+ // was shown to disagree with the exact test on twelve records up to ten
154
+ // trials, PERMISSIVE in every one, with the visible symptom inverted: an
155
+ // artifact winning every trial still failed, because a few large
156
+ // opposite-direction deltas outweighed a clean sweep of small ones.
157
+ //
158
+ // TWO PROPOSITIONS, KEPT SEPARATE — this is the refinement both council
159
+ // seats independently required (2026-08-26, 2/2) and it is the half that
160
+ // makes the amendment safe. A sign test answers "did this help more often
161
+ // than it hurt" and says NOTHING about how much. Replacing Wilcoxon with it
162
+ // outright would let a clean sweep of negligible improvements claim a SIZE
163
+ // win. So:
164
+ // · directional reliability → exact one-sided sign test over non-tied pairs
165
+ // · practical magnitude → the pre-registered T1_MEDIAN_LINES_PCT bar,
166
+ // unchanged and still independently binding
167
+ // Both must hold. Dropping either is a different claim and needs its own
168
+ // amendment.
169
+ //
170
+ // A report predating the amendment carries no direction counts. It is
171
+ // treated as UNMEASURED for the significance half rather than falling back
172
+ // to `wilcoxon_p`, because a silent fallback to the defective test is
173
+ // exactly what this amendment removes.
174
+ const sizeDir = directionVerdict(size);
175
+ const cxDir = directionVerdict(cx);
176
+ // ASYMMETRY, deliberate and the conservative direction of it. A PASS needs
177
+ // the direction bar MET; a REFUSAL fires on EITHER signal. Applying the
178
+ // strict reading to both would make the anti-golfing refusal disappear on
179
+ // any report without direction counts — a missing input silently rescuing
180
+ // an arm is the failure mode a refusal exists to prevent, and it is the
181
+ // opposite of what the amendment is for. So the refusal keeps the legacy
182
+ // Wilcoxon signal as a second trigger; the claim does not.
183
+ const cx_rose =
184
+ cx.measured &&
185
+ cx.median_delta > 0 &&
186
+ (cxDir === null ? cx.wilcoxon_p < ALPHA : cxDir.kind === 'regression');
187
+ // `regression`, NOT `pass`, and the distinction cost a test run to find.
188
+ // `direction_wins` counts the endpoint's IMPROVEMENT direction — a negative
189
+ // delta — for every continuous endpoint, so on complexity a `pass` means
190
+ // complexity FELL. What `cx_rose` needs is the opposite tail, which is
191
+ // exactly what `regression` names. Writing `pass` here reads correctly in
192
+ // English and inverts the anti-golfing guard.
102
193
  const pct = size.measured ? size.median_delta_pct : null;
103
- const lines_fell = pct !== null && pct <= T1_MEDIAN_LINES_PCT && size.wilcoxon_p < ALPHA;
194
+ const lines_fell = pct !== null && pct <= T1_MEDIAN_LINES_PCT && sizeDir?.kind === 'pass';
104
195
 
105
196
  // (2b) Golfing is refused as soon as T2 shows it, and does NOT wait for T4.
106
197
  //
@@ -161,8 +252,11 @@ export function evaluateSizeClaim(input: SizeClaimInput): SizeClaimVerdict {
161
252
  ...base,
162
253
  verdict: lines_fell ? 'PASS' : 'NO-SIZE-WIN',
163
254
  reason: lines_fell
164
- ? `median added lines ${pct}% at p=${size.wilcoxon_p} with no significant complexity rise and no safety regression`
165
- : `T1 not met (median added lines ${pct}% at p=${size.wilcoxon_p}; bar is <= ${T1_MEDIAN_LINES_PCT}% at p<${ALPHA})`,
255
+ ? `median added lines ${pct}% (magnitude bar) AND ${describeDirection(sizeDir)} (direction bar) ` +
256
+ 'with no significant complexity rise and no safety regression'
257
+ : `T1 not met (median added lines ${pct}%, bar <= ${T1_MEDIAN_LINES_PCT}%; ` +
258
+ `direction: ${describeDirection(sizeDir)}). Wilcoxon p=${size.wilcoxon_p} is reported for ` +
259
+ 'triage and decides nothing.',
166
260
  lines_fell,
167
261
  size_measured: true,
168
262
  complexity_measured: true,
@@ -0,0 +1,158 @@
1
+ /**
2
+ * The `cache` block of a benchmark / cost report — required fields, and the one
3
+ * legitimate way to not have a number (`road-to-runtime-context-floors` step 4.1).
4
+ *
5
+ * Both fields are REQUIRED. A report that cannot compute one states a reason; it
6
+ * does not omit the key and it does not emit a zero. A blank reads as "no cache
7
+ * activity" and a zero reads as "the worst possible ratio" — both are claims, and
8
+ * neither is the claim "this was not measured".
9
+ *
10
+ * Contract: `docs/contracts/benchmark-report-schema.md` § The `cache` block.
11
+ */
12
+
13
+ export const REQUIRED_CACHE_FIELDS = ['read_write_ratio', 'stable_prefix_share'] as const;
14
+ export type RequiredCacheField = (typeof REQUIRED_CACHE_FIELDS)[number];
15
+
16
+ /**
17
+ * What produced the report (`road-to-delivered-cost-truth` step 4.2).
18
+ *
19
+ * A benchmark number without its provenance cannot be reproduced or challenged,
20
+ * and this repository carries a measured instance of that failure: an external
21
+ * round's headline figures are recorded `unverifiable` precisely because the run
22
+ * behind them is unreachable. These four keep a report here from becoming that.
23
+ */
24
+ export const REQUIRED_PROVENANCE_FIELDS = [
25
+ 'host_binary_hash',
26
+ 'harness_commit',
27
+ 'harness_dirty',
28
+ 'reproducibility',
29
+ ] as const;
30
+ export type RequiredProvenanceField = (typeof REQUIRED_PROVENANCE_FIELDS)[number];
31
+
32
+ /** A measured number, or a stated reason there is none. Never a bare absence. */
33
+ export type CacheFieldValue = number | { unavailable: string };
34
+
35
+ export interface CacheBlock {
36
+ read_write_ratio: CacheFieldValue;
37
+ stable_prefix_share: CacheFieldValue;
38
+ }
39
+
40
+ export type AnyRequiredField = RequiredCacheField | RequiredProvenanceField;
41
+
42
+ export type FieldProblem =
43
+ | { field: AnyRequiredField; kind: 'missing' }
44
+ | { field: AnyRequiredField; kind: 'blank-unavailable' }
45
+ | { field: AnyRequiredField; kind: 'not-a-number'; value: unknown }
46
+ | { field: AnyRequiredField; kind: 'out-of-range'; value: number }
47
+ | { field: AnyRequiredField; kind: 'blank-value' };
48
+
49
+ export function unavailable(reason: string): CacheFieldValue {
50
+ return { unavailable: reason };
51
+ }
52
+
53
+ function validateField(field: RequiredCacheField, raw: unknown): FieldProblem | null {
54
+ if (raw === undefined || raw === null) return { field, kind: 'missing' };
55
+ if (typeof raw === 'object') {
56
+ const reason = (raw as { unavailable?: unknown }).unavailable;
57
+ if (typeof reason !== 'string' || reason.trim().length === 0) {
58
+ return { field, kind: 'blank-unavailable' };
59
+ }
60
+ return null;
61
+ }
62
+ if (typeof raw !== 'number' || !Number.isFinite(raw)) return { field, kind: 'not-a-number', value: raw };
63
+ // A share is a fraction; a ratio is unbounded above but never negative.
64
+ if (raw < 0) return { field, kind: 'out-of-range', value: raw };
65
+ if (field === 'stable_prefix_share' && raw > 1) return { field, kind: 'out-of-range', value: raw };
66
+ return null;
67
+ }
68
+
69
+ /** Validate a report's `cache` block. Empty array = valid. */
70
+ export function validateCacheBlock(report: unknown): FieldProblem[] {
71
+ const cache = (report as { cache?: unknown } | null)?.cache;
72
+ if (cache === undefined || cache === null || typeof cache !== 'object') {
73
+ return REQUIRED_CACHE_FIELDS.map((field) => ({ field, kind: 'missing' as const }));
74
+ }
75
+ const rec = cache as Record<string, unknown>;
76
+ return REQUIRED_CACHE_FIELDS.map((f) => validateField(f, rec[f])).filter((p): p is FieldProblem => p !== null);
77
+ }
78
+
79
+ function blockOf(field: AnyRequiredField): string {
80
+ return (REQUIRED_PROVENANCE_FIELDS as readonly string[]).includes(field) ? 'provenance' : 'cache';
81
+ }
82
+
83
+ export function describeProblem(p: FieldProblem): string {
84
+ const q = `${blockOf(p.field)}.${p.field}`;
85
+ switch (p.kind) {
86
+ case 'missing':
87
+ return `${q} is missing — it is required; emit { unavailable: "<reason>" } when it cannot be supplied`;
88
+ case 'blank-unavailable':
89
+ return `${q} declares itself unavailable with no reason — a reason is the whole point of the form`;
90
+ case 'blank-value':
91
+ return `${q} is an empty string, which states nothing; emit { unavailable: "<reason>" } instead`;
92
+ case 'not-a-number':
93
+ return `${q} is ${JSON.stringify(p.value)}, which is neither a number nor { unavailable: "<reason>" }`;
94
+ case 'out-of-range':
95
+ return `${q} is ${String(p.value)}, outside its valid range`;
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Validate a report's `provenance` block.
101
+ *
102
+ * `harness_dirty` is a BOOLEAN and the others are strings, so the shape check is
103
+ * per-field rather than uniform — and `false` must pass, which a truthiness
104
+ * check would silently reject. That is the bug this comment exists to prevent on
105
+ * the next edit: a dirty flag of `false` is the good case.
106
+ */
107
+ export function validateProvenanceBlock(report: unknown): FieldProblem[] {
108
+ const block = (report as { provenance?: unknown } | null)?.provenance;
109
+ if (block === undefined || block === null || typeof block !== 'object') {
110
+ return REQUIRED_PROVENANCE_FIELDS.map((field) => ({ field, kind: 'missing' as const }));
111
+ }
112
+ const rec = block as Record<string, unknown>;
113
+ const out: FieldProblem[] = [];
114
+ for (const field of REQUIRED_PROVENANCE_FIELDS) {
115
+ const raw = rec[field];
116
+ if (raw === undefined || raw === null) {
117
+ out.push({ field, kind: 'missing' });
118
+ continue;
119
+ }
120
+ if (typeof raw === 'object') {
121
+ const reason = (raw as { unavailable?: unknown }).unavailable;
122
+ if (typeof reason !== 'string' || reason.trim().length === 0) out.push({ field, kind: 'blank-unavailable' });
123
+ continue;
124
+ }
125
+ if (field === 'harness_dirty') {
126
+ if (typeof raw !== 'boolean') out.push({ field, kind: 'not-a-number', value: raw });
127
+ continue;
128
+ }
129
+ if (typeof raw !== 'string') out.push({ field, kind: 'not-a-number', value: raw });
130
+ else if (raw.trim().length === 0) out.push({ field, kind: 'blank-value' });
131
+ }
132
+ return out;
133
+ }
134
+
135
+ /**
136
+ * Compute the ratio from token totals, or state why not.
137
+ *
138
+ * Zero cache-creation tokens is the interesting case: the ratio is undefined,
139
+ * not infinite and not zero, and the honest report says so.
140
+ */
141
+ export function readWriteRatio(cacheRead: number, cacheCreation: number): CacheFieldValue {
142
+ if (!Number.isFinite(cacheRead) || !Number.isFinite(cacheCreation)) {
143
+ return unavailable('the session source carries no cache_read/cache_creation token fields');
144
+ }
145
+ if (cacheCreation === 0) {
146
+ return unavailable('no cache-creation tokens were recorded in this window, so the ratio is undefined rather than zero');
147
+ }
148
+ return cacheRead / cacheCreation;
149
+ }
150
+
151
+ /** The STABLE cohort as a fraction of dispatches carrying the field, or why not. */
152
+ export function stablePrefixShare(stableN: number, unstableN: number): CacheFieldValue {
153
+ const total = stableN + unstableN;
154
+ if (total === 0) {
155
+ return unavailable('no dispatch in this window recorded both payload_hash and cache_hit');
156
+ }
157
+ return stableN / total;
158
+ }
@@ -0,0 +1,349 @@
1
+ /**
2
+ * The missing seam: two candidate records over one observation, and one signed
3
+ * delta per trial.
4
+ *
5
+ * A recorded search over this tree established that nothing read two
6
+ * {@link CandidateRecord}s and emitted a delta, a {@link PairedVerdict} or a
7
+ * {@link MetricVector}. The only live `decidePairedVerdict` caller runs over
8
+ * benchmark task pairs, the only paired-row construction is a deserialiser, and
9
+ * the evaluation cascade takes its vector from the caller. So the comparison a
10
+ * two-arm proposer experiment needs had no producer at all: the verdict
11
+ * function existed and nothing could feed it from candidates.
12
+ *
13
+ * This module is that producer, and it is deliberately the only thing it is.
14
+ *
15
+ * Everything about the SHAPE of the comparison is derived from constants
16
+ * committed before either arm existed: the sign convention from
17
+ * {@link PairedInput}'s own contract, the direction handling from
18
+ * {@link MetricDirection}, the tie epsilon from the value the A/B report
19
+ * already uses, the aggregation and the significance bar from
20
+ * {@link decidePairedVerdict}. What is NOT here is the outcome scalar itself.
21
+ * {@link TrialOutcome} is supplied by a caller, because choosing what a trial
22
+ * MEASURES is the one decision in this experiment that could favour an arm, and
23
+ * a module that invented one would be answering it in the wrong place. The
24
+ * artifact-count delta is supplied on the same terms and for a sharper reason:
25
+ * the pairing makes every pair-derived path count differ by exactly 0, so a
26
+ * derivation here would report a constant and call it a measurement.
27
+ *
28
+ * The honest consequence, stated rather than left to be discovered: this
29
+ * producer has no live population today. No shipped evaluator emits a
30
+ * {@link TrialOutcome} for a candidate over the frozen corpus, so every test
31
+ * here supplies its own. A producer with no population is exactly as honest as
32
+ * a guard with no caller, and the same disclosure applies.
33
+ */
34
+
35
+ import type { CandidateRecord } from './candidate_record.js';
36
+ import {
37
+ ARTIFACT_COUNT_METRIC,
38
+ buildVector,
39
+ type MetricDirection,
40
+ type MetricRow,
41
+ type MetricVector,
42
+ } from './evaluation_vector.js';
43
+ import { decidePairedVerdict, type PairedVerdict } from './paired_verdict.js';
44
+
45
+ /**
46
+ * Deltas within this of zero are ties.
47
+ *
48
+ * NOT chosen here: it is the value the A/B report's own direction counts
49
+ * already use, and its reason is recorded there, that two definitions of a tie
50
+ * in one report is how the numbers start disagreeing. Restating that value
51
+ * rather than picking a fresh one keeps a candidate comparison and a bench
52
+ * comparison answering to the same notion of no difference.
53
+ */
54
+ export const TIE_EPSILON = 1e-9;
55
+
56
+ export class PairingError extends Error {
57
+ constructor(message: string) {
58
+ super(message);
59
+ this.name = 'PairingError';
60
+ }
61
+ }
62
+
63
+ /**
64
+ * The pairing key, derived from the record alone.
65
+ *
66
+ * A record carries no observation field, so the key is reconstructed from what
67
+ * it does carry: the mutation dimension and the sorted mutation paths. That is
68
+ * exactly the observation identity for this experiment, because each fixed
69
+ * recipe owns one dimension and each observation names one subject. Keying on
70
+ * the candidate id would pair nothing, since an id hashes the mutated bytes, so
71
+ * two arms that produced different text have different ids by construction,
72
+ * which is the whole reason there is something to compare.
73
+ */
74
+ export function pairingKey(record: CandidateRecord): string {
75
+ const paths = record.mutations.map((m) => m.path).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
76
+ return `${record.dimension} ${paths.join(' ')}`;
77
+ }
78
+
79
+ export interface CandidatePair {
80
+ readonly key: string;
81
+ readonly control: CandidateRecord;
82
+ readonly treatment: CandidateRecord;
83
+ /**
84
+ * The arms produced byte-identical mutations.
85
+ *
86
+ * Not an error and not silently dropped. It means every trial on this pair
87
+ * is a structural tie, so the pair contributes to the trial count and to no
88
+ * discordant count, and a reader who sees `underpowered` without this flag
89
+ * would look for the cause in the measurement rather than in the arms.
90
+ */
91
+ readonly identical_arms: boolean;
92
+ }
93
+
94
+ function serialiseMutations(r: CandidateRecord): string {
95
+ return [...r.mutations]
96
+ .sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0))
97
+ .map((m) => `${m.path} ${m.content}`)
98
+ .join('');
99
+ }
100
+
101
+ /**
102
+ * Pair two arms' record sets, refusing every shape where half a pair exists.
103
+ *
104
+ * An unmatched record on either side is refused rather than dropped. Dropping
105
+ * it would make the trial count depend on which observations each arm happened
106
+ * to satisfy, and a comparison whose denominator is chosen by one of the arms
107
+ * is not a paired comparison.
108
+ */
109
+ export function pairCandidates(
110
+ control: readonly CandidateRecord[],
111
+ treatment: readonly CandidateRecord[],
112
+ ): CandidatePair[] {
113
+ const byKey = new Map<string, CandidateRecord>();
114
+ for (const r of treatment) {
115
+ const k = pairingKey(r);
116
+ if (byKey.has(k)) {
117
+ throw new PairingError(
118
+ `treatment arm emitted two records for '${k}': one observation is one candidate ` +
119
+ 'per arm, and a second would make the pairing pick a winner before any trial ran',
120
+ );
121
+ }
122
+ byKey.set(k, r);
123
+ }
124
+ const out: CandidatePair[] = [];
125
+ const seen = new Set<string>();
126
+ for (const c of control) {
127
+ const k = pairingKey(c);
128
+ if (seen.has(k)) {
129
+ throw new PairingError(`control arm emitted two records for '${k}'`);
130
+ }
131
+ seen.add(k);
132
+ const t = byKey.get(k);
133
+ if (t === undefined) {
134
+ throw new PairingError(
135
+ `no treatment record for '${k}': half a pair is no result, not a partial one`,
136
+ );
137
+ }
138
+ out.push({
139
+ key: k,
140
+ control: c,
141
+ treatment: t,
142
+ identical_arms: serialiseMutations(c) === serialiseMutations(t),
143
+ });
144
+ }
145
+ for (const k of byKey.keys()) {
146
+ if (!seen.has(k)) {
147
+ throw new PairingError(
148
+ `no control record for '${k}': the treatment arm ran an observation the control did not`,
149
+ );
150
+ }
151
+ }
152
+ return out;
153
+ }
154
+
155
+ /**
156
+ * One measured trial: the same scalar, on both arms, under the same conditions.
157
+ *
158
+ * Both values are required. An absent arm is refused rather than imputed,
159
+ * because imputing it would put a number the run did not observe into a
160
+ * denominator that decides a verdict.
161
+ */
162
+ export interface TrialOutcome {
163
+ /**
164
+ * Unique across the WHOLE comparison, not merely within its pair.
165
+ *
166
+ * Stated rather than left implicit, because the two readings differ in what
167
+ * they refuse and the ambiguity was the defect. `pairedDeltas` refuses a
168
+ * repeat within one call and cannot see across pairs; {@link compareArms}
169
+ * pools every pair's deltas into ONE sample, and the denominator of that
170
+ * sample is what the sign test adjudicates. A caller that derives the
171
+ * outcomes map wrongly — the realistic shape being the same measurement
172
+ * array reached under two keys — then contributes one set of deltas twice.
173
+ * Under a pair-scoped reading that is undetectable; under this one it is a
174
+ * refusal, and the cost is that a caller names its trials per pair.
175
+ */
176
+ readonly trial_id: string;
177
+ readonly control: number;
178
+ readonly treatment: number;
179
+ }
180
+
181
+ /**
182
+ * The signed deltas for one pair. Positive favours the TREATMENT, always.
183
+ *
184
+ * The convention is not this module's to set: the verdict's own input contract
185
+ * states one signed delta per trial with positive favouring the treatment, so
186
+ * the direction handling here is a translation of {@link MetricDirection} into
187
+ * that fixed convention rather than a second convention beside it. For a
188
+ * lower-better metric the subtraction is reversed, so a caller never has to
189
+ * remember which endpoint it is looking at.
190
+ */
191
+ export function pairedDeltas(
192
+ outcomes: readonly TrialOutcome[],
193
+ direction: MetricDirection,
194
+ ): number[] {
195
+ if (outcomes.length === 0) {
196
+ throw new PairingError(
197
+ 'no trials: a verdict over zero trials is a fabricated result, not an empty one',
198
+ );
199
+ }
200
+ const ids = new Set<string>();
201
+ for (const o of outcomes) {
202
+ if (ids.has(o.trial_id)) {
203
+ throw new PairingError(
204
+ `duplicate trial id '${o.trial_id}': one trial counted twice inflates the discordant count`,
205
+ );
206
+ }
207
+ ids.add(o.trial_id);
208
+ if (!Number.isFinite(o.control) || !Number.isFinite(o.treatment)) {
209
+ throw new PairingError(
210
+ `trial '${o.trial_id}' carries a non-finite outcome: an unmeasured trial is absent, never zero`,
211
+ );
212
+ }
213
+ }
214
+ return outcomes.map((o) =>
215
+ direction === 'higher-better' ? o.treatment - o.control : o.control - o.treatment,
216
+ );
217
+ }
218
+
219
+ export interface PairComparison {
220
+ readonly pairs: readonly CandidatePair[];
221
+ readonly trials: number;
222
+ readonly verdict: PairedVerdict;
223
+ /** Pairs whose arms produced identical bytes, so every one of their trials tied. */
224
+ readonly identical_pairs: readonly string[];
225
+ }
226
+
227
+ export interface ComparisonInput {
228
+ readonly control: readonly CandidateRecord[];
229
+ readonly treatment: readonly CandidateRecord[];
230
+ /** Trials keyed by pairing key. Every pair must carry at least one. */
231
+ readonly outcomes: Readonly<Record<string, readonly TrialOutcome[]>>;
232
+ readonly direction: MetricDirection;
233
+ }
234
+
235
+ /**
236
+ * The comparison, pooled across pairs.
237
+ *
238
+ * Pooling is what raises the experiment off the discordant floor: with one
239
+ * delta per pair the trial count equals the corpus size, which sits exactly on
240
+ * the derived floor, so a single dissent makes a pass arithmetically
241
+ * unreachable before the run starts. Pooling per-trial deltas across pairs
242
+ * makes the count the number of TRIALS rather than the number of pairs.
243
+ *
244
+ * The assumption that buys it is stated rather than assumed away: the exact
245
+ * sign test treats each delta as an independent draw, and trials on the same
246
+ * pair share a subject. A caller that cannot defend that independence should
247
+ * pass one aggregate delta per pair and accept the smaller sample, which this
248
+ * function supports by simply being given fewer trials.
249
+ */
250
+ export function compareArms(input: ComparisonInput): PairComparison {
251
+ const pairs = pairCandidates(input.control, input.treatment);
252
+ const keys = new Set(pairs.map((p) => p.key));
253
+ for (const k of Object.keys(input.outcomes)) {
254
+ if (!keys.has(k)) {
255
+ throw new PairingError(
256
+ `outcomes carry key '${k}', which matches no pair: the key is a formatted string ` +
257
+ 'the caller derives rather than receives, so an unmatched one is a mis-derived ' +
258
+ 'or stale measurement set, and pooling only the keys that happened to match ' +
259
+ 'is the same silently smaller denominator the opposite refusal names',
260
+ );
261
+ }
262
+ }
263
+ const deltas: number[] = [];
264
+ const seenTrials = new Set<string>();
265
+ for (const p of pairs) {
266
+ const trials = input.outcomes[p.key];
267
+ if (trials === undefined || trials.length === 0) {
268
+ throw new PairingError(
269
+ `pair '${p.key}' has no trials: a pair present in the arms and absent from the ` +
270
+ 'measurements silently shrinks the denominator',
271
+ );
272
+ }
273
+ for (const t of trials) {
274
+ if (seenTrials.has(t.trial_id)) {
275
+ throw new PairingError(
276
+ `trial id '${t.trial_id}' appears on more than one pair: the refusal in ` +
277
+ 'pairedDeltas is scoped to one pair and cannot see a reuse across pairs, ' +
278
+ 'and one trial counted twice inflates the discordant count either way',
279
+ );
280
+ }
281
+ seenTrials.add(t.trial_id);
282
+ }
283
+ deltas.push(...pairedDeltas(trials, input.direction));
284
+ }
285
+ return {
286
+ pairs,
287
+ trials: deltas.length,
288
+ verdict: decidePairedVerdict({ deltas, tieEpsilon: TIE_EPSILON }),
289
+ identical_pairs: pairs.filter((p) => p.identical_arms).map((p) => p.key),
290
+ };
291
+ }
292
+
293
+ /**
294
+ * The comparison as a metric vector the evaluation cascade can consume.
295
+ *
296
+ * The artifact-count row is not optional: {@link buildVector} refuses a vector
297
+ * without it, so a candidate cannot reach the promotion verdict without its
298
+ * artifact delta having been measured. The delta is SUPPLIED here rather than
299
+ * derived, and the reason is the same one that keeps {@link TrialOutcome} out
300
+ * of this module.
301
+ *
302
+ * Why this module cannot derive it. {@link pairingKey} folds the sorted mutation-path list into the key and
303
+ * {@link pairCandidates} forms a pair only on an exact key match, so control
304
+ * and treatment of every pair carry identical path multisets by construction.
305
+ * Any count taken over those paths therefore differs by exactly 0 for every
306
+ * pair and every candidate — not usually, but always. A row filled that way
307
+ * satisfies the builder's SHAPE check while making the ceiling branch in
308
+ * `promotionVerdict` unreachable, which defeats the invariant the shape
309
+ * check exists to carry: the vector would be refused for omitting the row and
310
+ * accepted for carrying a constant.
311
+ *
312
+ * The quantity the gate actually names is baseline-relative growth — how many
313
+ * artifacts the candidate ADDS to the tree it is a variant of. That is a fact
314
+ * about the candidate against an unmutated baseline, and this module sees
315
+ * neither the baseline nor the filesystem. So the caller that knows which
316
+ * mutated paths are new files passes the count, and a caller that has not
317
+ * measured it has nothing to pass.
318
+ *
319
+ * @param artifactDelta signed count of artifacts the candidate adds against
320
+ * its baseline. Must be a finite integer; a fractional or non-finite value is
321
+ * refused rather than rounded, because a rounded ceiling comparison is a
322
+ * verdict on a number nobody measured.
323
+ * @throws {PairingError} when `artifactDelta` is not a finite integer.
324
+ */
325
+ export function comparisonVector(
326
+ candidate_id: string,
327
+ metric: string,
328
+ direction: MetricDirection,
329
+ comparison: PairComparison,
330
+ artifactDelta: number,
331
+ ): MetricVector {
332
+ if (!Number.isInteger(artifactDelta)) {
333
+ throw new PairingError(
334
+ `artifact delta ${String(artifactDelta)} is not a finite integer: the artifact-count ` +
335
+ 'row is a count of artifacts, and a gate that compared a fraction against its ' +
336
+ 'ceiling would be adjudicating a quantity the run never observed',
337
+ );
338
+ }
339
+ const rows: MetricRow[] = [
340
+ { kind: 'paired', metric, direction, verdict: comparison.verdict },
341
+ {
342
+ kind: 'counted',
343
+ metric: ARTIFACT_COUNT_METRIC,
344
+ direction: 'lower-better',
345
+ delta: artifactDelta,
346
+ },
347
+ ];
348
+ return buildVector(candidate_id, rows);
349
+ }