@velum-labs/routekit-eval-setup 1.3.2 → 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 (342) 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 -10
  44. package/dist/effect-api.js +56 -6
  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 +140 -0
  52. package/dist/eval-event-log.js +220 -0
  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 -17
  72. package/dist/index.js +69 -11
  73. package/dist/inspection.js +2 -3
  74. package/dist/project-artifacts.d.ts +7 -2
  75. package/dist/project-artifacts.js +49 -136
  76. package/dist/project-authoring.d.ts +66 -5
  77. package/dist/project-authoring.js +783 -109
  78. package/dist/project-contracts.d.ts +419 -84
  79. package/dist/project-contracts.js +160 -52
  80. package/dist/project-store.js +2 -1
  81. package/dist/project-workflow.d.ts +5 -4
  82. package/dist/project-workflow.js +154 -35
  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.d.ts +1 -0
  239. package/dist/test/eval-event-log.test.js +125 -0
  240. package/dist/test/evaluation-evidence-freshness.test.d.ts +1 -0
  241. package/dist/test/evaluation-evidence-freshness.test.js +44 -0
  242. package/dist/test/evaluation-evidence.test.d.ts +1 -0
  243. package/dist/test/evaluation-evidence.test.js +230 -0
  244. package/dist/test/evaluation-grader-calibration.test.d.ts +1 -0
  245. package/dist/test/evaluation-grader-calibration.test.js +373 -0
  246. package/dist/test/evaluation-proposal-digest.test.d.ts +1 -0
  247. package/dist/test/evaluation-proposal-digest.test.js +187 -0
  248. package/dist/test/evaluation-source-retrieval.test.d.ts +1 -0
  249. package/dist/test/evaluation-source-retrieval.test.js +237 -0
  250. package/dist/test/evaluation-structure-policy.test.d.ts +1 -0
  251. package/dist/test/evaluation-structure-policy.test.js +196 -0
  252. package/dist/test/fixtures/repository-resource-panel.d.ts +39 -0
  253. package/dist/test/fixtures/repository-resource-panel.js +111 -0
  254. package/dist/test/fixtures/vitest-boundary-panel.d.ts +84 -0
  255. package/dist/test/fixtures/vitest-boundary-panel.js +120 -0
  256. package/dist/test/fixtures/vitest-phase-panel.d.ts +135 -0
  257. package/dist/test/fixtures/vitest-phase-panel.js +213 -0
  258. package/dist/test/fixtures/vitest-reporter-results.d.ts +76 -0
  259. package/dist/test/fixtures/vitest-reporter-results.js +94 -0
  260. package/dist/test/grounded-authoring.test.d.ts +1 -0
  261. package/dist/test/grounded-authoring.test.js +565 -0
  262. package/dist/test/integrated-repository-history.test.d.ts +1 -0
  263. package/dist/test/integrated-repository-history.test.js +227 -0
  264. package/dist/test/project-authoring.test.js +593 -43
  265. package/dist/test/project-workflow.test.js +419 -40
  266. package/dist/test/repository-authoring-artifacts.test.d.ts +1 -0
  267. package/dist/test/repository-authoring-artifacts.test.js +185 -0
  268. package/dist/test/repository-bundle.test.d.ts +1 -0
  269. package/dist/test/repository-bundle.test.js +52 -0
  270. package/dist/test/repository-case-generation.test.d.ts +1 -0
  271. package/dist/test/repository-case-generation.test.js +3465 -0
  272. package/dist/test/repository-command-diagnostic.test.d.ts +1 -0
  273. package/dist/test/repository-command-diagnostic.test.js +55 -0
  274. package/dist/test/repository-command-signals.test.d.ts +1 -0
  275. package/dist/test/repository-command-signals.test.js +124 -0
  276. package/dist/test/repository-fixture-scope-coverage.test.d.ts +1 -0
  277. package/dist/test/repository-fixture-scope-coverage.test.js +127 -0
  278. package/dist/test/repository-fixture-validation.test.d.ts +1 -0
  279. package/dist/test/repository-fixture-validation.test.js +362 -0
  280. package/dist/test/repository-foundry-progress.test.d.ts +1 -0
  281. package/dist/test/repository-foundry-progress.test.js +110 -0
  282. package/dist/test/repository-foundry-quality.test.d.ts +1 -0
  283. package/dist/test/repository-foundry-quality.test.js +1138 -0
  284. package/dist/test/repository-import-context.test.d.ts +1 -0
  285. package/dist/test/repository-import-context.test.js +354 -0
  286. package/dist/test/repository-model-authoring.test.d.ts +1 -0
  287. package/dist/test/repository-model-authoring.test.js +544 -0
  288. package/dist/test/repository-model.test.d.ts +1 -0
  289. package/dist/test/repository-model.test.js +2195 -0
  290. package/dist/test/repository-node-test-reporter.test.d.ts +1 -0
  291. package/dist/test/repository-node-test-reporter.test.js +104 -0
  292. package/dist/test/repository-oracle-concurrency.test.d.ts +1 -0
  293. package/dist/test/repository-oracle-concurrency.test.js +542 -0
  294. package/dist/test/repository-oracle-coverage-witness.test.d.ts +1 -0
  295. package/dist/test/repository-oracle-coverage-witness.test.js +511 -0
  296. package/dist/test/repository-oracle-coverage.test.d.ts +1 -0
  297. package/dist/test/repository-oracle-coverage.test.js +168 -0
  298. package/dist/test/repository-oracle-evidence.test.d.ts +1 -0
  299. package/dist/test/repository-oracle-evidence.test.js +185 -0
  300. package/dist/test/repository-oracle-plan.test.d.ts +1 -0
  301. package/dist/test/repository-oracle-plan.test.js +176 -0
  302. package/dist/test/repository-overlay-isolation.test.d.ts +1 -0
  303. package/dist/test/repository-overlay-isolation.test.js +85 -0
  304. package/dist/test/repository-preparation-cache.test.d.ts +1 -0
  305. package/dist/test/repository-preparation-cache.test.js +414 -0
  306. package/dist/test/repository-public-artifact.test.d.ts +1 -0
  307. package/dist/test/repository-public-artifact.test.js +273 -0
  308. package/dist/test/repository-qualification-diagnostics.test.d.ts +1 -0
  309. package/dist/test/repository-qualification-diagnostics.test.js +524 -0
  310. package/dist/test/repository-reference-authoring.test.d.ts +1 -0
  311. package/dist/test/repository-reference-authoring.test.js +1633 -0
  312. package/dist/test/repository-review-evidence-v2.test.d.ts +1 -0
  313. package/dist/test/repository-review-evidence-v2.test.js +183 -0
  314. package/dist/test/repository-review-evidence.test.d.ts +1 -0
  315. package/dist/test/repository-review-evidence.test.js +124 -0
  316. package/dist/test/repository-seed-exclusions.test.d.ts +1 -0
  317. package/dist/test/repository-seed-exclusions.test.js +96 -0
  318. package/dist/test/repository-seed-selection.test.d.ts +1 -0
  319. package/dist/test/repository-seed-selection.test.js +504 -0
  320. package/dist/test/repository-semantic-calibration.test.d.ts +1 -0
  321. package/dist/test/repository-semantic-calibration.test.js +688 -0
  322. package/dist/test/repository-solution-edits.test.d.ts +1 -0
  323. package/dist/test/repository-solution-edits.test.js +377 -0
  324. package/dist/test/repository-specification-budget.test.d.ts +1 -0
  325. package/dist/test/repository-specification-budget.test.js +171 -0
  326. package/dist/test/repository-specification-contract-checkpoint.test.d.ts +1 -0
  327. package/dist/test/repository-specification-contract-checkpoint.test.js +228 -0
  328. package/dist/test/repository-specification-contract-facts.test.d.ts +1 -0
  329. package/dist/test/repository-specification-contract-facts.test.js +177 -0
  330. package/dist/test/repository-trajectory-authoring.test.d.ts +1 -0
  331. package/dist/test/repository-trajectory-authoring.test.js +176 -0
  332. package/dist/test/repository-valid-control-plan.test.d.ts +1 -0
  333. package/dist/test/repository-valid-control-plan.test.js +45 -0
  334. package/dist/test/repository-vitest-phase.test.d.ts +1 -0
  335. package/dist/test/repository-vitest-phase.test.js +848 -0
  336. package/dist/test/repository-vitest-reporter.test.d.ts +1 -0
  337. package/dist/test/repository-vitest-reporter.test.js +158 -0
  338. package/dist/test/repository-workspace-build.test.d.ts +1 -0
  339. package/dist/test/repository-workspace-build.test.js +160 -0
  340. package/dist/test/strict-authoring-schema.test.d.ts +1 -0
  341. package/dist/test/strict-authoring-schema.test.js +169 -0
  342. package/package.json +48 -6
@@ -0,0 +1,414 @@
1
+ import assert from "node:assert/strict";
2
+ import { execFile } from "node:child_process";
3
+ import { randomUUID } from "node:crypto";
4
+ import { access, mkdir, mkdtemp, readdir, readFile, realpath, rm, writeFile } from "node:fs/promises";
5
+ import { tmpdir } from "node:os";
6
+ import { join } from "node:path";
7
+ import { test } from "node:test";
8
+ import { promisify } from "node:util";
9
+ import { Effect, Fiber } from "effect";
10
+ import { makeRepositoryPreparationCacheV1, RepositoryReadOnlyPnpmStore, replayRepositoryCommandsV1 } from "../adapters/repository-command-runner.js";
11
+ const exec = promisify(execFile);
12
+ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
13
+ async function fixture(t) {
14
+ const root = await realpath(await mkdtemp(join(tmpdir(), "preparation-cache-unit-")));
15
+ t.after(() => rm(root, { recursive: true, force: true }));
16
+ const marker = `ready-${randomUUID()}.json`;
17
+ await mkdir(join(root, "tool"));
18
+ await writeFile(join(root, "package.json"), JSON.stringify({
19
+ name: "preparation-cache-fixture",
20
+ private: true,
21
+ packageManager: "pnpm@11.15.1",
22
+ dependencies: { "fixture-tool": "workspace:*" }
23
+ }));
24
+ await writeFile(join(root, "pnpm-workspace.yaml"), "packages:\n - tool\n");
25
+ await writeFile(join(root, "pnpm-lock.yaml"), `lockfileVersion: '9.0'
26
+ settings:
27
+ autoInstallPeers: true
28
+ excludeLinksFromLockfile: false
29
+ importers:
30
+ .:
31
+ dependencies:
32
+ fixture-tool:
33
+ specifier: workspace:*
34
+ version: link:tool
35
+ tool: {}
36
+ `);
37
+ await writeFile(join(root, "tool/package.json"), JSON.stringify({
38
+ name: "fixture-tool",
39
+ version: "1.0.0",
40
+ bin: { "fixture-tool": "bin.cjs" }
41
+ }));
42
+ await writeFile(join(root, "tool/bin.cjs"), `#!/usr/bin/env node
43
+ console.log(JSON.stringify({ value: require('./value.json'), nodePath: process.env.NODE_PATH, path: __dirname }));
44
+ `, { mode: 0o755 });
45
+ await writeFile(join(root, "mode.json"), '"clean"');
46
+ await writeFile(join(root, "template-path.json"), "null");
47
+ await writeFile(join(root, "case.test.mjs"), `
48
+ import assert from 'node:assert/strict';
49
+ import { execFileSync } from 'node:child_process';
50
+ import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
51
+ import { join } from 'node:path';
52
+ import { test } from 'node:test';
53
+ test('installed candidate remains isolated', async () => {
54
+ assert.equal(existsSync(join(process.env.HOME, 'poison')), false);
55
+ assert.equal(existsSync(join(process.env.TMPDIR, 'poison')), false);
56
+ const pnpmConfig = key => execFileSync('corepack', ['pnpm@11.15.1', 'config', 'get', key], { encoding: 'utf8' }).trim();
57
+ assert.equal(pnpmConfig('offline'), 'true');
58
+ const store = pnpmConfig('store-dir');
59
+ assert.notEqual(store, 'undefined');
60
+ assert.equal(store.startsWith(process.env.HOME + '/'), false, 'candidate uses the shared read-only store, not its temporary home');
61
+ assert.match(store, /routekit-foundry-pnpm-store-/, 'candidate uses the host-selected writable runtime store');
62
+ const installed = JSON.parse(execFileSync('corepack', ['pnpm@11.15.1', 'exec', 'fixture-tool'], { encoding: 'utf8' }));
63
+ assert.equal(installed.value, 1);
64
+ assert.ok(installed.path.startsWith(process.cwd()));
65
+ assert.ok(installed.nodePath.includes(process.cwd()));
66
+ assert.equal(installed.nodePath.includes('routekit-foundry-prepared-'), false);
67
+ const templatePath = JSON.parse(readFileSync('template-path.json', 'utf8'));
68
+ if (templatePath !== null) {
69
+ assert.equal(typeof templatePath, 'string');
70
+ const templateStat = statSync(join(templatePath, 'tool/value.json'));
71
+ const replayStat = statSync(join(process.cwd(), 'node_modules/fixture-tool/value.json'));
72
+ assert.equal(
73
+ templateStat.dev === replayStat.dev && templateStat.ino === replayStat.ino,
74
+ false,
75
+ 'candidate replay must not hard-link prepared template files'
76
+ );
77
+ }
78
+ const mode = JSON.parse(readFileSync('mode.json', 'utf8'));
79
+ if (mode === 'poison') {
80
+ if (process.platform === 'darwin') {
81
+ assert.throws(() => writeFileSync(join(templatePath, 'tool/value.json'), '999'), error => error.code === 'EACCES' || error.code === 'EPERM');
82
+ }
83
+ writeFileSync('node_modules/fixture-tool/value.json', '999');
84
+ writeFileSync('node_modules/.bin/fixture-tool', 'poison');
85
+ writeFileSync(join(process.env.HOME, 'poison'), 'poison');
86
+ writeFileSync(join(process.env.TMPDIR, 'poison'), 'poison');
87
+ }
88
+ if (mode === 'wait') {
89
+ writeFileSync(${JSON.stringify(marker)}, JSON.stringify({ pid: process.pid, checkout: process.cwd(), home: process.env.HOME, temporary: process.env.TMPDIR }));
90
+ await new Promise(() => setInterval(() => {}, 1000));
91
+ }
92
+ });
93
+ `);
94
+ const git = (...args) => exec("git", ["-C", root, ...args]);
95
+ await git("init", "-q");
96
+ const commit = async () => {
97
+ await git("add", ".");
98
+ await git("-c", "core.hooksPath=/dev/null", "-c", "commit.gpgsign=false", "-c", "user.name=Fixture", "-c", "user.email=fixture@example.test", "commit", "-qm", "synthetic fixture");
99
+ return (await git("rev-parse", "HEAD")).stdout.trim();
100
+ };
101
+ await writeFile(join(root, "tool/value.json"), "1");
102
+ const initial = await commit();
103
+ await writeFile(join(root, "second-commit.txt"), "distinct immutable commit");
104
+ const reference = await commit();
105
+ const preparation = [
106
+ {
107
+ id: "frozen-install",
108
+ kind: "custom",
109
+ cwd: ".",
110
+ executable: "corepack",
111
+ args: [
112
+ "pnpm@11.15.1",
113
+ "--filter",
114
+ "preparation-cache-fixture...",
115
+ "install",
116
+ "--offline",
117
+ "--frozen-lockfile",
118
+ "--ignore-pnpmfile",
119
+ "--ignore-scripts"
120
+ ],
121
+ timeoutMs: 30000
122
+ }
123
+ ];
124
+ const grade = {
125
+ id: "behavior",
126
+ kind: "test",
127
+ cwd: ".",
128
+ executable: "node",
129
+ args: ["--test", "case.test.mjs"],
130
+ timeoutMs: 30000
131
+ };
132
+ return { root, initial, reference, preparation, grade, marker };
133
+ }
134
+ test("trusted pnpm preparation does not depend on the operating-system account home", async (t) => {
135
+ const f = await fixture(t);
136
+ const [result] = await Effect.runPromise(replayRepositoryCommandsV1({
137
+ repositoryRoot: f.root,
138
+ commit: f.initial,
139
+ recipes: [f.grade],
140
+ repetitions: 1,
141
+ trustedPreparationRecipes: f.preparation,
142
+ fileOverrides: [{ path: "mode.json", content: JSON.stringify("clean") }]
143
+ }));
144
+ assert.ok(result);
145
+ assert.equal(result.exitCode, 0, JSON.stringify(result));
146
+ assert.equal(result.gradeExecuted, true);
147
+ assert.equal(result.trustedPreparationResults.length, 1);
148
+ assert.equal(result.trustedPreparationResults[0]?.exitCode, 0);
149
+ });
150
+ test("an explicitly prehydrated pnpm store stays read-only during offline replay", { timeout: 60_000 }, async (t) => {
151
+ const f = await fixture(t);
152
+ const storeRoot = join(f.root, "prehydrated-store");
153
+ await exec("corepack", [
154
+ "pnpm@11.15.1", "install", "--offline", "--frozen-lockfile", "--ignore-pnpmfile",
155
+ "--ignore-scripts", "--store-dir", storeRoot, "--config.enable-global-virtual-store=false"
156
+ ], { cwd: f.root });
157
+ const store = await realpath((await exec("corepack", [
158
+ "pnpm@11.15.1", "store", "path", "--store-dir", storeRoot, "--silent"
159
+ ], { cwd: f.root })).stdout.trim());
160
+ const forbiddenWrite = join(store, "candidate-must-not-write");
161
+ const [result] = await Effect.runPromise(replayRepositoryCommandsV1({
162
+ repositoryRoot: f.root,
163
+ commit: f.initial,
164
+ repetitions: 1,
165
+ trustedPreparationRecipes: f.preparation,
166
+ recipes: [{
167
+ id: "read-only-store",
168
+ kind: "custom",
169
+ cwd: ".",
170
+ executable: "node",
171
+ args: ["-e", `
172
+ const assert = require("node:assert/strict");
173
+ const fs = require("node:fs");
174
+ assert.equal(process.env.pnpm_config_store_dir, ${JSON.stringify(store)});
175
+ assert.equal(process.env.pnpm_config_frozen_store, "true");
176
+ assert.equal(process.env.pnpm_config_offline, "true");
177
+ if (process.platform === "darwin") {
178
+ assert.throws(() => fs.writeFileSync(${JSON.stringify(forbiddenWrite)}, "forbidden"),
179
+ error => error.code === "EACCES" || error.code === "EPERM");
180
+ }
181
+ `],
182
+ timeoutMs: 10_000
183
+ }]
184
+ }).pipe(Effect.provideService(RepositoryReadOnlyPnpmStore, store)));
185
+ assert.ok(result);
186
+ assert.equal(result.exitCode, 0, JSON.stringify(result));
187
+ assert.equal(result.trustedPreparationResults[0]?.exitCode, 0, JSON.stringify(result));
188
+ await assert.rejects(access(forbiddenWrite), { code: "ENOENT" });
189
+ });
190
+ test("read-only pnpm stores reject unavailable paths and online installation", async (t) => {
191
+ const f = await fixture(t);
192
+ for (const [store, preparation, message] of [
193
+ [".", f.preparation, /requires an absolute path and offline installation/],
194
+ [join(f.root, "missing-store"), f.preparation, /read-only pnpm store is unavailable/],
195
+ [f.root, [{ ...f.preparation[0], args: f.preparation[0].args.filter((arg) => arg !== "--offline") }],
196
+ /requires an absolute path and offline installation/]
197
+ ]) {
198
+ await assert.rejects(Effect.runPromise(replayRepositoryCommandsV1({
199
+ repositoryRoot: f.root,
200
+ commit: f.initial,
201
+ recipes: [f.grade],
202
+ trustedPreparationRecipes: preparation
203
+ }).pipe(Effect.provideService(RepositoryReadOnlyPnpmStore, store))), message);
204
+ }
205
+ });
206
+ test("pristine frozen installs are single-flight and real pnpm clones cannot contaminate later candidates", async (t) => {
207
+ if (process.platform !== "darwin" && process.platform !== "linux") {
208
+ t.skip("pristine reuse is supported on the Unix runners");
209
+ return;
210
+ }
211
+ const f = await fixture(t);
212
+ const templates = [];
213
+ const results = await Effect.runPromise(Effect.scoped(Effect.gen(function* () {
214
+ const cache = yield* makeRepositoryPreparationCacheV1({
215
+ repositoryRoot: f.root,
216
+ commits: [f.initial, f.reference],
217
+ trustedPreparationRecipes: f.preparation
218
+ });
219
+ const request = { repositoryRoot: f.root, commit: f.initial, recipes: f.preparation };
220
+ const [first, duplicate] = yield* Effect.all([cache.get(request), cache.get(request)], {
221
+ concurrency: 2
222
+ });
223
+ assert.ok(first);
224
+ assert.strictEqual(first, duplicate, "concurrent requests share one actual installation resource");
225
+ templates.push(first.isolated.root);
226
+ const second = yield* cache.get({ ...request, commit: f.reference });
227
+ assert.ok(second);
228
+ templates.push(second.isolated.root);
229
+ assert.notEqual(first.key, second.key);
230
+ const replay = (mode) => replayRepositoryCommandsV1({
231
+ repositoryRoot: f.root,
232
+ commit: f.initial,
233
+ recipes: [f.grade],
234
+ repetitions: 2,
235
+ trustedPreparationRecipes: f.preparation,
236
+ preparationCache: cache,
237
+ fileOverrides: [
238
+ { path: "mode.json", content: JSON.stringify(mode) },
239
+ {
240
+ path: "template-path.json",
241
+ content: JSON.stringify(first.isolated.checkout)
242
+ }
243
+ ],
244
+ candidateValidationRecipes: [
245
+ {
246
+ id: "syntax",
247
+ kind: "check",
248
+ cwd: ".",
249
+ executable: "node",
250
+ args: ["--check", "tool/bin.cjs"],
251
+ timeoutMs: 10000
252
+ }
253
+ ]
254
+ });
255
+ const poisoned = yield* replay("poison");
256
+ const clean = yield* replay("clean");
257
+ assert.equal(yield* Effect.promise(() => readFile(join(first.isolated.checkout, "tool/value.json"), "utf8")), "1");
258
+ assert.equal(yield* Effect.promise(() => readFile(join(second.isolated.checkout, "tool/value.json"), "utf8")), "1");
259
+ return [...poisoned, ...clean];
260
+ })));
261
+ assert.equal(results.length, 4);
262
+ for (const result of results) {
263
+ assert.equal(result.exitCode, 0, JSON.stringify(result));
264
+ assert.equal(result.gradeExecuted, true);
265
+ assert.equal(result.candidateValidationResults.length, 1);
266
+ assert.equal(result.trustedPreparationResults.length, 0, "shared preparation is not attributed to a candidate repetition");
267
+ assert.equal(result.preparation?.sharedResults.length, 1);
268
+ assert.equal(result.preparation?.sharedResults[0]?.repetition, 0);
269
+ assert.ok((result.preparation?.cloneDurationMs ?? -1) >= 0);
270
+ }
271
+ for (const root of templates)
272
+ await assert.rejects(access(root));
273
+ assert.equal(await readFile(join(f.root, "tool/value.json"), "utf8"), "1");
274
+ });
275
+ test("preparation reuse rejects changed recipes, unpinned commits, and unsafe install modes", async (t) => {
276
+ const f = await fixture(t);
277
+ await Effect.runPromise(Effect.scoped(Effect.gen(function* () {
278
+ const cache = yield* makeRepositoryPreparationCacheV1({
279
+ repositoryRoot: f.root,
280
+ commits: [f.initial],
281
+ trustedPreparationRecipes: f.preparation
282
+ });
283
+ assert.equal(yield* cache.get({ repositoryRoot: f.root, commit: f.reference, recipes: f.preparation }), undefined);
284
+ assert.equal(yield* cache.get({
285
+ repositoryRoot: f.root,
286
+ commit: f.initial,
287
+ recipes: [{ ...f.preparation[0], timeoutMs: 1 }]
288
+ }), undefined);
289
+ for (const args of [
290
+ f.preparation[0].args.filter((arg) => arg !== "--ignore-scripts"),
291
+ [...f.preparation[0].args, "--ignore-scripts=false"],
292
+ [...f.preparation[0].args, "--config.pnpmfile=hostile.cjs"]
293
+ ]) {
294
+ const recipes = [{ ...f.preparation[0], args }];
295
+ const unsafe = yield* makeRepositoryPreparationCacheV1({
296
+ repositoryRoot: f.root,
297
+ commits: [f.initial],
298
+ trustedPreparationRecipes: recipes
299
+ });
300
+ assert.equal(yield* unsafe.get({ repositoryRoot: f.root, commit: f.initial, recipes }), undefined);
301
+ }
302
+ })));
303
+ });
304
+ test("failed frozen installations retain their actual command evidence and are never reused", async (t) => {
305
+ if (process.platform !== "darwin" && process.platform !== "linux") {
306
+ t.skip("pristine reuse is supported on the Unix runners");
307
+ return;
308
+ }
309
+ const f = await fixture(t);
310
+ const manifest = JSON.parse(await readFile(join(f.root, "package.json"), "utf8"));
311
+ manifest.dependencies["fixture-tool"] = "workspace:^";
312
+ await writeFile(join(f.root, "package.json"), JSON.stringify(manifest));
313
+ await exec("git", ["-C", f.root, "add", "."]);
314
+ await exec("git", [
315
+ "-C",
316
+ f.root,
317
+ "-c",
318
+ "core.hooksPath=/dev/null",
319
+ "-c",
320
+ "commit.gpgsign=false",
321
+ "-c",
322
+ "user.name=Fixture",
323
+ "-c",
324
+ "user.email=fixture@example.test",
325
+ "commit",
326
+ "-qm",
327
+ "synthetic stale lockfile"
328
+ ]);
329
+ const commit = (await exec("git", ["-C", f.root, "rev-parse", "HEAD"])).stdout.trim();
330
+ await Effect.runPromise(Effect.scoped(Effect.gen(function* () {
331
+ const cache = yield* makeRepositoryPreparationCacheV1({
332
+ repositoryRoot: f.root,
333
+ commits: [commit],
334
+ trustedPreparationRecipes: f.preparation
335
+ });
336
+ const causes = [];
337
+ for (let attempt = 0; attempt < 2; attempt += 1) {
338
+ const error = yield* cache
339
+ .get({ repositoryRoot: f.root, commit, recipes: f.preparation })
340
+ .pipe(Effect.match({ onFailure: (error) => error, onSuccess: () => undefined }));
341
+ assert.ok(error, "a stale frozen lockfile cannot publish a prepared template");
342
+ const cause = error.cause;
343
+ assert.equal(cause.trustedPreparationResults.length, 1);
344
+ const command = cause.trustedPreparationResults[0];
345
+ assert.notEqual(command.exitCode, 0);
346
+ assert.equal(command.stage, "trusted-preparation");
347
+ assert.equal(command.repetition, 0);
348
+ assert.match(command.stdout + command.stderr, /OUTDATED_LOCKFILE|frozen-lockfile/u);
349
+ causes.push(cause);
350
+ }
351
+ assert.notStrictEqual(causes[0], causes[1], "failed installation invokes preparation again on the next request");
352
+ })));
353
+ });
354
+ test("interrupting a candidate closes its child process, clone, and scoped pristine template", async (t) => {
355
+ if (process.platform !== "darwin" && process.platform !== "linux") {
356
+ t.skip("pristine reuse is supported on the Unix runners");
357
+ return;
358
+ }
359
+ const f = await fixture(t);
360
+ let templateRoot;
361
+ const fiber = Effect.runFork(Effect.scoped(Effect.gen(function* () {
362
+ const cache = yield* makeRepositoryPreparationCacheV1({
363
+ repositoryRoot: f.root,
364
+ commits: [f.initial],
365
+ trustedPreparationRecipes: f.preparation
366
+ });
367
+ const template = yield* cache.get({
368
+ repositoryRoot: f.root,
369
+ commit: f.initial,
370
+ recipes: f.preparation
371
+ });
372
+ assert.ok(template);
373
+ templateRoot = template.isolated.root;
374
+ yield* replayRepositoryCommandsV1({
375
+ repositoryRoot: f.root,
376
+ commit: f.initial,
377
+ recipes: [f.grade],
378
+ repetitions: 2,
379
+ trustedPreparationRecipes: f.preparation,
380
+ preparationCache: cache,
381
+ fileOverrides: [{ path: "mode.json", content: '"wait"' }]
382
+ });
383
+ })));
384
+ t.after(() => Effect.runPromise(Fiber.interrupt(fiber)));
385
+ let running;
386
+ const deadline = Date.now() + 15000;
387
+ while (running === undefined && Date.now() < deadline) {
388
+ for (const entry of await readdir(tmpdir())) {
389
+ if (!entry.startsWith("routekit-foundry-isolated-"))
390
+ continue;
391
+ try {
392
+ running = JSON.parse(await readFile(join(tmpdir(), entry, "repository", f.marker), "utf8"));
393
+ }
394
+ catch { }
395
+ }
396
+ if (running === undefined)
397
+ await delay(20);
398
+ }
399
+ assert.ok(running, "real cloned candidate reached its blocking grade");
400
+ assert.ok(templateRoot);
401
+ await Effect.runPromise(Fiber.interrupt(fiber));
402
+ for (const path of [templateRoot, running.checkout, running.home, running.temporary])
403
+ await assert.rejects(access(path));
404
+ for (let attempt = 0; attempt < 100; attempt += 1) {
405
+ try {
406
+ process.kill(running.pid, 0);
407
+ }
408
+ catch {
409
+ return;
410
+ }
411
+ await delay(10);
412
+ }
413
+ assert.fail("cancelled candidate child remained alive");
414
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,273 @@
1
+ import assert from "node:assert/strict";
2
+ import { createHash } from "node:crypto";
3
+ import test from "node:test";
4
+ import { pipelineCheckpointDescriptorDigestV2 } from "../case-pipeline-protocol-v2.js";
5
+ import { decodeRepositoryPublicArtifactProjectionV1, makeRepositoryPublicArtifactProjectionV1 } from "../services/repository-public-artifact/service.js";
6
+ const sha = (digit) => digit.repeat(64);
7
+ const createDigest = (value) => createHash("sha256").update(value, "utf8").digest("hex");
8
+ const commit = "b".repeat(40);
9
+ const quality = [
10
+ "authenticity",
11
+ "specification-sufficiency",
12
+ "oracle-adequacy",
13
+ "stability",
14
+ "distinctness",
15
+ "realism",
16
+ "leakage",
17
+ "triviality",
18
+ "coverage"
19
+ ].map((axis) => ({
20
+ axis: axis,
21
+ outcome: "pass"
22
+ }));
23
+ const repositoryVisible = {
24
+ lane: "repository-agent",
25
+ id: "case-routing",
26
+ requestText: "Preserve explicit provider routing.",
27
+ checkoutCommit: commit,
28
+ allowedTools: ["read", "search", "edit", "shell", "test"],
29
+ constraints: ["Do not modify unrelated gateway behavior."]
30
+ };
31
+ const input = {
32
+ version: 1,
33
+ admitted: true,
34
+ caseId: "case-routing",
35
+ capabilityId: "capability-routing",
36
+ familyId: "family-routing",
37
+ lane: "repository-agent",
38
+ visible: repositoryVisible,
39
+ sourceCommitSha: commit,
40
+ coverageCellId: "cell-routing",
41
+ basisDigest: sha("c"),
42
+ behavioralFingerprint: "routing-explicit-provider",
43
+ admissionDigest: sha("d"),
44
+ terminalCheckpoint: {
45
+ version: 2,
46
+ checkpointId: "checkpoint-terminal",
47
+ identityDigest: sha("e"),
48
+ attemptGeneration: 2,
49
+ sequence: 8,
50
+ kind: "terminal",
51
+ stage: "admit",
52
+ parentDigest: sha("f"),
53
+ payloadDigest: sha("1"),
54
+ payloadBytes: 1024,
55
+ createdAt: "2026-09-12T00:00:00.000Z"
56
+ },
57
+ quality
58
+ };
59
+ test("public projection is deterministic, admitted-source-bound, and compiler-ready", () => {
60
+ const first = makeRepositoryPublicArtifactProjectionV1(input);
61
+ const second = makeRepositoryPublicArtifactProjectionV1({
62
+ ...input,
63
+ quality: [...input.quality].reverse()
64
+ });
65
+ assert.deepEqual(first, second);
66
+ assert.equal(first.admitted, true);
67
+ assert.equal(first.artifacts.length, 2);
68
+ assert.equal(first.terminalCheckpointDigest, pipelineCheckpointDescriptorDigestV2(input.terminalCheckpoint));
69
+ assert.deepEqual({
70
+ terminalCheckpointDigest: first.terminalCheckpointDigest,
71
+ projectionDigest: first.projectionDigest,
72
+ artifacts: first.artifacts.map(({ path, publicArtifactDigest, bytes }) => ({
73
+ path,
74
+ publicArtifactDigest,
75
+ bytes
76
+ }))
77
+ }, {
78
+ terminalCheckpointDigest: "eba11c069310c9ed74c391f60702df8270c676bcfa7e76d5a5915557eee9b318",
79
+ projectionDigest: "5868cdf8a567e56d8c6c344405c568cd65d4272fab236397b9c4bbbc484cffda",
80
+ artifacts: [
81
+ {
82
+ path: ".routekit/evals/cases/case-routing-c4ce9ac2e022.eval.json",
83
+ publicArtifactDigest: "7c7017454e45d1b5ca4dedb776c8d62b444067345d599335685e1a3915921da3",
84
+ bytes: 522
85
+ },
86
+ {
87
+ path: ".routekit/evals/cases/case-routing-c4ce9ac2e022.metadata.json",
88
+ publicArtifactDigest: "eed9d36602bbc001bc5412c9b32bf3a0a336673d6eda0e9b14891742b54d3255",
89
+ bytes: 1220
90
+ }
91
+ ]
92
+ });
93
+ assert.doesNotThrow(() => decodeRepositoryPublicArtifactProjectionV1(first));
94
+ for (const artifact of first.artifacts) {
95
+ assert.match(artifact.path, /^\.routekit\/evals\/cases\//u);
96
+ assert.equal(artifact.caseId, input.caseId);
97
+ assert.equal(artifact.admissionDigest, input.admissionDigest);
98
+ assert.equal(artifact.visibility, "public");
99
+ assert.equal(artifact.fileType, "regular");
100
+ assert.equal(artifact.bytes, Buffer.byteLength(artifact.content, "utf8"));
101
+ assert.match(artifact.publicArtifactDigest, /^[a-f0-9]{64}$/u);
102
+ }
103
+ });
104
+ test("public projection cannot represent or leak private foundry evidence", () => {
105
+ const privateCanaries = [
106
+ "HIDDEN_FIXTURE_CANARY",
107
+ "ORACLE_BODY_CANARY",
108
+ "SOLUTION_CANARY",
109
+ "ADVERSARY_CANARY",
110
+ "RAW_MODEL_RESPONSE_CANARY",
111
+ "PROVIDER_DIAGNOSTIC_CANARY",
112
+ "PRIVATE_CHECKPOINT_CANARY",
113
+ "github_pat-PRIVATE_CANARY_1234567890"
114
+ ];
115
+ assert.throws(() => makeRepositoryPublicArtifactProjectionV1({
116
+ ...input,
117
+ hiddenFixtures: privateCanaries,
118
+ oracle: { body: privateCanaries[1] },
119
+ rawModelResponse: privateCanaries[4],
120
+ checkpointPayload: privateCanaries
121
+ }));
122
+ assert.throws(() => makeRepositoryPublicArtifactProjectionV1({
123
+ ...input,
124
+ terminalCheckpoint: {
125
+ ...input.terminalCheckpoint,
126
+ payload: { hiddenFixtures: privateCanaries }
127
+ }
128
+ }));
129
+ assert.throws(() => makeRepositoryPublicArtifactProjectionV1({
130
+ ...input,
131
+ visible: {
132
+ ...input.visible,
133
+ requestText: `Use token ${privateCanaries[5]}`
134
+ }
135
+ }), /private foundry evidence/u);
136
+ const representablePrivateStrings = [
137
+ {
138
+ ...input,
139
+ caseId: privateCanaries[0],
140
+ visible: { ...repositoryVisible, id: privateCanaries[0] }
141
+ },
142
+ { ...input, capabilityId: privateCanaries[1] },
143
+ { ...input, familyId: privateCanaries[2] },
144
+ { ...input, visible: { ...repositoryVisible, requestText: privateCanaries[3] } },
145
+ { ...input, visible: { ...repositoryVisible, constraints: [privateCanaries[4]] } },
146
+ { ...input, coverageCellId: privateCanaries[5] },
147
+ { ...input, behavioralFingerprint: privateCanaries[6] },
148
+ {
149
+ ...input,
150
+ terminalCheckpoint: {
151
+ ...input.terminalCheckpoint,
152
+ checkpointId: privateCanaries[0]
153
+ }
154
+ }
155
+ ];
156
+ for (const privateInput of representablePrivateStrings) {
157
+ assert.throws(() => makeRepositoryPublicArtifactProjectionV1(privateInput), /private foundry evidence/u);
158
+ }
159
+ const requestVisible = {
160
+ lane: "request",
161
+ id: input.caseId,
162
+ request: {
163
+ endpoint: "responses",
164
+ method: "POST",
165
+ path: "/v1/responses",
166
+ headers: [{ name: "content-type", value: "application/json" }],
167
+ bodyJson: "{}"
168
+ }
169
+ };
170
+ const requestInput = {
171
+ ...input,
172
+ lane: "request",
173
+ visible: requestVisible
174
+ };
175
+ for (const visible of [
176
+ {
177
+ ...requestVisible,
178
+ request: { ...requestVisible.request, path: privateCanaries[0] }
179
+ },
180
+ {
181
+ ...requestVisible,
182
+ request: {
183
+ ...requestVisible.request,
184
+ headers: [{ name: privateCanaries[1], value: "application/json" }]
185
+ }
186
+ },
187
+ {
188
+ ...requestVisible,
189
+ request: {
190
+ ...requestVisible.request,
191
+ headers: [{ name: "x-test", value: privateCanaries[2] }]
192
+ }
193
+ },
194
+ {
195
+ ...requestVisible,
196
+ request: { ...requestVisible.request, bodyJson: privateCanaries[4] }
197
+ }
198
+ ]) {
199
+ assert.throws(() => makeRepositoryPublicArtifactProjectionV1({ ...requestInput, visible }), /private foundry evidence/u);
200
+ }
201
+ assert.throws(() => makeRepositoryPublicArtifactProjectionV1({
202
+ ...input,
203
+ visible: {
204
+ ...repositoryVisible,
205
+ requestText: "Use token github_pat-abcdefghijklmnopqrstuvwxyz123456"
206
+ }
207
+ }), /credential/u);
208
+ const projection = makeRepositoryPublicArtifactProjectionV1(input);
209
+ const output = projection.artifacts.map(({ content }) => content).join("\n");
210
+ for (const canary of privateCanaries)
211
+ assert.doesNotMatch(output, new RegExp(canary, "u"));
212
+ });
213
+ test("public projection fails closed on rejected, substituted, failed, and unpinned shapes", () => {
214
+ assert.throws(() => makeRepositoryPublicArtifactProjectionV1({
215
+ ...input,
216
+ admitted: false
217
+ }));
218
+ assert.throws(() => makeRepositoryPublicArtifactProjectionV1({
219
+ ...input,
220
+ visible: { ...input.visible, id: "other-case" }
221
+ }), /identity/u);
222
+ assert.throws(() => makeRepositoryPublicArtifactProjectionV1({
223
+ ...input,
224
+ visible: { ...input.visible, checkoutCommit: "a".repeat(40) }
225
+ }), /pinned/u);
226
+ assert.throws(() => makeRepositoryPublicArtifactProjectionV1({
227
+ ...input,
228
+ terminalCheckpoint: { ...input.terminalCheckpoint, kind: "stage" }
229
+ }));
230
+ assert.throws(() => makeRepositoryPublicArtifactProjectionV1({
231
+ ...input,
232
+ quality: input.quality.map((finding) => finding.axis === "leakage" ? { ...finding, outcome: "fail" } : finding)
233
+ }), /admission quality axis/u);
234
+ assert.throws(() => makeRepositoryPublicArtifactProjectionV1({
235
+ ...input,
236
+ version: 2
237
+ }));
238
+ });
239
+ test("projection schema rejects mutated bytes, provenance, content, and unknown fields", () => {
240
+ const projection = makeRepositoryPublicArtifactProjectionV1(input);
241
+ const [definition, metadata] = projection.artifacts;
242
+ assert.ok(definition);
243
+ assert.ok(metadata);
244
+ assert.throws(() => decodeRepositoryPublicArtifactProjectionV1({
245
+ ...projection,
246
+ artifacts: [{ ...definition, content: `${definition.content} ` }, metadata]
247
+ }), /digest/u);
248
+ const privateContent = definition.content.replace("Preserve explicit provider routing.", "HIDDEN_FIXTURE_CANARY");
249
+ assert.throws(() => decodeRepositoryPublicArtifactProjectionV1({
250
+ ...projection,
251
+ artifacts: [
252
+ {
253
+ ...definition,
254
+ content: privateContent,
255
+ bytes: Buffer.byteLength(privateContent, "utf8"),
256
+ publicArtifactDigest: createDigest(privateContent)
257
+ },
258
+ metadata
259
+ ]
260
+ }), /private foundry evidence/u);
261
+ assert.throws(() => decodeRepositoryPublicArtifactProjectionV1({
262
+ ...projection,
263
+ artifacts: [definition, { ...metadata, admissionDigest: sha("a") }]
264
+ }), /admission/u);
265
+ assert.throws(() => decodeRepositoryPublicArtifactProjectionV1({
266
+ ...projection,
267
+ artifacts: [definition, { ...metadata, privateCheckpoint: { payload: "hidden" } }]
268
+ }));
269
+ assert.throws(() => decodeRepositoryPublicArtifactProjectionV1({
270
+ ...projection,
271
+ projectionDigest: sha("9")
272
+ }), /projection digest/u);
273
+ });