@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,565 @@
1
+ import assert from "node:assert/strict";
2
+ import { execFile } from "node:child_process";
3
+ import { mkdir, mkdtemp, realpath, rm, writeFile } from "node:fs/promises";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { test } from "node:test";
7
+ import { promisify } from "node:util";
8
+ import { Effect, Option, Schema } from "effect";
9
+ import { makeCaseCheckpointStoreV1 } from "../case-checkpoint-store.js";
10
+ import { PipelineBudgetExhaustedError } from "../case-pipeline-protocol.js";
11
+ import { RepositoryFoundryError } from "../errors.js";
12
+ import { BudgetedLanguageModelLive, budgetSnapshotV1, makePipelineStateAccessorV1 } from "../services/budgeted-model/service.js";
13
+ import { GROUNDED_AUTHORING_UNRESOLVED_PREFIX, GROUNDED_FULL_RESULT_WINDOW, GROUNDED_INPUT_BYTES_LIMIT, GROUNDED_MAX_TOOL_TURNS_BEFORE_SUBMIT, GROUNDED_READ_BYTES_PER_TURN, groundedStructuredGenerationV1 } from "../services/grounded-authoring/service.js";
14
+ import { RepositoryFoundryLanguageModel } from "../services/language-model/service.js";
15
+ const execute = promisify(execFile);
16
+ const Answer = Schema.Struct({ answer: Schema.String });
17
+ const assignment = {
18
+ role: "oracle-author",
19
+ model: "openai/gpt-6-astra",
20
+ reasoningEffort: "high"
21
+ };
22
+ const goodCode = `import assert from "node:assert/strict";
23
+ import test from "node:test";
24
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
25
+ import { value } from "./subject.mjs";
26
+ test("frozen public behavior", () => {
27
+ assert.equal(existsSync("candidate-ran.txt"), false);
28
+ writeFileSync("candidate-ran.txt", "fresh candidate only");
29
+ assert.equal(readFileSync("control.json", "utf8"), "reference");
30
+ assert.equal(value, 1);
31
+ });
32
+ `;
33
+ const brokenCode = `${goodCode}\nconst syntaxError = ;\n`;
34
+ const decoderCode = `export function decodeSse(chunk) {
35
+ return chunk.split("\\n\\n").filter(Boolean).map((event) => event.replace(/^data: /u, ""));
36
+ }
37
+ `;
38
+ /** Roughly 300 KB with multi-byte characters so byte slicing must respect UTF-8 boundaries. */
39
+ const bigText = Array.from({ length: 6_000 }, (_, index) => `line ${String(index).padStart(5, "0")} café 中文 ${"x".repeat(32)}`).join("\n");
40
+ async function repository(t) {
41
+ const root = await realpath(await mkdtemp(join(tmpdir(), "grounded-authoring-test-")));
42
+ t.after(() => rm(root, { recursive: true, force: true }));
43
+ const git = (...args) => execute("git", ["-C", root, ...args]);
44
+ await git("init", "-q");
45
+ await mkdir(join(root, "lib"), { recursive: true });
46
+ await writeFile(join(root, "case.test.mjs"), goodCode);
47
+ await writeFile(join(root, "lib", "sse-decoder.mjs"), decoderCode);
48
+ await writeFile(join(root, "big.txt"), bigText);
49
+ const commit = async (value, control) => {
50
+ await writeFile(join(root, "subject.mjs"), `export const value = ${String(value)};\n`);
51
+ await writeFile(join(root, "control.json"), control);
52
+ await git("add", ".");
53
+ await git("-c", "core.hooksPath=/dev/null", "-c", "commit.gpgSign=false", "-c", "user.name=Grounded Authoring", "-c", "user.email=grounded@example.test", "commit", "-qm", "fixture");
54
+ return (await git("rev-parse", "HEAD")).stdout.trim();
55
+ };
56
+ const initialCommit = await commit(0, "initial");
57
+ const referenceCommit = await commit(1, "reference");
58
+ // The working tree is dirty; the loop must only ever see pinned objects.
59
+ await writeFile(join(root, "control.json"), "untrusted working tree");
60
+ await writeFile(join(root, "lib", "sse-decoder.mjs"), "export const decodeSse = undefined;\n");
61
+ const grade = {
62
+ id: "grade",
63
+ kind: "test",
64
+ cwd: ".",
65
+ executable: "node",
66
+ args: ["--test", "case.test.mjs"],
67
+ timeoutMs: 5000
68
+ };
69
+ const observation = (id, subjectId, outcome) => ({
70
+ id,
71
+ kind: "test-command",
72
+ subjectId,
73
+ outcome,
74
+ detail: "Synthetic qualified seed evidence."
75
+ });
76
+ const seed = {
77
+ version: 1,
78
+ id: "synthetic-seed",
79
+ status: "qualified",
80
+ source: { kind: "historical-fix", changeEpisodeId: "synthetic-change" },
81
+ summary: "Synthetic public behavior.",
82
+ capabilityEvidence: [{ kind: "test", id: "case", path: "case.test.mjs" }],
83
+ initialState: { commit: initialCommit },
84
+ referenceCommit,
85
+ targetBehavior: [{ id: "behavior", description: "Return one.", critical: true, evidence: [] }],
86
+ baselineObservations: [observation("baseline", "baseline", "pass")],
87
+ preChangeObservations: [observation("pre", "grade", "fail")],
88
+ postChangeObservations: [observation("post", "grade", "pass")],
89
+ candidateTestIds: ["case"],
90
+ environment: {
91
+ protectedControlPaths: ["control.json"],
92
+ trustedPreparationRecipes: [],
93
+ candidateValidationRecipes: [
94
+ {
95
+ id: "syntax",
96
+ kind: "check",
97
+ cwd: ".",
98
+ executable: "node",
99
+ args: ["--check", "case.test.mjs"],
100
+ timeoutMs: 5000
101
+ }
102
+ ],
103
+ baselineGradeRecipes: [{ ...grade, id: "baseline" }],
104
+ gradeRecipes: [grade]
105
+ },
106
+ confidence: "high",
107
+ risks: [],
108
+ rejectionReasons: []
109
+ };
110
+ return { root, seed, initialCommit, referenceCommit };
111
+ }
112
+ /** A scripted model: each reply may read the previous tool result from the transcript. */
113
+ const scriptedModel = (script) => {
114
+ const seen = [];
115
+ const generateAssignedStructured = (request) => Effect.gen(function* () {
116
+ const input = request.input;
117
+ seen.push({
118
+ operationId: request.operationId,
119
+ schemaName: request.schemaName,
120
+ instructions: request.instructions,
121
+ input
122
+ });
123
+ const raw = script(input, seen.length);
124
+ const value = yield* Schema.decodeUnknownEffect(request.outputSchema)({ turn: raw }).pipe(Effect.mapError((cause) => new RepositoryFoundryError({
125
+ operation: "invoke-language-model",
126
+ detail: `language-model role ${request.assignment.role} violated ${request.schemaName}`,
127
+ cause
128
+ })));
129
+ return {
130
+ value,
131
+ call: {
132
+ operationId: request.operationId,
133
+ role: request.assignment.role,
134
+ model: request.assignment.model,
135
+ reasoningEffort: request.assignment.reasoningEffort,
136
+ callId: `call-${String(seen.length)}`
137
+ }
138
+ };
139
+ });
140
+ const shape = {
141
+ generateAssignedStructured,
142
+ generateStructured: (request) => generateAssignedStructured({
143
+ ...request,
144
+ assignment: { role: request.role, model: assignment.model, reasoningEffort: "high" }
145
+ })
146
+ };
147
+ return { shape, seen };
148
+ };
149
+ const lastResult = (input) => (input.transcript.at(-1)?.result ?? {});
150
+ const initialState = () => ({
151
+ version: 1,
152
+ caseId: "case-1",
153
+ repositoryRoot: "/repo",
154
+ dimension: { id: "dim", description: "A dimension.", includes: [], excludes: [] },
155
+ model: assignment.model,
156
+ stage: "oracle",
157
+ status: "running",
158
+ startedAt: "2026-09-08T00:00:00.000Z",
159
+ updatedAt: "2026-09-08T00:00:00.000Z",
160
+ modelCalls: 0,
161
+ elapsedMs: 0,
162
+ resumeCount: 0,
163
+ folds: 0
164
+ });
165
+ test("grounded work resumes a pending submission with prior execution feedback and no new model call", async (t) => {
166
+ const repo = await repository(t);
167
+ const store = makeCaseCheckpointStoreV1({ caseDirectory: join(repo.root, "private-work") });
168
+ const model = scriptedModel((_input, turn) => turn === 1
169
+ ? { action: "read_files", commit: "reference", paths: ["lib/sse-decoder.mjs"], reason: "ground" }
170
+ : { action: "submit", result: { answer: turn === 2 ? "draft" : "repaired" } });
171
+ let interrupted = false;
172
+ let validations = 0;
173
+ const input = {
174
+ languageModel: model.shape,
175
+ assignment,
176
+ operationId: "resume:author",
177
+ instructions: "Ground then submit.",
178
+ task: { goal: "durable feedback" },
179
+ outputSchema: Answer,
180
+ schemaName: "Answer",
181
+ checkpointStore: store,
182
+ tools: {
183
+ repositoryRoot: repo.root,
184
+ commits: { initial: repo.initialCommit, reference: repo.referenceCommit }
185
+ },
186
+ validateSubmission: (value) => Effect.gen(function* () {
187
+ validations += 1;
188
+ if (value.answer === "draft")
189
+ return [{ kind: "execution", message: "Preserve this concrete failure." }];
190
+ if (!interrupted) {
191
+ interrupted = true;
192
+ return yield* new RepositoryFoundryError({
193
+ operation: "run-pipeline-stage",
194
+ detail: "simulated interruption during preflight"
195
+ });
196
+ }
197
+ return [];
198
+ })
199
+ };
200
+ const first = await Effect.runPromise(groundedStructuredGenerationV1(input).pipe(Effect.result));
201
+ assert.equal(first._tag, "Failure");
202
+ assert.equal(model.seen.length, 3);
203
+ const resumed = await Effect.runPromise(groundedStructuredGenerationV1({
204
+ ...input,
205
+ // Restore through a new store object, as in a new capability process.
206
+ checkpointStore: makeCaseCheckpointStoreV1({ caseDirectory: store.caseDirectory })
207
+ }));
208
+ assert.equal(model.seen.length, 3, "do not repurchase a received pending action");
209
+ assert.equal(resumed.turns, 3);
210
+ assert.deepEqual(resumed.transcript.map((entry) => entry.action.action), ["read_files", "submit", "submit"]);
211
+ assert.deepEqual(resumed.transcript[1].result.findings, [
212
+ { kind: "execution", message: "Preserve this concrete failure." }
213
+ ]);
214
+ assert.equal(resumed.value.answer, "repaired");
215
+ assert.equal(validations, 3, "only incomplete preflight repeats");
216
+ const completed = await Effect.runPromise(groundedStructuredGenerationV1(input));
217
+ assert.equal(completed.value.answer, "repaired");
218
+ assert.equal(model.seen.length, 3);
219
+ assert.equal(validations, 3, "accepted work survives interruption before the stage checkpoint");
220
+ });
221
+ test("grounded work binds task, pinned trees, policy and schema instead of trusting an operation name", async (t) => {
222
+ const repo = await repository(t);
223
+ const store = makeCaseCheckpointStoreV1({ caseDirectory: join(repo.root, "private-work") });
224
+ const model = scriptedModel((_input, turn) => ({ action: "submit", result: { answer: String(turn) } }));
225
+ const input = {
226
+ languageModel: model.shape,
227
+ assignment,
228
+ operationId: "same-operation",
229
+ instructions: "Submit.",
230
+ task: { revision: 1 },
231
+ outputSchema: Answer,
232
+ schemaName: "Answer",
233
+ checkpointStore: store,
234
+ tools: {
235
+ repositoryRoot: repo.root,
236
+ commits: { initial: repo.initialCommit, reference: repo.referenceCommit }
237
+ }
238
+ };
239
+ assert.equal((await Effect.runPromise(groundedStructuredGenerationV1(input))).value.answer, "1");
240
+ assert.equal((await Effect.runPromise(groundedStructuredGenerationV1(input))).value.answer, "1");
241
+ const changedTask = { ...input, task: { revision: 2 } };
242
+ assert.equal((await Effect.runPromise(groundedStructuredGenerationV1(changedTask))).value.answer, "2");
243
+ const changedPolicy = { ...changedTask, instructions: "A revised validation policy." };
244
+ assert.equal((await Effect.runPromise(groundedStructuredGenerationV1(changedPolicy))).value.answer, "3");
245
+ const changedTree = { ...changedPolicy, tools: { ...input.tools, commits: {
246
+ initial: repo.referenceCommit, reference: repo.initialCommit
247
+ } } };
248
+ assert.equal((await Effect.runPromise(groundedStructuredGenerationV1(changedTree))).value.answer, "4");
249
+ const changedSchema = { ...changedTree, outputSchema: Schema.Struct({
250
+ answer: Schema.String, optional: Schema.optionalKey(Schema.String)
251
+ }) };
252
+ assert.equal((await Effect.runPromise(groundedStructuredGenerationV1(changedSchema))).value.answer, "5");
253
+ assert.equal(model.seen.length, 5);
254
+ });
255
+ test("grounded work preserves received fixture actions across real interruption without accepting unexecuted work", async (t) => {
256
+ const repo = await repository(t);
257
+ const store = makeCaseCheckpointStoreV1({ caseDirectory: join(repo.root, "private-work") });
258
+ const model = scriptedModel((_input, turn) => turn === 1
259
+ ? {
260
+ action: "run_fixture", fixtureId: "durable-fixture", testPath: "case.test.mjs",
261
+ content: goodCode, expectationMode: "preserved", kind: "boundary",
262
+ description: "Pinned behavior.", expectedBehavior: "Return one."
263
+ }
264
+ : { action: "submit", result: { answer: "executed" } });
265
+ let stop = true;
266
+ const input = {
267
+ languageModel: model.shape, assignment, operationId: "interrupted-fixture",
268
+ instructions: "Probe before submit.", task: { goal: "execute fixture" },
269
+ outputSchema: Answer, schemaName: "Answer",
270
+ tools: {
271
+ repositoryRoot: repo.root,
272
+ commits: { initial: repo.initialCommit, reference: repo.referenceCommit },
273
+ seed: repo.seed, runFixture: true
274
+ },
275
+ checkpointStore: {
276
+ ...store,
277
+ writeWorkCheckpoint: (name, value) => store.writeWorkCheckpoint(name, value).pipe(Effect.andThen(Effect.suspend(() => {
278
+ if (!stop)
279
+ return Effect.void;
280
+ stop = false;
281
+ return Effect.interrupt;
282
+ })))
283
+ }
284
+ };
285
+ const first = await Effect.runPromise(groundedStructuredGenerationV1(input).pipe(Effect.timeoutOption(2000))).catch(() => undefined);
286
+ assert.ok(first === undefined || Option.isNone(first));
287
+ assert.equal(model.seen.length, 1);
288
+ const result = await Effect.runPromise(groundedStructuredGenerationV1({ ...input, checkpointStore: store }));
289
+ assert.equal(result.turns, 2);
290
+ assert.equal(model.seen.length, 2, "fixture action is restored, not regenerated");
291
+ assert.equal(result.transcript[0].result.outcome, "pass");
292
+ });
293
+ test("the grounded loop searches, reads, continues a truncated file, runs fixtures, and accepts a validated submission", async (t) => {
294
+ const repo = await repository(t);
295
+ const fixtureAction = (fixtureId, content) => ({
296
+ action: "run_fixture",
297
+ fixtureId,
298
+ testPath: "case.test.mjs",
299
+ content,
300
+ expectationMode: "preserved",
301
+ kind: "metamorphic",
302
+ description: "Frozen public behavior.",
303
+ expectedBehavior: "Return one."
304
+ });
305
+ const model = scriptedModel((input, turn) => {
306
+ const previous = lastResult(input);
307
+ switch (turn) {
308
+ case 1:
309
+ return { action: "search", commit: "reference", pattern: "decodeSse", pathPrefix: "lib" };
310
+ case 2:
311
+ return {
312
+ action: "read_files",
313
+ commit: "reference",
314
+ paths: ["lib/sse-decoder.mjs", "big.txt", "lib/missing-decoder.mjs"],
315
+ reason: "the fixture needs the SSE decoder"
316
+ };
317
+ case 3: {
318
+ const files = previous.files;
319
+ const big = files.find((file) => file.path === "big.txt");
320
+ return {
321
+ action: "read_range",
322
+ commit: "reference",
323
+ path: "big.txt",
324
+ offset: big.nextOffset,
325
+ length: 100_000
326
+ };
327
+ }
328
+ case 4:
329
+ return fixtureAction("draft", brokenCode);
330
+ case 5:
331
+ return fixtureAction("draft", goodCode);
332
+ case 6:
333
+ return { action: "submit", result: { answer: "short" } };
334
+ default:
335
+ return { action: "submit", result: { answer: "grounded and complete" } };
336
+ }
337
+ });
338
+ const result = await Effect.runPromise(groundedStructuredGenerationV1({
339
+ languageModel: model.shape,
340
+ assignment,
341
+ operationId: "oracle:author",
342
+ instructions: "Author the hidden oracle.",
343
+ task: { goal: "write a fixture that uses the SSE decoder" },
344
+ outputSchema: Answer,
345
+ schemaName: "Answer",
346
+ tools: {
347
+ repositoryRoot: repo.root,
348
+ commits: { initial: repo.initialCommit, reference: repo.referenceCommit },
349
+ seed: repo.seed,
350
+ runFixture: true
351
+ },
352
+ validateSubmission: (value) => Effect.succeed(value.answer.length < 12
353
+ ? [{ kind: "contract", message: "answer must be complete", path: "answer" }]
354
+ : [])
355
+ }));
356
+ assert.deepEqual(result.value, { answer: "grounded and complete" });
357
+ assert.equal(result.turns, 7);
358
+ assert.equal(result.transcript.length, 7);
359
+ assert.deepEqual(result.transcript.map((entry) => entry.action.action), ["search", "read_files", "read_range", "run_fixture", "run_fixture", "submit", "submit"]);
360
+ assert.deepEqual(model.seen.map((entry) => entry.operationId), Array.from({ length: 7 }, (_, index) => `oracle:author:turn-${String(index + 1)}`));
361
+ assert.deepEqual(model.seen.map((entry) => entry.input.remainingTurns), [24, 23, 22, 21, 20, 19, 18]);
362
+ assert.ok(model.seen.every((entry) => entry.input.remainingCalls === undefined));
363
+ const search = result.transcript[0].result;
364
+ assert.equal(search.total, 1);
365
+ assert.equal(search.matches[0].path, "lib/sse-decoder.mjs");
366
+ assert.equal(search.matches[0].line, 1);
367
+ assert.match(search.matches[0].text, /export function decodeSse/u);
368
+ const read = result.transcript[1].result;
369
+ assert.equal(read.files[0].path, "lib/sse-decoder.mjs");
370
+ assert.equal(read.files[0].content, decoderCode, "pinned content, not the dirty working tree");
371
+ assert.equal(read.files[0].truncated, false);
372
+ const big = read.files[1];
373
+ assert.equal(big.truncated, true);
374
+ assert.equal(big.totalBytes, Buffer.byteLength(bigText));
375
+ assert.ok(big.nextOffset > 0 && big.nextOffset <= GROUNDED_READ_BYTES_PER_TURN);
376
+ assert.ok(!big.content.includes("�"), "truncation respects UTF-8 boundaries");
377
+ assert.equal(Buffer.byteLength(big.content), big.nextOffset);
378
+ assert.ok(read.bytesReturned <= GROUNDED_READ_BYTES_PER_TURN);
379
+ assert.equal(read.files[2].error, "not-found");
380
+ assert.ok(read.files[2].closest.includes("lib/sse-decoder.mjs"));
381
+ const range = result.transcript[2].result;
382
+ assert.equal(range.offset, big.nextOffset);
383
+ assert.equal(range.truncated, true);
384
+ assert.equal(range.nextOffset, range.offset + range.length);
385
+ assert.ok(range.length > GROUNDED_READ_BYTES_PER_TURN - 4 &&
386
+ range.length <= GROUNDED_READ_BYTES_PER_TURN);
387
+ assert.equal(Buffer.from(bigText).subarray(range.offset, range.nextOffset).toString("utf8"), range.content);
388
+ assert.ok(!range.content.includes("�"));
389
+ const broken = result.transcript[3].result;
390
+ assert.equal(broken.outcome, "unknown");
391
+ assert.match(broken.stderrTail, /SyntaxError/u);
392
+ assert.ok(broken.durationMs >= 0);
393
+ assert.equal(broken.stages[0].stage, "candidate-validation");
394
+ const passing = result.transcript[4].result;
395
+ assert.equal(passing.outcome, "pass");
396
+ assert.match(passing.stdoutTail, /# pass 1/u);
397
+ assert.deepEqual(result.transcript[5].result, {
398
+ accepted: false,
399
+ findings: [{ kind: "contract", message: "answer must be complete", path: "answer" }],
400
+ note: "revise and submit again; the transcript keeps your prior submission"
401
+ });
402
+ assert.deepEqual(result.transcript[6].result, { accepted: true });
403
+ const seventh = model.seen[6].input.transcript.at(-1);
404
+ assert.deepEqual(seventh.action, { action: "submit", result: { answer: "short" } });
405
+ assert.deepEqual(seventh.result.findings, [
406
+ { kind: "contract", message: "answer must be complete", path: "answer" }
407
+ ]);
408
+ assert.ok(model.seen[3].schemaName === "Answer");
409
+ });
410
+ test("the grounded loop requires a proposal after bounded tool exploration", async (t) => {
411
+ const repo = await repository(t);
412
+ const model = scriptedModel((_input, turn) => turn <= GROUNDED_MAX_TOOL_TURNS_BEFORE_SUBMIT
413
+ ? { action: "list_files", commit: "initial" }
414
+ : { action: "submit", result: { answer: "bounded proposal" } });
415
+ const result = await Effect.runPromise(groundedStructuredGenerationV1({
416
+ languageModel: model.shape,
417
+ assignment,
418
+ operationId: "bounded:author",
419
+ instructions: "Inspect, then answer.",
420
+ task: { goal: "answer without unbounded browsing" },
421
+ outputSchema: Answer,
422
+ schemaName: "Answer",
423
+ tools: {
424
+ repositoryRoot: repo.root,
425
+ commits: { initial: repo.initialCommit, reference: repo.referenceCommit }
426
+ }
427
+ }));
428
+ assert.equal(result.turns, GROUNDED_MAX_TOOL_TURNS_BEFORE_SUBMIT + 1);
429
+ assert.deepEqual(result.value, { answer: "bounded proposal" });
430
+ assert.match(model.seen[GROUNDED_MAX_TOOL_TURNS_BEFORE_SUBMIT].instructions, /bounded exploration phase is complete/u);
431
+ });
432
+ test("grounded replay retains only adjacent evidence, bounds every request, and keeps unresolved loops recoverable", async (t) => {
433
+ const repo = await repository(t);
434
+ const reads = GROUNDED_FULL_RESULT_WINDOW + 2;
435
+ const model = scriptedModel((_input, turn) => turn <= reads
436
+ ? { action: "read_files", commit: "initial", paths: ["big.txt"], reason: "context" }
437
+ : { action: "submit", result: { answer: "done" } });
438
+ const result = await Effect.runPromise(groundedStructuredGenerationV1({
439
+ languageModel: model.shape,
440
+ assignment,
441
+ operationId: "spec",
442
+ instructions: "Read.",
443
+ task: { goal: "read the big file" },
444
+ outputSchema: Answer,
445
+ schemaName: "Answer",
446
+ maxToolTurnsBeforeSubmit: reads,
447
+ tools: {
448
+ repositoryRoot: repo.root,
449
+ commits: { initial: repo.initialCommit, reference: repo.referenceCommit }
450
+ }
451
+ }));
452
+ assert.equal(result.turns, reads + 1);
453
+ const last = model.seen[reads].input;
454
+ assert.equal(last.transcript.length, reads);
455
+ const full = last.transcript.filter((entry) => "result" in entry);
456
+ const summarized = last.transcript.filter((entry) => "resultBytes" in entry);
457
+ assert.equal(full.length + summarized.length, reads);
458
+ assert.equal(full.length, GROUNDED_FULL_RESULT_WINDOW, "only the adjacent before/after evidence window remains complete");
459
+ assert.ok(summarized.length >= 2);
460
+ assert.deepEqual(summarized[0].action, {
461
+ action: "read_files",
462
+ commit: "initial",
463
+ paths: ["big.txt"]
464
+ });
465
+ assert.equal(typeof summarized[0].resultBytes, "number");
466
+ assert.match(String(summarized[0].note), /re-request/u);
467
+ assert.equal(last.hostNotes.length, 0);
468
+ assert.ok(Buffer.byteLength(JSON.stringify(last)) <= GROUNDED_INPUT_BYTES_LIMIT);
469
+ assert.ok(model.seen.every((entry) => Buffer.byteLength(JSON.stringify(entry.input)) <= GROUNDED_INPUT_BYTES_LIMIT), "repository exploration must not grow the next model request without bound");
470
+ const earlier = model.seen[GROUNDED_FULL_RESULT_WINDOW].input;
471
+ assert.ok(earlier.transcript.every((entry) => "resultBytes" in entry || "result" in entry));
472
+ const unresolved = scriptedModel(() => ({
473
+ action: "list_files",
474
+ commit: "reference",
475
+ glob: "**/*.mjs"
476
+ }));
477
+ const error = await Effect.runPromise(groundedStructuredGenerationV1({
478
+ languageModel: unresolved.shape,
479
+ assignment,
480
+ operationId: "spec",
481
+ instructions: "Read.",
482
+ task: {},
483
+ outputSchema: Answer,
484
+ schemaName: "Answer",
485
+ maxTurns: 2,
486
+ tools: {
487
+ repositoryRoot: repo.root,
488
+ commits: { initial: repo.initialCommit, reference: repo.referenceCommit }
489
+ }
490
+ }).pipe(Effect.flip));
491
+ assert.ok(error instanceof RepositoryFoundryError);
492
+ assert.equal(error.operation, "run-pipeline-stage");
493
+ assert.ok(error.detail.startsWith(GROUNDED_AUTHORING_UNRESOLVED_PREFIX));
494
+ assert.equal(unresolved.seen.length, 2);
495
+ const listing = unresolved.seen[1].input.transcript[0].result;
496
+ assert.deepEqual(listing.paths, ["case.test.mjs", "lib/sse-decoder.mjs", "subject.mjs"]);
497
+ assert.equal(listing.total, 3);
498
+ });
499
+ test("through the budgeted model every turn is counted, invalid output is fed back, and exhaustion is typed", async (t) => {
500
+ const repo = await repository(t);
501
+ const directory = join(await mkdtemp(join(tmpdir(), "grounded-authoring-store-")), "case");
502
+ t.after(() => rm(join(directory, ".."), { recursive: true, force: true }));
503
+ const store = makeCaseCheckpointStoreV1({ caseDirectory: directory });
504
+ const state = await Effect.runPromise(makePipelineStateAccessorV1(initialState()));
505
+ const model = scriptedModel((_input, turn) => {
506
+ if (turn === 1)
507
+ return { action: "fly" };
508
+ if (turn === 2) {
509
+ return { action: "search", commit: "initial", pattern: "value", pathPrefix: "subject.mjs" };
510
+ }
511
+ return { action: "submit", result: { answer: "done" } };
512
+ });
513
+ const layer = BudgetedLanguageModelLive({
514
+ store,
515
+ state,
516
+ budget: { maxModelCalls: 3, maxWallMs: 60 * 60_000 },
517
+ startedAtMs: Date.now(),
518
+ inner: model.shape
519
+ });
520
+ const run = (operationId) => Effect.gen(function* () {
521
+ const languageModel = yield* RepositoryFoundryLanguageModel;
522
+ return yield* groundedStructuredGenerationV1({
523
+ languageModel,
524
+ assignment,
525
+ operationId,
526
+ instructions: "Search.",
527
+ task: { goal: "find value" },
528
+ outputSchema: Answer,
529
+ schemaName: "Answer",
530
+ tools: {
531
+ repositoryRoot: repo.root,
532
+ commits: { initial: repo.initialCommit, reference: repo.referenceCommit }
533
+ }
534
+ });
535
+ });
536
+ const outcome = await Effect.runPromise(Effect.gen(function* () {
537
+ const result = yield* run("controls");
538
+ const snapshot = yield* budgetSnapshotV1;
539
+ return { result, snapshot };
540
+ }).pipe(Effect.provide(layer)));
541
+ assert.equal(outcome.result.turns, 3);
542
+ assert.equal(outcome.snapshot.modelCalls, 3);
543
+ assert.deepEqual(outcome.result.transcript.map((entry) => entry.action.action), ["invalid", "search", "submit"]);
544
+ const invalid = outcome.result.transcript[0].result;
545
+ assert.equal(invalid.error, "invalid-output");
546
+ assert.match(invalid.detail, /violated Answer/u);
547
+ assert.deepEqual(model.seen.map((entry) => entry.input.remainingCalls), [3, 2, 1]);
548
+ const search = outcome.result.transcript[1].result;
549
+ assert.match(search.matches[0].text, /export const value = 0/u);
550
+ const ledger = await Effect.runPromise(store.readLedger);
551
+ assert.deepEqual(ledger.map((entry) => entry.phase), [
552
+ "start",
553
+ "received",
554
+ "failed",
555
+ "start",
556
+ "received",
557
+ "validated",
558
+ "start",
559
+ "received",
560
+ "validated"
561
+ ]);
562
+ const exhausted = await Effect.runPromise(run("controls-2").pipe(Effect.provide(layer), Effect.flip));
563
+ assert.ok(exhausted instanceof PipelineBudgetExhaustedError);
564
+ assert.equal(model.seen.length, 3);
565
+ });
@@ -0,0 +1 @@
1
+ export {};