@velum-labs/routekit-eval-setup 1.4.0 → 1.5.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 (341) hide show
  1. package/dist/adapters/authoring-responses-request.d.ts +5 -0
  2. package/dist/adapters/authoring-responses-request.js +38 -0
  3. package/dist/adapters/evaluation-evidence-freshness.d.ts +7 -0
  4. package/dist/adapters/evaluation-evidence-freshness.js +76 -0
  5. package/dist/adapters/git-task-history.d.ts +67 -0
  6. package/dist/adapters/git-task-history.js +171 -0
  7. package/dist/adapters/integrated-repository-history.d.ts +21 -0
  8. package/dist/adapters/integrated-repository-history.js +175 -0
  9. package/dist/adapters/repository-command-diagnostic.d.ts +8 -0
  10. package/dist/adapters/repository-command-diagnostic.js +46 -0
  11. package/dist/adapters/repository-command-evidence.d.ts +13 -0
  12. package/dist/adapters/repository-command-evidence.js +102 -0
  13. package/dist/adapters/repository-command-runner.d.ts +238 -0
  14. package/dist/adapters/repository-command-runner.js +1483 -0
  15. package/dist/adapters/repository-import-context.d.ts +47 -0
  16. package/dist/adapters/repository-import-context.js +469 -0
  17. package/dist/adapters/repository-node-test-reporter.d.ts +3 -0
  18. package/dist/adapters/repository-node-test-reporter.js +27 -0
  19. package/dist/adapters/repository-review-evidence.d.ts +39 -0
  20. package/dist/adapters/repository-review-evidence.js +632 -0
  21. package/dist/adapters/repository-seed-selection.d.ts +7 -0
  22. package/dist/adapters/repository-seed-selection.js +79 -0
  23. package/dist/adapters/repository-solution-edits.d.ts +49 -0
  24. package/dist/adapters/repository-solution-edits.js +136 -0
  25. package/dist/adapters/repository-vitest-phase-adapter.d.ts +8 -0
  26. package/dist/adapters/repository-vitest-phase-adapter.js +310 -0
  27. package/dist/adapters/repository-vitest-reporter.d.ts +24 -0
  28. package/dist/adapters/repository-vitest-reporter.js +314 -0
  29. package/dist/adapters/strict-authoring-schema.d.ts +5 -0
  30. package/dist/adapters/strict-authoring-schema.js +158 -0
  31. package/dist/adapters/test-discovery.d.ts +30 -0
  32. package/dist/adapters/test-discovery.js +124 -0
  33. package/dist/adapters/typescript-repository-index.d.ts +51 -0
  34. package/dist/adapters/typescript-repository-index.js +226 -0
  35. package/dist/agentic-capabilities-protocol.d.ts +1373 -0
  36. package/dist/agentic-capabilities-protocol.js +786 -0
  37. package/dist/case-checkpoint-store.d.ts +29 -0
  38. package/dist/case-checkpoint-store.js +133 -0
  39. package/dist/case-pipeline-protocol-v2.d.ts +184 -0
  40. package/dist/case-pipeline-protocol-v2.js +193 -0
  41. package/dist/case-pipeline-protocol.d.ts +2626 -0
  42. package/dist/case-pipeline-protocol.js +371 -0
  43. package/dist/effect-api.d.ts +74 -12
  44. package/dist/effect-api.js +56 -7
  45. package/dist/errors.d.ts +31 -0
  46. package/dist/errors.js +10 -0
  47. package/dist/eval-capability-execution-envelope.d.ts +64 -0
  48. package/dist/eval-capability-execution-envelope.js +98 -0
  49. package/dist/eval-capability-policy.d.ts +90 -0
  50. package/dist/eval-capability-policy.js +107 -0
  51. package/dist/eval-event-log.d.ts +51 -0
  52. package/dist/eval-event-log.js +69 -10
  53. package/dist/evaluation-authoring-policy.d.ts +18 -0
  54. package/dist/evaluation-authoring-policy.js +19 -0
  55. package/dist/evaluation-authoring-validation.d.ts +22 -0
  56. package/dist/evaluation-authoring-validation.js +72 -0
  57. package/dist/evaluation-evidence.d.ts +20 -0
  58. package/dist/evaluation-evidence.js +319 -0
  59. package/dist/evaluation-grader-calibration-protocol.d.ts +108 -0
  60. package/dist/evaluation-grader-calibration-protocol.js +80 -0
  61. package/dist/evaluation-grader-calibration.d.ts +18 -0
  62. package/dist/evaluation-grader-calibration.js +334 -0
  63. package/dist/evaluation-grading-policy.d.ts +24 -0
  64. package/dist/evaluation-grading-policy.js +54 -0
  65. package/dist/evaluation-proposal-policy.d.ts +4 -0
  66. package/dist/evaluation-proposal-policy.js +91 -0
  67. package/dist/evaluation-source-retrieval.d.ts +68 -0
  68. package/dist/evaluation-source-retrieval.js +513 -0
  69. package/dist/evaluation-structure-policy.d.ts +29 -0
  70. package/dist/evaluation-structure-policy.js +138 -0
  71. package/dist/index.d.ts +124 -19
  72. package/dist/index.js +69 -12
  73. package/dist/inspection.js +2 -3
  74. package/dist/project-artifacts.d.ts +2 -2
  75. package/dist/project-artifacts.js +26 -121
  76. package/dist/project-authoring.d.ts +66 -5
  77. package/dist/project-authoring.js +783 -109
  78. package/dist/project-contracts.d.ts +292 -82
  79. package/dist/project-contracts.js +65 -7
  80. package/dist/project-store.js +2 -1
  81. package/dist/project-workflow.d.ts +3 -3
  82. package/dist/project-workflow.js +116 -18
  83. package/dist/repository-adversary-protocol.d.ts +64 -0
  84. package/dist/repository-adversary-protocol.js +105 -0
  85. package/dist/repository-behavior-protocol.d.ts +188 -0
  86. package/dist/repository-behavior-protocol.js +202 -0
  87. package/dist/repository-benchmark-protocol.d.ts +487 -0
  88. package/dist/repository-benchmark-protocol.js +96 -0
  89. package/dist/repository-execution-protocol.d.ts +150 -0
  90. package/dist/repository-execution-protocol.js +38 -0
  91. package/dist/repository-fixture-instructions.d.ts +3 -0
  92. package/dist/repository-fixture-instructions.js +91 -0
  93. package/dist/repository-fixture-protocol.d.ts +79 -0
  94. package/dist/repository-fixture-protocol.js +79 -0
  95. package/dist/repository-foundry-plan-protocol.d.ts +118 -0
  96. package/dist/repository-foundry-plan-protocol.js +296 -0
  97. package/dist/repository-foundry-progress-protocol.d.ts +52 -0
  98. package/dist/repository-foundry-progress-protocol.js +52 -0
  99. package/dist/repository-improvement-protocol.d.ts +100 -0
  100. package/dist/repository-improvement-protocol.js +106 -0
  101. package/dist/repository-language-model-protocol.d.ts +43 -0
  102. package/dist/repository-language-model-protocol.js +146 -0
  103. package/dist/repository-oracle-coverage-protocol.d.ts +18 -0
  104. package/dist/repository-oracle-coverage-protocol.js +39 -0
  105. package/dist/repository-oracle-execution-binding.d.ts +27 -0
  106. package/dist/repository-oracle-execution-binding.js +59 -0
  107. package/dist/repository-oracle-protocol.d.ts +230 -0
  108. package/dist/repository-oracle-protocol.js +156 -0
  109. package/dist/repository-oracle-scope-policy.d.ts +22 -0
  110. package/dist/repository-oracle-scope-policy.js +92 -0
  111. package/dist/repository-quality-policy.d.ts +15 -0
  112. package/dist/repository-quality-policy.js +357 -0
  113. package/dist/repository-routing-benchmark-protocol.d.ts +176 -0
  114. package/dist/repository-routing-benchmark-protocol.js +103 -0
  115. package/dist/repository-routing-model-protocol.d.ts +36 -0
  116. package/dist/repository-routing-model-protocol.js +89 -0
  117. package/dist/repository-routing-plan-protocol.d.ts +112 -0
  118. package/dist/repository-routing-plan-protocol.js +58 -0
  119. package/dist/repository-routing-quality-policy.d.ts +9 -0
  120. package/dist/repository-routing-quality-policy.js +191 -0
  121. package/dist/repository-seed-qualification-progress-protocol.d.ts +205 -0
  122. package/dist/repository-seed-qualification-progress-protocol.js +28 -0
  123. package/dist/repository-semantic-calibration-protocol.d.ts +768 -0
  124. package/dist/repository-semantic-calibration-protocol.js +276 -0
  125. package/dist/repository-semantic-calibration.d.ts +163 -0
  126. package/dist/repository-semantic-calibration.js +581 -0
  127. package/dist/repository-specification-contract-facts-protocol.d.ts +224 -0
  128. package/dist/repository-specification-contract-facts-protocol.js +276 -0
  129. package/dist/repository-specification-critique-protocol.d.ts +189 -0
  130. package/dist/repository-specification-critique-protocol.js +103 -0
  131. package/dist/repository-task-family-protocol.d.ts +24 -0
  132. package/dist/repository-task-family-protocol.js +37 -0
  133. package/dist/repository-task-seed-protocol.d.ts +384 -0
  134. package/dist/repository-task-seed-protocol.js +236 -0
  135. package/dist/repository-trajectory-protocol.d.ts +20 -0
  136. package/dist/repository-trajectory-protocol.js +42 -0
  137. package/dist/service.js +1 -1
  138. package/dist/services/adversary/service.d.ts +64 -0
  139. package/dist/services/adversary/service.js +330 -0
  140. package/dist/services/benchmark-compiler/service.d.ts +450 -0
  141. package/dist/services/benchmark-compiler/service.js +9 -0
  142. package/dist/services/budgeted-model/service.d.ts +118 -0
  143. package/dist/services/budgeted-model/service.js +460 -0
  144. package/dist/services/case-authoring/service.d.ts +163 -0
  145. package/dist/services/case-authoring/service.js +1456 -0
  146. package/dist/services/case-finalization/service.d.ts +283 -0
  147. package/dist/services/case-finalization/service.js +370 -0
  148. package/dist/services/case-generation/service.d.ts +619 -0
  149. package/dist/services/case-generation/service.js +2628 -0
  150. package/dist/services/case-pipeline/service.d.ts +31 -0
  151. package/dist/services/case-pipeline/service.js +485 -0
  152. package/dist/services/case-pipeline-v2/service.d.ts +70 -0
  153. package/dist/services/case-pipeline-v2/service.js +477 -0
  154. package/dist/services/command-observability/service.d.ts +13 -0
  155. package/dist/services/command-observability/service.js +3 -0
  156. package/dist/services/dimension-labeling/service.d.ts +77 -0
  157. package/dist/services/dimension-labeling/service.js +188 -0
  158. package/dist/services/eval-candidate/service.d.ts +208 -0
  159. package/dist/services/eval-candidate/service.js +64 -0
  160. package/dist/services/eval-capabilities/service.d.ts +183 -0
  161. package/dist/services/eval-capabilities/service.js +1433 -0
  162. package/dist/services/eval-environment/service.d.ts +173 -0
  163. package/dist/services/eval-environment/service.js +127 -0
  164. package/dist/services/evidence-reconstruction/service.d.ts +36 -0
  165. package/dist/services/evidence-reconstruction/service.js +145 -0
  166. package/dist/services/fixture-builder/service.d.ts +62 -0
  167. package/dist/services/fixture-builder/service.js +36 -0
  168. package/dist/services/fixture-validation/service.d.ts +75 -0
  169. package/dist/services/fixture-validation/service.js +295 -0
  170. package/dist/services/foundry/service.d.ts +831 -0
  171. package/dist/services/foundry/service.js +442 -0
  172. package/dist/services/foundry-progress/service.d.ts +62 -0
  173. package/dist/services/foundry-progress/service.js +149 -0
  174. package/dist/services/foundry-v2/service.d.ts +54 -0
  175. package/dist/services/foundry-v2/service.js +28 -0
  176. package/dist/services/grounded-authoring/service.d.ts +126 -0
  177. package/dist/services/grounded-authoring/service.js +822 -0
  178. package/dist/services/historical-case/service.d.ts +722 -0
  179. package/dist/services/historical-case/service.js +177 -0
  180. package/dist/services/improvement-loop/service.d.ts +59 -0
  181. package/dist/services/improvement-loop/service.js +176 -0
  182. package/dist/services/language-model/service.d.ts +52 -0
  183. package/dist/services/language-model/service.js +194 -0
  184. package/dist/services/oracle-builder/service.d.ts +146 -0
  185. package/dist/services/oracle-builder/service.js +513 -0
  186. package/dist/services/oracle-coverage/service.d.ts +28 -0
  187. package/dist/services/oracle-coverage/service.js +50 -0
  188. package/dist/services/oracle-coverage-witness/service.d.ts +130 -0
  189. package/dist/services/oracle-coverage-witness/service.js +538 -0
  190. package/dist/services/pipeline-challenge/service.d.ts +551 -0
  191. package/dist/services/pipeline-challenge/service.js +427 -0
  192. package/dist/services/pipeline-controls/service.d.ts +130 -0
  193. package/dist/services/pipeline-controls/service.js +483 -0
  194. package/dist/services/pipeline-oracle/service.d.ts +8 -0
  195. package/dist/services/pipeline-oracle/service.js +256 -0
  196. package/dist/services/pipeline-seed/service.d.ts +298 -0
  197. package/dist/services/pipeline-seed/service.js +428 -0
  198. package/dist/services/pipeline-spec/service.d.ts +103 -0
  199. package/dist/services/pipeline-spec/service.js +619 -0
  200. package/dist/services/pipeline-tournament/service.d.ts +258 -0
  201. package/dist/services/pipeline-tournament/service.js +476 -0
  202. package/dist/services/quality-gate/service.d.ts +233 -0
  203. package/dist/services/quality-gate/service.js +136 -0
  204. package/dist/services/repository-bundle/service.d.ts +33 -0
  205. package/dist/services/repository-bundle/service.js +114 -0
  206. package/dist/services/repository-model/service.d.ts +105 -0
  207. package/dist/services/repository-model/service.js +250 -0
  208. package/dist/services/repository-public-artifact/service.d.ts +133 -0
  209. package/dist/services/repository-public-artifact/service.js +330 -0
  210. package/dist/services/routing-benchmark/service.d.ts +362 -0
  211. package/dist/services/routing-benchmark/service.js +96 -0
  212. package/dist/services/specification-critic/service.d.ts +92 -0
  213. package/dist/services/specification-critic/service.js +172 -0
  214. package/dist/services/task-family/service.d.ts +40 -0
  215. package/dist/services/task-family/service.js +55 -0
  216. package/dist/services/task-seed/service.d.ts +906 -0
  217. package/dist/services/task-seed/service.js +1406 -0
  218. package/dist/services/task-specification/service.d.ts +27 -0
  219. package/dist/services/task-specification/service.js +40 -0
  220. package/dist/services/trajectory-policy/service.d.ts +110 -0
  221. package/dist/services/trajectory-policy/service.js +216 -0
  222. package/dist/test/agentic-capabilities-protocol.test.d.ts +1 -0
  223. package/dist/test/agentic-capabilities-protocol.test.js +570 -0
  224. package/dist/test/agentic-capabilities.test.d.ts +1 -0
  225. package/dist/test/agentic-capabilities.test.js +1461 -0
  226. package/dist/test/agentic-environment.test.d.ts +1 -0
  227. package/dist/test/agentic-environment.test.js +213 -0
  228. package/dist/test/case-pipeline-foundation.test.d.ts +1 -0
  229. package/dist/test/case-pipeline-foundation.test.js +535 -0
  230. package/dist/test/case-pipeline-protocol-v2.test.d.ts +1 -0
  231. package/dist/test/case-pipeline-protocol-v2.test.js +124 -0
  232. package/dist/test/case-pipeline-v2.test.d.ts +1 -0
  233. package/dist/test/case-pipeline-v2.test.js +286 -0
  234. package/dist/test/case-pipeline.test.d.ts +1 -0
  235. package/dist/test/case-pipeline.test.js +851 -0
  236. package/dist/test/eval-capability-policy.test.d.ts +1 -0
  237. package/dist/test/eval-capability-policy.test.js +50 -0
  238. package/dist/test/eval-event-log.test.js +34 -1
  239. package/dist/test/evaluation-evidence-freshness.test.d.ts +1 -0
  240. package/dist/test/evaluation-evidence-freshness.test.js +44 -0
  241. package/dist/test/evaluation-evidence.test.d.ts +1 -0
  242. package/dist/test/evaluation-evidence.test.js +230 -0
  243. package/dist/test/evaluation-grader-calibration.test.d.ts +1 -0
  244. package/dist/test/evaluation-grader-calibration.test.js +373 -0
  245. package/dist/test/evaluation-proposal-digest.test.d.ts +1 -0
  246. package/dist/test/evaluation-proposal-digest.test.js +187 -0
  247. package/dist/test/evaluation-source-retrieval.test.d.ts +1 -0
  248. package/dist/test/evaluation-source-retrieval.test.js +237 -0
  249. package/dist/test/evaluation-structure-policy.test.d.ts +1 -0
  250. package/dist/test/evaluation-structure-policy.test.js +196 -0
  251. package/dist/test/fixtures/repository-resource-panel.d.ts +39 -0
  252. package/dist/test/fixtures/repository-resource-panel.js +111 -0
  253. package/dist/test/fixtures/vitest-boundary-panel.d.ts +84 -0
  254. package/dist/test/fixtures/vitest-boundary-panel.js +120 -0
  255. package/dist/test/fixtures/vitest-phase-panel.d.ts +135 -0
  256. package/dist/test/fixtures/vitest-phase-panel.js +213 -0
  257. package/dist/test/fixtures/vitest-reporter-results.d.ts +76 -0
  258. package/dist/test/fixtures/vitest-reporter-results.js +94 -0
  259. package/dist/test/grounded-authoring.test.d.ts +1 -0
  260. package/dist/test/grounded-authoring.test.js +565 -0
  261. package/dist/test/integrated-repository-history.test.d.ts +1 -0
  262. package/dist/test/integrated-repository-history.test.js +227 -0
  263. package/dist/test/project-authoring.test.js +593 -43
  264. package/dist/test/project-workflow.test.js +395 -32
  265. package/dist/test/repository-authoring-artifacts.test.d.ts +1 -0
  266. package/dist/test/repository-authoring-artifacts.test.js +185 -0
  267. package/dist/test/repository-bundle.test.d.ts +1 -0
  268. package/dist/test/repository-bundle.test.js +52 -0
  269. package/dist/test/repository-case-generation.test.d.ts +1 -0
  270. package/dist/test/repository-case-generation.test.js +3465 -0
  271. package/dist/test/repository-command-diagnostic.test.d.ts +1 -0
  272. package/dist/test/repository-command-diagnostic.test.js +55 -0
  273. package/dist/test/repository-command-signals.test.d.ts +1 -0
  274. package/dist/test/repository-command-signals.test.js +124 -0
  275. package/dist/test/repository-fixture-scope-coverage.test.d.ts +1 -0
  276. package/dist/test/repository-fixture-scope-coverage.test.js +127 -0
  277. package/dist/test/repository-fixture-validation.test.d.ts +1 -0
  278. package/dist/test/repository-fixture-validation.test.js +362 -0
  279. package/dist/test/repository-foundry-progress.test.d.ts +1 -0
  280. package/dist/test/repository-foundry-progress.test.js +110 -0
  281. package/dist/test/repository-foundry-quality.test.d.ts +1 -0
  282. package/dist/test/repository-foundry-quality.test.js +1138 -0
  283. package/dist/test/repository-import-context.test.d.ts +1 -0
  284. package/dist/test/repository-import-context.test.js +354 -0
  285. package/dist/test/repository-model-authoring.test.d.ts +1 -0
  286. package/dist/test/repository-model-authoring.test.js +544 -0
  287. package/dist/test/repository-model.test.d.ts +1 -0
  288. package/dist/test/repository-model.test.js +2195 -0
  289. package/dist/test/repository-node-test-reporter.test.d.ts +1 -0
  290. package/dist/test/repository-node-test-reporter.test.js +104 -0
  291. package/dist/test/repository-oracle-concurrency.test.d.ts +1 -0
  292. package/dist/test/repository-oracle-concurrency.test.js +542 -0
  293. package/dist/test/repository-oracle-coverage-witness.test.d.ts +1 -0
  294. package/dist/test/repository-oracle-coverage-witness.test.js +511 -0
  295. package/dist/test/repository-oracle-coverage.test.d.ts +1 -0
  296. package/dist/test/repository-oracle-coverage.test.js +168 -0
  297. package/dist/test/repository-oracle-evidence.test.d.ts +1 -0
  298. package/dist/test/repository-oracle-evidence.test.js +185 -0
  299. package/dist/test/repository-oracle-plan.test.d.ts +1 -0
  300. package/dist/test/repository-oracle-plan.test.js +176 -0
  301. package/dist/test/repository-overlay-isolation.test.d.ts +1 -0
  302. package/dist/test/repository-overlay-isolation.test.js +85 -0
  303. package/dist/test/repository-preparation-cache.test.d.ts +1 -0
  304. package/dist/test/repository-preparation-cache.test.js +414 -0
  305. package/dist/test/repository-public-artifact.test.d.ts +1 -0
  306. package/dist/test/repository-public-artifact.test.js +273 -0
  307. package/dist/test/repository-qualification-diagnostics.test.d.ts +1 -0
  308. package/dist/test/repository-qualification-diagnostics.test.js +524 -0
  309. package/dist/test/repository-reference-authoring.test.d.ts +1 -0
  310. package/dist/test/repository-reference-authoring.test.js +1633 -0
  311. package/dist/test/repository-review-evidence-v2.test.d.ts +1 -0
  312. package/dist/test/repository-review-evidence-v2.test.js +183 -0
  313. package/dist/test/repository-review-evidence.test.d.ts +1 -0
  314. package/dist/test/repository-review-evidence.test.js +124 -0
  315. package/dist/test/repository-seed-exclusions.test.d.ts +1 -0
  316. package/dist/test/repository-seed-exclusions.test.js +96 -0
  317. package/dist/test/repository-seed-selection.test.d.ts +1 -0
  318. package/dist/test/repository-seed-selection.test.js +504 -0
  319. package/dist/test/repository-semantic-calibration.test.d.ts +1 -0
  320. package/dist/test/repository-semantic-calibration.test.js +688 -0
  321. package/dist/test/repository-solution-edits.test.d.ts +1 -0
  322. package/dist/test/repository-solution-edits.test.js +377 -0
  323. package/dist/test/repository-specification-budget.test.d.ts +1 -0
  324. package/dist/test/repository-specification-budget.test.js +171 -0
  325. package/dist/test/repository-specification-contract-checkpoint.test.d.ts +1 -0
  326. package/dist/test/repository-specification-contract-checkpoint.test.js +228 -0
  327. package/dist/test/repository-specification-contract-facts.test.d.ts +1 -0
  328. package/dist/test/repository-specification-contract-facts.test.js +177 -0
  329. package/dist/test/repository-trajectory-authoring.test.d.ts +1 -0
  330. package/dist/test/repository-trajectory-authoring.test.js +176 -0
  331. package/dist/test/repository-valid-control-plan.test.d.ts +1 -0
  332. package/dist/test/repository-valid-control-plan.test.js +45 -0
  333. package/dist/test/repository-vitest-phase.test.d.ts +1 -0
  334. package/dist/test/repository-vitest-phase.test.js +848 -0
  335. package/dist/test/repository-vitest-reporter.test.d.ts +1 -0
  336. package/dist/test/repository-vitest-reporter.test.js +158 -0
  337. package/dist/test/repository-workspace-build.test.d.ts +1 -0
  338. package/dist/test/repository-workspace-build.test.js +160 -0
  339. package/dist/test/strict-authoring-schema.test.d.ts +1 -0
  340. package/dist/test/strict-authoring-schema.test.js +169 -0
  341. package/package.json +48 -7
@@ -7,6 +7,8 @@ import { layer as NodeServicesLayer } from "@effect/platform-node/NodeServices";
7
7
  import { CostServiceLive, makeCostService } from "@velum-labs/routekit-registry";
8
8
  import { Cause, Effect, Layer } from "effect";
9
9
  import { EvalDimensionContrastError, EvalModelCatalogError } from "../errors.js";
10
+ import { compileEvaluationEvidence, renderEvaluationEvidenceContext } from "../evaluation-evidence.js";
11
+ import { renderEvaluationCriteria } from "../evaluation-structure-policy.js";
10
12
  import { EvalRepositoryInspectorLive } from "../inspection.js";
11
13
  import { EvalProjectArtifactsLive } from "../project-artifacts.js";
12
14
  import { estimateEvalPlanCost, scopedExpectedCalls, summarizeEvalRunLedger } from "../project-contracts.js";
@@ -35,7 +37,7 @@ const makeRepository = async () => {
35
37
  const root = await mkdtemp(path.join(os.tmpdir(), "routekit-eval-project-"));
36
38
  roots.push(root);
37
39
  await mkdir(path.join(root, "src"), { recursive: true });
38
- await writeFile(path.join(root, "README.md"), "# Example application\n");
40
+ await writeFile(path.join(root, "README.md"), "# Example application\n\nA terminal event must be last; later output is invalid and unsupported.\n");
39
41
  await writeFile(path.join(root, "src", "model.ts"), 'client.responses.create({ model: "openai/current" });\n');
40
42
  return root;
41
43
  };
@@ -205,15 +207,89 @@ const reviewedProposedDimensions = reviewedDimensions.map((dimension, index) =>
205
207
  inScopeRequest: `Solve an in-scope request for dimension ${String(index + 1)}.`,
206
208
  nearMissRequest: `Solve a neighboring request outside dimension ${String(index + 1)}.`
207
209
  }));
210
+ const reviewedPrompt = (dimensionId, index) => {
211
+ switch (index % 5) {
212
+ case 0:
213
+ return `Transform raw ${dimensionId} capture ${String(index + 1)}`;
214
+ case 1:
215
+ return `Locate the fault in ${dimensionId} trace ${String(index + 1)}`;
216
+ case 2:
217
+ return `Construct the ${dimensionId} artifact for sample ${String(index + 1)}`;
218
+ case 3:
219
+ return `Analyze the ${dimensionId} boundary sample ${String(index + 1)}`;
220
+ default:
221
+ return `Explain the ${dimensionId} operational result ${String(index + 1)}`;
222
+ }
223
+ };
224
+ const reviewedEvidenceSources = compileEvaluationEvidence({
225
+ sources: [
226
+ {
227
+ path: "README.md",
228
+ content: "# Example application\n\nA terminal event must be last; later output is invalid and unsupported.\n"
229
+ },
230
+ {
231
+ path: "src/model.ts",
232
+ content: 'client.responses.create({ model: "openai/current" });\n'
233
+ }
234
+ ],
235
+ maximumBlockBytes: 3_000
236
+ });
237
+ const reviewedEvidenceBlock = reviewedEvidenceSources[0].blocks[0];
238
+ const reviewedCompiledFields = (caseId, index) => {
239
+ const criterionId = `${caseId}-criterion`;
240
+ const criteria = [
241
+ {
242
+ id: criterionId,
243
+ description: `Derive the observable repository behavior for case ${String(index + 1)}.`,
244
+ importance: "critical",
245
+ gradingMode: "semantic"
246
+ }
247
+ ];
248
+ return {
249
+ context: renderEvaluationEvidenceContext([reviewedEvidenceBlock]),
250
+ rubric: renderEvaluationCriteria(criteria),
251
+ evidenceIds: [reviewedEvidenceBlock.id],
252
+ criteria,
253
+ positiveControls: [
254
+ {
255
+ id: `${caseId}-positive`,
256
+ response: `The response derives the repository-backed behavior for case ${String(index + 1)}.`
257
+ }
258
+ ],
259
+ negativeControls: [
260
+ {
261
+ id: `${caseId}-missing`,
262
+ response: "The response discusses the topic but omits the required behavior.",
263
+ targetedCriterionIds: [criterionId],
264
+ kind: "missing-criterion"
265
+ },
266
+ {
267
+ id: `${caseId}-forbidden`,
268
+ response: "The response invents behavior contradicted by the repository evidence.",
269
+ targetedCriterionIds: [criterionId],
270
+ kind: "forbidden-behavior"
271
+ },
272
+ {
273
+ id: `${caseId}-non-responsive`,
274
+ response: "This is a polished overview that never answers the concrete request.",
275
+ targetedCriterionIds: [criterionId],
276
+ kind: "non-responsive"
277
+ }
278
+ ]
279
+ };
280
+ };
208
281
  const reviewedSuites = reviewedDimensions.map((dimension) => ({
209
282
  version: 1,
210
283
  dimensionId: dimension.id,
211
284
  maximumOutputTokens: 256,
212
- cases: Array.from({ length: 20 }, (_, index) => ({
213
- id: `${dimension.id}-case-${String(index + 1)}`,
214
- prompt: `Solve ${dimension.id} case ${String(index + 1)}`,
215
- rubric: `The response must satisfy ${dimension.id} case ${String(index + 1)}`
216
- }))
285
+ cases: Array.from({ length: 20 }, (_, index) => {
286
+ const id = `${dimension.id}-case-${String(index + 1)}`;
287
+ return {
288
+ id,
289
+ prompt: reviewedPrompt(dimension.id, index),
290
+ ...reviewedCompiledFields(id, index)
291
+ };
292
+ })
217
293
  }));
218
294
  const reviewedDecompositionBenchmark = {
219
295
  maximumVectorL1Error: 0.3,
@@ -233,32 +309,53 @@ const reviewedCompositionSuite = {
233
309
  maximumOutputTokens: 256,
234
310
  minimumWinnerScoreGap: 0.05,
235
311
  minimumWinnerAgreement: 0.8,
236
- cases: Array.from({ length: 20 }, (_, index) => ({
237
- id: `composition-case-${String(index + 1)}`,
238
- prompt: `Solve multi-dimension production case ${String(index + 1)}`,
239
- rubric: `The response must satisfy multi-dimension case ${String(index + 1)}`,
240
- decomposition: {
241
- weights: reviewedDimensions.map((dimension, dimensionIndex) => ({
242
- dimensionId: dimension.id,
243
- weight: dimensionIndex === index % reviewedDimensions.length ||
244
- dimensionIndex === (index + 1) % reviewedDimensions.length
245
- ? 0.5
246
- : 0
247
- })),
248
- unknownWeight: 0
249
- },
250
- requirements: {
251
- endpoint: "responses",
252
- requiresTools: false,
253
- requiresVision: false
254
- }
255
- }))
312
+ cases: Array.from({ length: 20 }, (_, index) => {
313
+ const id = `composition-case-${String(index + 1)}`;
314
+ return {
315
+ id,
316
+ prompt: reviewedPrompt("multi-dimension", index),
317
+ ...reviewedCompiledFields(id, index),
318
+ decomposition: {
319
+ weights: reviewedDimensions.map((dimension, dimensionIndex) => ({
320
+ dimensionId: dimension.id,
321
+ weight: dimensionIndex === index % reviewedDimensions.length ||
322
+ dimensionIndex === (index + 1) % reviewedDimensions.length
323
+ ? 0.5
324
+ : 0
325
+ })),
326
+ unknownWeight: 0
327
+ },
328
+ requirements: {
329
+ endpoint: "responses",
330
+ requiresTools: false,
331
+ requiresVision: false
332
+ }
333
+ };
334
+ })
256
335
  };
257
336
  const reviewedEvaluationInput = {
337
+ evidenceSources: reviewedEvidenceSources,
258
338
  suites: reviewedSuites,
259
339
  decompositionBenchmark: reviewedDecompositionBenchmark,
260
340
  compositionSuite: reviewedCompositionSuite
261
341
  };
342
+ const flashcardEvaluationInput = {
343
+ ...reviewedEvaluationInput,
344
+ suites: reviewedSuites.map((suite) => ({
345
+ ...suite,
346
+ cases: Array.from({ length: 20 }, (_, index) => {
347
+ const scenario = Math.floor(index / 2);
348
+ return {
349
+ id: `${suite.dimensionId}-flashcard-${String(index + 1)}`,
350
+ prompt: index % 2 === 0
351
+ ? "Diagnose the described RouteKit behavior. Use only the supplied context."
352
+ : "Give a concise verification criterion. Use only the supplied context.",
353
+ context: `Captured scenario ${String(scenario + 1)} emitted output after completion. The terminal event must be last.`,
354
+ rubric: "Reject post-terminal output and require completion to be the final event."
355
+ };
356
+ })
357
+ }))
358
+ };
262
359
  async function completeProjectSetup(root, candidateModels = "openai/gpt-5.6-luna openai/gpt-5.6-terra openai/gpt-5.6-sol") {
263
360
  await Effect.runPromise(Effect.gen(function* () {
264
361
  const workflow = yield* EvalProjectWorkflow;
@@ -388,15 +485,36 @@ test("reviewed artifacts are digest-bound and produce an immutable exact-call pl
388
485
  assert.deepEqual(JSON.parse(await readFile(planPath, "utf8")), result.plan);
389
486
  const firstDimension = reviewedDimensions[0];
390
487
  const generatedSuite = await readFile(path.join(root, ".routekit", "evals", "plans", result.plan.planId, "dimensions", firstDimension.id, `${firstDimension.id}.eval.ts`), "utf8");
488
+ const candidateCases = JSON.parse(await readFile(path.join(root, ".routekit", "evals", "plans", result.plan.planId, "dimensions", firstDimension.id, "data", "candidate-cases.json"), "utf8"));
489
+ const hiddenOracles = JSON.parse(await readFile(path.join(root, ".routekit", "evals", "plans", result.plan.planId, "dimensions", firstDimension.id, "data", "hidden-oracles.json"), "utf8"));
391
490
  const completionAssertion = generatedSuite.indexOf("run.toComplete();");
491
+ const oracleLookup = generatedSuite.indexOf("hiddenOracleById.get(candidateCase.id)");
392
492
  const judgeCall = generatedSuite.indexOf("await judge.autoEvals");
393
493
  const completionRethrow = generatedSuite.indexOf("throw candidateCompletionError;");
394
494
  const judgeRethrow = generatedSuite.indexOf("throw judgeError;");
395
495
  assert.match(generatedSuite, /emit the complete target-protocol envelope and terminal event/u);
396
496
  assert.match(generatedSuite, /include the concrete output rather than only describing it/u);
497
+ assert.match(generatedSuite, /You are a strict evaluator for AI agent outputs\./u);
498
+ assert.deepEqual(Object.keys(candidateCases[0]).sort(), [
499
+ "context",
500
+ "id",
501
+ "prompt"
502
+ ]);
503
+ assert.equal(Object.hasOwn(candidateCases[0], "rubric"), false);
504
+ assert.equal(Object.hasOwn(candidateCases[0], "criteria"), false);
505
+ assert.deepEqual(Object.keys(hiddenOracles[0]).sort(), [
506
+ "criteria",
507
+ "id",
508
+ "negativeControls",
509
+ "positiveControls",
510
+ "rubric"
511
+ ]);
512
+ assert.equal(candidateCases[0].id, hiddenOracles[0].id);
397
513
  assert.ok(judgeCall >= 0);
514
+ assert.ok(oracleLookup >= 0);
398
515
  assert.ok(completionAssertion >= 0);
399
- assert.ok(completionAssertion < judgeCall);
516
+ assert.ok(completionAssertion < oracleLookup);
517
+ assert.ok(oracleLookup < judgeCall);
400
518
  assert.ok(judgeCall < completionRethrow);
401
519
  assert.ok(completionRethrow < judgeRethrow);
402
520
  for (const dimension of reviewedDimensions) {
@@ -404,6 +522,95 @@ test("reviewed artifacts are digest-bound and produce an immutable exact-call pl
404
522
  .mode & 0o777, 0o600);
405
523
  }
406
524
  });
525
+ test("evaluation approval rejects historical cases without compiler provenance", async () => {
526
+ const root = await makeRepository();
527
+ await completeProjectSetup(root);
528
+ const exit = await Effect.runPromise(Effect.gen(function* () {
529
+ const workflow = yield* EvalProjectWorkflow;
530
+ const proposedBasis = yield* workflow.proposeDimensions(root, reviewedProposedDimensions);
531
+ yield* workflow.approveDimensions(root, proposedBasis.artifacts.basisProposalDigest);
532
+ const proposed = yield* workflow.proposeEvaluations(root, flashcardEvaluationInput);
533
+ return yield* Effect.exit(workflow.approveEvaluations(root, proposed.artifacts.evaluationProposalDigest));
534
+ }).pipe(Effect.provide(ProjectWorkflowTestLive)));
535
+ assert.equal(exit._tag, "Failure");
536
+ if (exit._tag === "Failure") {
537
+ const error = Cause.squash(exit.cause);
538
+ assert.match(String(error), /is not compiler-backed/u);
539
+ }
540
+ const approvalPath = path.join(root, ".routekit", "evals", "evaluations.approved.json");
541
+ await assert.rejects(stat(approvalPath), /ENOENT/u);
542
+ });
543
+ test("repository evidence changes stale approval before approval and planning", async () => {
544
+ const beforeApprovalRoot = await makeRepository();
545
+ await completeProjectSetup(beforeApprovalRoot);
546
+ const beforeApproval = await Effect.runPromise(Effect.gen(function* () {
547
+ const workflow = yield* EvalProjectWorkflow;
548
+ const proposedBasis = yield* workflow.proposeDimensions(beforeApprovalRoot, reviewedProposedDimensions);
549
+ yield* workflow.approveDimensions(beforeApprovalRoot, proposedBasis.artifacts.basisProposalDigest);
550
+ const proposed = yield* workflow.proposeEvaluations(beforeApprovalRoot, reviewedEvaluationInput);
551
+ return proposed.artifacts.evaluationProposalDigest;
552
+ }).pipe(Effect.provide(ProjectWorkflowTestLive)));
553
+ await writeFile(path.join(beforeApprovalRoot, "README.md"), "# Example application\n\nChanged after authoring.\n");
554
+ const approvalExit = await Effect.runPromise(Effect.gen(function* () {
555
+ const workflow = yield* EvalProjectWorkflow;
556
+ return yield* Effect.exit(workflow.approveEvaluations(beforeApprovalRoot, beforeApproval));
557
+ }).pipe(Effect.provide(ProjectWorkflowTestLive)));
558
+ assert.equal(approvalExit._tag, "Failure");
559
+ if (approvalExit._tag === "Failure") {
560
+ assert.match(String(Cause.squash(approvalExit.cause)), /evidence source changed after authoring/u);
561
+ }
562
+ const beforePlanRoot = await makeRepository();
563
+ await completeProjectSetup(beforePlanRoot);
564
+ await Effect.runPromise(Effect.gen(function* () {
565
+ const workflow = yield* EvalProjectWorkflow;
566
+ const proposedBasis = yield* workflow.proposeDimensions(beforePlanRoot, reviewedProposedDimensions);
567
+ yield* workflow.approveDimensions(beforePlanRoot, proposedBasis.artifacts.basisProposalDigest);
568
+ const proposed = yield* workflow.proposeEvaluations(beforePlanRoot, reviewedEvaluationInput);
569
+ yield* workflow.approveEvaluations(beforePlanRoot, proposed.artifacts.evaluationProposalDigest);
570
+ }).pipe(Effect.provide(ProjectWorkflowTestLive)));
571
+ await writeFile(path.join(beforePlanRoot, "README.md"), "# Example application\n\nChanged before planning.\n");
572
+ const stale = await Effect.runPromise(Effect.gen(function* () {
573
+ const workflow = yield* EvalProjectWorkflow;
574
+ const status = yield* workflow.status(beforePlanRoot);
575
+ const planExit = yield* Effect.exit(workflow.createPlan(beforePlanRoot, "pilot"));
576
+ return { status, planExit };
577
+ }).pipe(Effect.provide(ProjectWorkflowTestLive)));
578
+ assert.equal(stale.status?.artifacts?.evaluationsApproved, false);
579
+ assert.equal(stale.status?.nextAction, "approve-evaluations");
580
+ assert.equal(stale.planExit._tag, "Failure");
581
+ if (stale.planExit._tag === "Failure") {
582
+ assert.match(String(stale.planExit.cause), /evidence source changed after authoring/u);
583
+ }
584
+ });
585
+ test("ready projects can explicitly rebind stale evaluation approvals", async () => {
586
+ const root = await makeRepository();
587
+ await completeProjectSetup(root);
588
+ const rebound = await Effect.runPromise(Effect.gen(function* () {
589
+ const workflow = yield* EvalProjectWorkflow;
590
+ const proposedBasis = yield* workflow.proposeDimensions(root, reviewedProposedDimensions);
591
+ yield* workflow.approveDimensions(root, proposedBasis.artifacts.basisProposalDigest);
592
+ const proposed = yield* workflow.proposeEvaluations(root, reviewedEvaluationInput);
593
+ const digest = proposed.artifacts.evaluationProposalDigest;
594
+ const ready = yield* workflow.approveEvaluations(root, digest);
595
+ yield* Effect.promise(() => writeFile(path.join(root, ".routekit", "evals", "evaluations.approval.json"), `${JSON.stringify({
596
+ version: 1,
597
+ kind: "evaluations",
598
+ digest,
599
+ approvedAt: "2026-08-30T00:00:00.000Z"
600
+ })}\n`, { mode: 0o600 }));
601
+ const stale = yield* workflow.status(root);
602
+ const reboundStatus = yield* workflow.approveEvaluations(root, digest);
603
+ return { ready, stale, reboundStatus };
604
+ }).pipe(Effect.provide(ProjectWorkflowTestLive)));
605
+ assert.equal(rebound.ready.state.stage, "ready");
606
+ assert.ok(rebound.stale !== undefined);
607
+ assert.equal(rebound.stale.state.stage, "ready");
608
+ assert.equal(rebound.stale.artifacts?.evaluationsApproved, false);
609
+ assert.equal(rebound.stale.nextAction, "approve-evaluations");
610
+ assert.equal(rebound.reboundStatus.state.stage, "ready");
611
+ assert.equal(rebound.reboundStatus.artifacts?.evaluationsApproved, true);
612
+ assert.equal(rebound.reboundStatus.nextAction, "run");
613
+ });
407
614
  test("full qualification refuses fewer than twenty reviewed cases per dimension", async () => {
408
615
  const root = await makeRepository();
409
616
  await completeProjectSetup(root);
@@ -412,6 +619,7 @@ test("full qualification refuses fewer than twenty reviewed cases per dimension"
412
619
  const proposed = yield* workflow.proposeDimensions(root, reviewedProposedDimensions);
413
620
  yield* workflow.approveDimensions(root, proposed.artifacts.basisProposalDigest);
414
621
  const evaluations = yield* workflow.proposeEvaluations(root, {
622
+ evidenceSources: reviewedEvidenceSources,
415
623
  suites: reviewedSuites.map((suite) => ({ ...suite, cases: suite.cases.slice(0, 5) })),
416
624
  decompositionBenchmark: {
417
625
  ...reviewedDecompositionBenchmark,
@@ -564,18 +772,25 @@ const qualifiedReport = (plan, runId, projectId, publishAllowed = true) => {
564
772
  expectedCases: plan.selectedCompositionCaseIds.length,
565
773
  comparableCases: plan.selectedCompositionCaseIds.length,
566
774
  agreeingCases: plan.selectedCompositionCaseIds.length,
567
- winnerAgreement: 1,
775
+ ...(plan.selectedCompositionCaseIds.length === 0
776
+ ? {}
777
+ : { winnerAgreement: 1 }),
778
+ conclusion: plan.selectedCompositionCaseIds.length === 0 ? "inconclusive" : "passed",
779
+ publishable: plan.scope === "full" && plan.selectedCompositionCaseIds.length > 0,
568
780
  cases: plan.selectedCompositionCaseIds.map((caseId) => ({
569
781
  caseId,
570
782
  predictedWinner: candidateModels[0],
783
+ predictedTiedModels: [],
571
784
  observedWinner: candidateModels[0],
785
+ observedTiedModels: [],
572
786
  predictedScoreGap: 0.1,
573
787
  observedScoreGap: 0.2,
788
+ comparable: true,
574
789
  passed: true
575
790
  }))
576
791
  }
577
792
  },
578
- ledger: Effect.runSync(summarizeEvalRunLedger(comparisons, plan.expectedCallCount, testCostService, observations)),
793
+ ledger: Effect.runSync(summarizeEvalRunLedger(comparisons, plan.expectedCallCount, testCostService, observations, plan.classifierModel)),
579
794
  activation: {
580
795
  version: 2,
581
796
  generatedAt: "2026-08-18T00:02:00.000Z",
@@ -599,7 +814,8 @@ const qualifiedReport = (plan, runId, projectId, publishAllowed = true) => {
599
814
  failureRate: 0,
600
815
  averageJudgeScore: 0.9,
601
816
  p95DurationMs: 250,
602
- unpricedCalls: plan.scope === "pilot" ? 5 : 20
817
+ averageCostUsd: 0.01,
818
+ unpricedCalls: 0
603
819
  })))
604
820
  }
605
821
  };
@@ -633,7 +849,7 @@ test("run lifecycle retains complete sanitized evidence and activates only after
633
849
  assert.equal(outcome.loaded?.status, "passed");
634
850
  assert.equal(outcome.loaded?.ledger.observedCalls, 740);
635
851
  assert.equal(outcome.loaded?.ledger.observedCandidateRows, 360);
636
- assert.equal(outcome.loaded?.ledger.unpricedCalls, 740);
852
+ assert.equal(outcome.loaded?.ledger.unpricedCalls, 0);
637
853
  assert.equal(outcome.activated.state.stage, "activated");
638
854
  const reportPath = path.join(root, ".routekit", "evals", "runs", outcome.started.runId, "report.json");
639
855
  assert.equal((await stat(reportPath)).mode & 0o777, 0o600);
@@ -695,6 +911,98 @@ test("finishRun derives ledger expectations from the selected case slice", async
695
911
  assert.equal(outcome.report.ledger.observedCalls, 4);
696
912
  assert.equal(outcome.report.ledger.observedCandidateRows, 2);
697
913
  });
914
+ test("zero-comparable pilot persists a completed inconclusive diagnostic", async () => {
915
+ const root = await makeRepository();
916
+ const plan = await createPlan(root, "pilot");
917
+ const outcome = await Effect.runPromise(Effect.gen(function* () {
918
+ const workflow = yield* EvalProjectWorkflow;
919
+ const started = yield* workflow.startRun(root, plan.planId);
920
+ const status = yield* workflow.status(root);
921
+ const passing = qualifiedReport(plan, started.runId, status.state.projectId);
922
+ assert.equal(passing.status, "passed");
923
+ if (passing.status !== "passed")
924
+ return undefined;
925
+ const report = {
926
+ ...passing,
927
+ status: "completed",
928
+ qualification: {
929
+ ...passing.qualification,
930
+ composition: {
931
+ expectedCases: plan.selectedCompositionCaseIds.length,
932
+ comparableCases: 0,
933
+ agreeingCases: 0,
934
+ conclusion: "inconclusive",
935
+ reason: "insufficient top-two separation",
936
+ publishable: false,
937
+ cases: plan.selectedCompositionCaseIds.map((caseId) => ({
938
+ caseId,
939
+ predictedWinner: null,
940
+ predictedTiedModels: [...plan.candidateModels],
941
+ observedWinner: null,
942
+ observedTiedModels: [...plan.candidateModels],
943
+ predictedScoreGap: 0,
944
+ observedScoreGap: 0,
945
+ comparable: false,
946
+ passed: false
947
+ }))
948
+ }
949
+ }
950
+ };
951
+ const finished = yield* workflow.finishRun(root, report);
952
+ const persisted = yield* workflow.result(root, started.runId);
953
+ return { finished, persisted };
954
+ }).pipe(Effect.provide(ProjectWorkflowTestLive)));
955
+ assert.equal(outcome?.finished.state.stage, "ready");
956
+ assert.equal(outcome?.persisted?.status, "completed");
957
+ assert.equal(outcome?.persisted?.qualification?.composition.expectedCases, 5);
958
+ assert.equal(outcome?.persisted?.qualification?.composition.comparableCases, 0);
959
+ assert.equal(outcome?.persisted?.qualification?.composition.winnerAgreement, undefined);
960
+ assert.equal(outcome?.persisted?.qualification?.composition.conclusion, "inconclusive");
961
+ assert.equal(outcome?.persisted?.qualification?.composition.publishable, false);
962
+ });
963
+ test("zero-comparable full qualification remains fail closed and unpublished", async () => {
964
+ const root = await makeRepository();
965
+ const plan = await createPlan(root, "full");
966
+ const outcome = await Effect.runPromise(Effect.gen(function* () {
967
+ const workflow = yield* EvalProjectWorkflow;
968
+ const started = yield* workflow.startRun(root, plan.planId);
969
+ const status = yield* workflow.status(root);
970
+ const passing = qualifiedReport(plan, started.runId, status.state.projectId);
971
+ assert.equal(passing.status, "passed");
972
+ if (passing.status !== "passed")
973
+ return undefined;
974
+ const report = {
975
+ ...passing,
976
+ qualification: {
977
+ ...passing.qualification,
978
+ composition: {
979
+ expectedCases: plan.selectedCompositionCaseIds.length,
980
+ comparableCases: 0,
981
+ agreeingCases: 0,
982
+ conclusion: "inconclusive",
983
+ reason: "insufficient top-two separation",
984
+ publishable: false,
985
+ cases: plan.selectedCompositionCaseIds.map((caseId) => ({
986
+ caseId,
987
+ predictedWinner: null,
988
+ predictedTiedModels: [...plan.candidateModels],
989
+ observedWinner: null,
990
+ observedTiedModels: [...plan.candidateModels],
991
+ predictedScoreGap: 0,
992
+ observedScoreGap: 0,
993
+ comparable: false,
994
+ passed: false
995
+ }))
996
+ }
997
+ }
998
+ };
999
+ const finished = yield* Effect.exit(workflow.finishRun(root, report));
1000
+ const current = yield* workflow.status(root);
1001
+ return { finished, current };
1002
+ }).pipe(Effect.provide(ProjectWorkflowTestLive)));
1003
+ assert.equal(outcome?.finished._tag, "Failure");
1004
+ assert.equal(outcome?.current?.state.stage, "running");
1005
+ });
698
1006
  test("failed runs preserve plan revisions for retry while mismatched plans remain stale", async () => {
699
1007
  const root = await makeRepository();
700
1008
  const plan = await createPlan(root, "full");
@@ -755,6 +1063,33 @@ test("failed runs preserve plan revisions for retry while mismatched plans remai
755
1063
  unpricedCalls: 0,
756
1064
  subscriptionUnitCalls: 0
757
1065
  },
1066
+ events: [
1067
+ {
1068
+ name: "plan",
1069
+ at: "2026-08-21T03:47:27.000Z",
1070
+ runId: first.runId,
1071
+ plannedCalls: plan.expectedCallCount
1072
+ },
1073
+ {
1074
+ name: "failure-detail",
1075
+ at: "2026-08-21T03:47:48.000Z",
1076
+ runId: first.runId,
1077
+ phase: "target",
1078
+ reason: "qualification timed out before observing any calls",
1079
+ retryable: true,
1080
+ accounting: {
1081
+ expectedCalls: plan.expectedCallCount,
1082
+ observedCalls: 0,
1083
+ knownInputTokens: 0,
1084
+ knownOutputTokens: 0,
1085
+ unknownTokenMeasurements: 0,
1086
+ knownPricedSubtotalUsd: 0,
1087
+ unpricedCalls: 0,
1088
+ subscriptionUnitCalls: 0
1089
+ },
1090
+ cleanup: { sessionOpened: true, sessionClosed: true }
1091
+ }
1092
+ ],
758
1093
  failure: "qualification timed out before observing any calls",
759
1094
  errors: []
760
1095
  });
@@ -779,7 +1114,7 @@ test("startRun rematerializes stale dimension and composition suite templates",
779
1114
  const dimensionManifestPath = path.join(dimensionRoot, "routekit.eval-manifest.json");
780
1115
  const compositionManifestPath = path.join(compositionRoot, "routekit.eval-manifest.json");
781
1116
  const staleTemplate = `// generated by RouteKit 1.0.21
782
- await judge.autoEvals({ criteria: testCase.rubric, prompt, run });
1117
+ await judge.autoEvals({ criteria: mixedCase.rubric, prompt, run });
783
1118
  run.toComplete();
784
1119
  `;
785
1120
  await Promise.all([
@@ -808,6 +1143,7 @@ run.toComplete();
808
1143
  assert.doesNotMatch(suite, /generated by RouteKit 1\.0\.21/u);
809
1144
  assert.match(suite, /emit the complete target-protocol envelope and terminal event/u);
810
1145
  assert.match(suite, /include the concrete output rather than only describing it/u);
1146
+ assert.match(suite, /You are a strict evaluator for AI agent outputs\./u);
811
1147
  assert.ok(judgeCall >= 0);
812
1148
  assert.ok(completionAssertion >= 0);
813
1149
  assert.ok(completionAssertion < judgeCall);
@@ -860,6 +1196,33 @@ test("failed run reports persist the nested qualification error chain", async ()
860
1196
  unpricedCalls: 0,
861
1197
  subscriptionUnitCalls: 0
862
1198
  },
1199
+ events: [
1200
+ {
1201
+ name: "plan",
1202
+ at: "2026-08-21T03:47:27.000Z",
1203
+ runId: started.runId,
1204
+ plannedCalls: plan.expectedCallCount
1205
+ },
1206
+ {
1207
+ name: "failure-detail",
1208
+ at: "2026-08-21T03:47:48.000Z",
1209
+ runId: started.runId,
1210
+ phase: "comparison",
1211
+ reason: "RouteKit Eval comparison failed",
1212
+ retryable: false,
1213
+ accounting: {
1214
+ expectedCalls: plan.expectedCallCount,
1215
+ observedCalls: 0,
1216
+ knownInputTokens: 0,
1217
+ knownOutputTokens: 0,
1218
+ unknownTokenMeasurements: 0,
1219
+ knownPricedSubtotalUsd: 0,
1220
+ unpricedCalls: 0,
1221
+ subscriptionUnitCalls: 0
1222
+ },
1223
+ cleanup: { sessionOpened: true, sessionClosed: true }
1224
+ }
1225
+ ],
863
1226
  failure: 'qualification dimension "provider-protocol-translation" failed ' +
864
1227
  "(per-test timeout 600000ms); observed call ids: none",
865
1228
  errors: [
@@ -0,0 +1 @@
1
+ export {};