@prismatic-io/lux 0.0.2-preview.14 → 0.0.2-preview.16

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 (388) hide show
  1. package/lib/answerers/claude-code/index.d.ts +14 -2
  2. package/lib/answerers/claude-code/index.d.ts.map +1 -1
  3. package/lib/answerers/claude-code/index.js +3 -3
  4. package/lib/answerers/claude-code/index.js.map +1 -1
  5. package/lib/answerers/persona/index.d.ts +28 -2
  6. package/lib/answerers/persona/index.d.ts.map +1 -1
  7. package/lib/answerers/persona/index.js +3 -3
  8. package/lib/answerers/persona/index.js.map +1 -1
  9. package/lib/answerers/terminal/index.d.ts +8 -2
  10. package/lib/answerers/terminal/index.d.ts.map +1 -1
  11. package/lib/answerers/terminal/index.js +3 -2
  12. package/lib/answerers/terminal/index.js.map +1 -1
  13. package/lib/assertions/core/resource-checks.d.ts.map +1 -1
  14. package/lib/assertions/core/resource-checks.js +3 -5
  15. package/lib/assertions/core/resource-checks.js.map +1 -1
  16. package/lib/assertions/rubric/index.d.ts.map +1 -1
  17. package/lib/assertions/rubric/index.js +7 -1
  18. package/lib/assertions/rubric/index.js.map +1 -1
  19. package/lib/assertions/rubric/internal.d.ts +16 -5
  20. package/lib/assertions/rubric/internal.d.ts.map +1 -1
  21. package/lib/assertions/rubric/internal.js +10 -6
  22. package/lib/assertions/rubric/internal.js.map +1 -1
  23. package/lib/authoring.d.ts +32 -2
  24. package/lib/authoring.d.ts.map +1 -1
  25. package/lib/authoring.js +33 -1
  26. package/lib/authoring.js.map +1 -1
  27. package/lib/cli/bin.js +2 -13
  28. package/lib/cli/bin.js.map +1 -1
  29. package/lib/cli/command-runtime.d.ts +3 -3
  30. package/lib/cli/command-runtime.d.ts.map +1 -1
  31. package/lib/cli/command-runtime.js +17 -6
  32. package/lib/cli/command-runtime.js.map +1 -1
  33. package/lib/cli/init-templates.d.ts +11 -0
  34. package/lib/cli/init-templates.d.ts.map +1 -0
  35. package/lib/cli/init-templates.js +207 -0
  36. package/lib/cli/init-templates.js.map +1 -0
  37. package/lib/cli/init.d.ts +7 -0
  38. package/lib/cli/init.d.ts.map +1 -1
  39. package/lib/cli/init.js +23 -173
  40. package/lib/cli/init.js.map +1 -1
  41. package/lib/cli/output-schemas.d.ts +1399 -0
  42. package/lib/cli/output-schemas.d.ts.map +1 -0
  43. package/lib/cli/output-schemas.js +91 -0
  44. package/lib/cli/output-schemas.js.map +1 -0
  45. package/lib/cli/program.d.ts +135 -4
  46. package/lib/cli/program.d.ts.map +1 -1
  47. package/lib/cli/program.js +725 -520
  48. package/lib/cli/program.js.map +1 -1
  49. package/lib/cli/render/reporter.d.ts.map +1 -1
  50. package/lib/cli/render/reporter.js +24 -4
  51. package/lib/cli/render/reporter.js.map +1 -1
  52. package/lib/cli/run-options.d.ts +0 -4
  53. package/lib/cli/run-options.d.ts.map +1 -1
  54. package/lib/cli/run-options.js +8 -19
  55. package/lib/cli/run-options.js.map +1 -1
  56. package/lib/cli/view.d.ts +5 -3
  57. package/lib/cli/view.d.ts.map +1 -1
  58. package/lib/cli/view.js +120 -78
  59. package/lib/cli/view.js.map +1 -1
  60. package/lib/core/annotation.d.ts +6 -2
  61. package/lib/core/annotation.d.ts.map +1 -1
  62. package/lib/core/annotation.js +2 -1
  63. package/lib/core/annotation.js.map +1 -1
  64. package/lib/core/answerer.d.ts +12 -0
  65. package/lib/core/answerer.d.ts.map +1 -1
  66. package/lib/core/answerer.js +2 -0
  67. package/lib/core/answerer.js.map +1 -1
  68. package/lib/core/assertion.d.ts +3 -0
  69. package/lib/core/assertion.d.ts.map +1 -1
  70. package/lib/core/assertion.js +3 -0
  71. package/lib/core/assertion.js.map +1 -1
  72. package/lib/core/case.d.ts +24 -2
  73. package/lib/core/case.d.ts.map +1 -1
  74. package/lib/core/case.js +5 -1
  75. package/lib/core/case.js.map +1 -1
  76. package/lib/core/driver.d.ts +40 -0
  77. package/lib/core/driver.d.ts.map +1 -1
  78. package/lib/core/driver.js +12 -0
  79. package/lib/core/driver.js.map +1 -1
  80. package/lib/core/environment.d.ts +18 -0
  81. package/lib/core/environment.d.ts.map +1 -0
  82. package/lib/core/environment.js +21 -0
  83. package/lib/core/environment.js.map +1 -0
  84. package/lib/core/evaluation-clusters.d.ts +17 -0
  85. package/lib/core/evaluation-clusters.d.ts.map +1 -0
  86. package/lib/core/evaluation-clusters.js +23 -0
  87. package/lib/core/evaluation-clusters.js.map +1 -0
  88. package/lib/core/experiment.d.ts +11 -0
  89. package/lib/core/experiment.d.ts.map +1 -1
  90. package/lib/core/experiment.js +31 -17
  91. package/lib/core/experiment.js.map +1 -1
  92. package/lib/core/file-tree.d.ts +7 -0
  93. package/lib/core/file-tree.d.ts.map +1 -0
  94. package/lib/core/file-tree.js +35 -0
  95. package/lib/core/file-tree.js.map +1 -0
  96. package/lib/core/index.d.ts +1 -0
  97. package/lib/core/index.d.ts.map +1 -1
  98. package/lib/core/index.js +1 -0
  99. package/lib/core/index.js.map +1 -1
  100. package/lib/core/lifecycle-fixtures.d.ts.map +1 -1
  101. package/lib/core/lifecycle-fixtures.js +4 -2
  102. package/lib/core/lifecycle-fixtures.js.map +1 -1
  103. package/lib/core/platform-process.d.ts +5 -1
  104. package/lib/core/platform-process.d.ts.map +1 -1
  105. package/lib/core/platform-process.js +48 -10
  106. package/lib/core/platform-process.js.map +1 -1
  107. package/lib/core/run.d.ts +93 -1
  108. package/lib/core/run.d.ts.map +1 -1
  109. package/lib/core/run.js +16 -0
  110. package/lib/core/run.js.map +1 -1
  111. package/lib/core/usage.d.ts +5 -0
  112. package/lib/core/usage.d.ts.map +1 -1
  113. package/lib/core/usage.js +3 -0
  114. package/lib/core/usage.js.map +1 -1
  115. package/lib/drivers/claude-code/index.d.ts +65 -2
  116. package/lib/drivers/claude-code/index.d.ts.map +1 -1
  117. package/lib/drivers/claude-code/index.js +30 -3
  118. package/lib/drivers/claude-code/index.js.map +1 -1
  119. package/lib/drivers/codex/app-events.d.ts.map +1 -1
  120. package/lib/drivers/codex/app-events.js +41 -30
  121. package/lib/drivers/codex/app-events.js.map +1 -1
  122. package/lib/drivers/codex/exec-events.d.ts +4 -0
  123. package/lib/drivers/codex/exec-events.d.ts.map +1 -0
  124. package/lib/drivers/codex/exec-events.js +230 -0
  125. package/lib/drivers/codex/exec-events.js.map +1 -0
  126. package/lib/drivers/codex/index.d.ts +76 -4
  127. package/lib/drivers/codex/index.d.ts.map +1 -1
  128. package/lib/drivers/codex/index.js +35 -232
  129. package/lib/drivers/codex/index.js.map +1 -1
  130. package/lib/drivers/cursor/acp-transport.d.ts +38 -0
  131. package/lib/drivers/cursor/acp-transport.d.ts.map +1 -0
  132. package/lib/drivers/cursor/acp-transport.js +152 -0
  133. package/lib/drivers/cursor/acp-transport.js.map +1 -0
  134. package/lib/drivers/cursor/config.d.ts +22 -0
  135. package/lib/drivers/cursor/config.d.ts.map +1 -0
  136. package/lib/drivers/cursor/config.js +26 -0
  137. package/lib/drivers/cursor/config.js.map +1 -0
  138. package/lib/drivers/cursor/events.d.ts +13 -0
  139. package/lib/drivers/cursor/events.d.ts.map +1 -0
  140. package/lib/drivers/cursor/events.js +73 -0
  141. package/lib/drivers/cursor/events.js.map +1 -0
  142. package/lib/drivers/cursor/index.d.ts +37 -0
  143. package/lib/drivers/cursor/index.d.ts.map +1 -0
  144. package/lib/drivers/cursor/index.js +276 -0
  145. package/lib/drivers/cursor/index.js.map +1 -0
  146. package/lib/drivers/cursor/interaction.d.ts +7 -0
  147. package/lib/drivers/cursor/interaction.d.ts.map +1 -0
  148. package/lib/drivers/cursor/interaction.js +66 -0
  149. package/lib/drivers/cursor/interaction.js.map +1 -0
  150. package/lib/drivers/mcp/index.d.ts +35 -2
  151. package/lib/drivers/mcp/index.d.ts.map +1 -1
  152. package/lib/drivers/mcp/index.js +16 -3
  153. package/lib/drivers/mcp/index.js.map +1 -1
  154. package/lib/drivers/shared/experiment-behavior.d.ts +13 -0
  155. package/lib/drivers/shared/experiment-behavior.d.ts.map +1 -0
  156. package/lib/drivers/shared/experiment-behavior.js +197 -0
  157. package/lib/drivers/shared/experiment-behavior.js.map +1 -0
  158. package/lib/drivers/shared/experiment-policy.d.ts +4 -0
  159. package/lib/drivers/shared/experiment-policy.d.ts.map +1 -0
  160. package/lib/drivers/shared/experiment-policy.js +143 -0
  161. package/lib/drivers/shared/experiment-policy.js.map +1 -0
  162. package/lib/drivers/subprocess/index.d.ts +37 -2
  163. package/lib/drivers/subprocess/index.d.ts.map +1 -1
  164. package/lib/drivers/subprocess/index.js +46 -6
  165. package/lib/drivers/subprocess/index.js.map +1 -1
  166. package/lib/index.d.ts +6 -5
  167. package/lib/index.d.ts.map +1 -1
  168. package/lib/index.js +4 -3
  169. package/lib/index.js.map +1 -1
  170. package/lib/orchestrator/annotation-loader.d.ts +6 -2
  171. package/lib/orchestrator/annotation-loader.d.ts.map +1 -1
  172. package/lib/orchestrator/annotation-loader.js +8 -0
  173. package/lib/orchestrator/annotation-loader.js.map +1 -1
  174. package/lib/orchestrator/annotation-store.d.ts.map +1 -1
  175. package/lib/orchestrator/annotation-store.js +16 -2
  176. package/lib/orchestrator/annotation-store.js.map +1 -1
  177. package/lib/orchestrator/campaign-lifecycle.d.ts +1 -0
  178. package/lib/orchestrator/campaign-lifecycle.d.ts.map +1 -1
  179. package/lib/orchestrator/campaign-lifecycle.js +4 -1
  180. package/lib/orchestrator/campaign-lifecycle.js.map +1 -1
  181. package/lib/orchestrator/compare.d.ts +4 -0
  182. package/lib/orchestrator/compare.d.ts.map +1 -1
  183. package/lib/orchestrator/compare.js +13 -1
  184. package/lib/orchestrator/compare.js.map +1 -1
  185. package/lib/orchestrator/comparison-identity.d.ts.map +1 -1
  186. package/lib/orchestrator/comparison-identity.js +1 -0
  187. package/lib/orchestrator/comparison-identity.js.map +1 -1
  188. package/lib/orchestrator/config.d.ts +42 -0
  189. package/lib/orchestrator/config.d.ts.map +1 -1
  190. package/lib/orchestrator/config.js +6 -2
  191. package/lib/orchestrator/config.js.map +1 -1
  192. package/lib/orchestrator/discover.d.ts +1 -0
  193. package/lib/orchestrator/discover.d.ts.map +1 -1
  194. package/lib/orchestrator/discover.js +7 -1
  195. package/lib/orchestrator/discover.js.map +1 -1
  196. package/lib/orchestrator/doctor.d.ts.map +1 -1
  197. package/lib/orchestrator/doctor.js +34 -26
  198. package/lib/orchestrator/doctor.js.map +1 -1
  199. package/lib/orchestrator/driver-capabilities.d.ts +3 -0
  200. package/lib/orchestrator/driver-capabilities.d.ts.map +1 -0
  201. package/lib/orchestrator/driver-capabilities.js +10 -0
  202. package/lib/orchestrator/driver-capabilities.js.map +1 -0
  203. package/lib/orchestrator/driver-identity.d.ts +5 -0
  204. package/lib/orchestrator/driver-identity.d.ts.map +1 -0
  205. package/lib/orchestrator/driver-identity.js +41 -0
  206. package/lib/orchestrator/driver-identity.js.map +1 -0
  207. package/lib/orchestrator/experiment-context.d.ts +10 -0
  208. package/lib/orchestrator/experiment-context.d.ts.map +1 -1
  209. package/lib/orchestrator/experiment-contracts.d.ts +10 -0
  210. package/lib/orchestrator/experiment-contracts.d.ts.map +1 -1
  211. package/lib/orchestrator/experiment-corpus.d.ts.map +1 -1
  212. package/lib/orchestrator/experiment-corpus.js +17 -19
  213. package/lib/orchestrator/experiment-corpus.js.map +1 -1
  214. package/lib/orchestrator/experiment-effects.d.ts +33 -0
  215. package/lib/orchestrator/experiment-effects.d.ts.map +1 -0
  216. package/lib/orchestrator/experiment-effects.js +44 -0
  217. package/lib/orchestrator/experiment-effects.js.map +1 -0
  218. package/lib/orchestrator/experiment-evaluation.d.ts.map +1 -1
  219. package/lib/orchestrator/experiment-evaluation.js +36 -3
  220. package/lib/orchestrator/experiment-evaluation.js.map +1 -1
  221. package/lib/orchestrator/experiment-identity.d.ts.map +1 -1
  222. package/lib/orchestrator/experiment-identity.js +18 -29
  223. package/lib/orchestrator/experiment-identity.js.map +1 -1
  224. package/lib/orchestrator/experiment-loader.d.ts +7 -2
  225. package/lib/orchestrator/experiment-loader.d.ts.map +1 -1
  226. package/lib/orchestrator/experiment-report.d.ts +70 -0
  227. package/lib/orchestrator/experiment-report.d.ts.map +1 -1
  228. package/lib/orchestrator/experiment-report.js +9 -1
  229. package/lib/orchestrator/experiment-report.js.map +1 -1
  230. package/lib/orchestrator/experiment-runs.d.ts +22 -1
  231. package/lib/orchestrator/experiment-runs.d.ts.map +1 -1
  232. package/lib/orchestrator/experiment-runs.js +13 -5
  233. package/lib/orchestrator/experiment-runs.js.map +1 -1
  234. package/lib/orchestrator/experiment-runtime-identity.d.ts +0 -16
  235. package/lib/orchestrator/experiment-runtime-identity.d.ts.map +1 -1
  236. package/lib/orchestrator/experiment-runtime-identity.js +5 -220
  237. package/lib/orchestrator/experiment-runtime-identity.js.map +1 -1
  238. package/lib/orchestrator/experiment-selection.d.ts.map +1 -1
  239. package/lib/orchestrator/experiment-selection.js +52 -0
  240. package/lib/orchestrator/experiment-selection.js.map +1 -1
  241. package/lib/orchestrator/experiment.d.ts +0 -2
  242. package/lib/orchestrator/experiment.d.ts.map +1 -1
  243. package/lib/orchestrator/experiment.js +23 -15
  244. package/lib/orchestrator/experiment.js.map +1 -1
  245. package/lib/orchestrator/fs-read.d.ts +1 -6
  246. package/lib/orchestrator/fs-read.d.ts.map +1 -1
  247. package/lib/orchestrator/fs-read.js +2 -32
  248. package/lib/orchestrator/fs-read.js.map +1 -1
  249. package/lib/orchestrator/grader-experiment.d.ts +17 -1
  250. package/lib/orchestrator/grader-experiment.d.ts.map +1 -1
  251. package/lib/orchestrator/grader-experiment.js +52 -7
  252. package/lib/orchestrator/grader-experiment.js.map +1 -1
  253. package/lib/orchestrator/grading.d.ts.map +1 -1
  254. package/lib/orchestrator/grading.js +13 -6
  255. package/lib/orchestrator/grading.js.map +1 -1
  256. package/lib/orchestrator/list-runs.d.ts +1 -0
  257. package/lib/orchestrator/list-runs.d.ts.map +1 -1
  258. package/lib/orchestrator/list-runs.js +27 -6
  259. package/lib/orchestrator/list-runs.js.map +1 -1
  260. package/lib/orchestrator/optimization-lifecycle.d.ts.map +1 -1
  261. package/lib/orchestrator/optimization-lifecycle.js +3 -1
  262. package/lib/orchestrator/optimization-lifecycle.js.map +1 -1
  263. package/lib/orchestrator/orchestrator.d.ts +6 -1
  264. package/lib/orchestrator/orchestrator.d.ts.map +1 -1
  265. package/lib/orchestrator/orchestrator.js +17 -143
  266. package/lib/orchestrator/orchestrator.js.map +1 -1
  267. package/lib/orchestrator/paired-effects.d.ts +34 -0
  268. package/lib/orchestrator/paired-effects.d.ts.map +1 -0
  269. package/lib/orchestrator/paired-effects.js +158 -0
  270. package/lib/orchestrator/paired-effects.js.map +1 -0
  271. package/lib/orchestrator/provenance.d.ts +5 -1
  272. package/lib/orchestrator/provenance.d.ts.map +1 -1
  273. package/lib/orchestrator/provenance.js +16 -3
  274. package/lib/orchestrator/provenance.js.map +1 -1
  275. package/lib/orchestrator/regrade.d.ts +1 -0
  276. package/lib/orchestrator/regrade.d.ts.map +1 -1
  277. package/lib/orchestrator/run-execution.d.ts +2 -0
  278. package/lib/orchestrator/run-execution.d.ts.map +1 -1
  279. package/lib/orchestrator/run-execution.js +18 -3
  280. package/lib/orchestrator/run-execution.js.map +1 -1
  281. package/lib/orchestrator/run-lifecycle.d.ts +1 -0
  282. package/lib/orchestrator/run-lifecycle.d.ts.map +1 -1
  283. package/lib/orchestrator/run-lifecycle.js +3 -2
  284. package/lib/orchestrator/run-lifecycle.js.map +1 -1
  285. package/lib/orchestrator/suite-runs.d.ts +3 -1
  286. package/lib/orchestrator/suite-runs.d.ts.map +1 -1
  287. package/lib/orchestrator/suite-runs.js +12 -2
  288. package/lib/orchestrator/suite-runs.js.map +1 -1
  289. package/lib/orchestrator/suite-summary.d.ts.map +1 -1
  290. package/lib/orchestrator/suite-summary.js +2 -1
  291. package/lib/orchestrator/suite-summary.js.map +1 -1
  292. package/lib/previewer/server.d.ts +6 -0
  293. package/lib/previewer/server.d.ts.map +1 -1
  294. package/lib/previewer/server.js +21 -5
  295. package/lib/previewer/server.js.map +1 -1
  296. package/package.json +2 -2
  297. package/skills/lux/references/cli.md +5 -2
  298. package/skills/lux/references/eval-authoring.md +0 -7
  299. package/skills/lux-answerer/SKILL.md +1 -1
  300. package/src/answerers/claude-code/index.ts +3 -3
  301. package/src/answerers/persona/index.ts +3 -3
  302. package/src/answerers/terminal/index.ts +4 -9
  303. package/src/assertions/core/resource-checks.ts +3 -5
  304. package/src/assertions/rubric/index.ts +7 -1
  305. package/src/assertions/rubric/internal.ts +13 -8
  306. package/src/authoring.ts +331 -2
  307. package/src/cli/bin.ts +2 -12
  308. package/src/cli/command-runtime.ts +20 -9
  309. package/src/cli/init-templates.ts +223 -0
  310. package/src/cli/init.ts +38 -184
  311. package/src/cli/output-schemas.ts +106 -0
  312. package/src/cli/program.ts +621 -548
  313. package/src/cli/render/reporter.ts +25 -4
  314. package/src/cli/run-options.ts +8 -25
  315. package/src/cli/view.ts +45 -84
  316. package/src/core/annotation.ts +2 -1
  317. package/src/core/answerer.ts +9 -0
  318. package/src/core/assertion.ts +3 -0
  319. package/src/core/case.ts +5 -1
  320. package/src/core/driver.ts +38 -0
  321. package/src/core/environment.ts +22 -0
  322. package/src/core/evaluation-clusters.ts +35 -0
  323. package/src/core/experiment.ts +60 -23
  324. package/src/core/file-tree.ts +35 -0
  325. package/src/core/index.ts +1 -0
  326. package/src/core/lifecycle-fixtures.ts +4 -2
  327. package/src/core/platform-process.ts +54 -6
  328. package/src/core/run.ts +20 -0
  329. package/src/core/usage.ts +8 -0
  330. package/src/drivers/claude-code/index.ts +34 -3
  331. package/src/drivers/codex/app-events.ts +43 -33
  332. package/src/drivers/codex/exec-events.ts +258 -0
  333. package/src/drivers/codex/index.ts +37 -262
  334. package/src/drivers/cursor/README.md +57 -0
  335. package/src/drivers/cursor/acp-transport.ts +182 -0
  336. package/src/drivers/cursor/config.ts +29 -0
  337. package/src/drivers/cursor/events.ts +83 -0
  338. package/src/drivers/cursor/index.ts +316 -0
  339. package/src/drivers/cursor/interaction.ts +90 -0
  340. package/src/drivers/mcp/index.ts +16 -3
  341. package/src/drivers/shared/experiment-behavior.ts +214 -0
  342. package/src/drivers/shared/experiment-policy.ts +195 -0
  343. package/src/drivers/subprocess/index.ts +45 -6
  344. package/src/index.ts +16 -5
  345. package/src/orchestrator/annotation-loader.ts +10 -0
  346. package/src/orchestrator/annotation-store.ts +24 -3
  347. package/src/orchestrator/campaign-lifecycle.ts +5 -1
  348. package/src/orchestrator/compare.ts +16 -1
  349. package/src/orchestrator/comparison-identity.ts +1 -0
  350. package/src/orchestrator/config.ts +6 -2
  351. package/src/orchestrator/discover.ts +8 -1
  352. package/src/orchestrator/doctor.ts +40 -22
  353. package/src/orchestrator/driver-capabilities.ts +16 -0
  354. package/src/orchestrator/driver-identity.ts +59 -0
  355. package/src/orchestrator/experiment-corpus.ts +23 -28
  356. package/src/orchestrator/experiment-effects.ts +61 -0
  357. package/src/orchestrator/experiment-evaluation.ts +45 -5
  358. package/src/orchestrator/experiment-identity.ts +27 -36
  359. package/src/orchestrator/experiment-report.ts +21 -1
  360. package/src/orchestrator/experiment-runs.ts +11 -4
  361. package/src/orchestrator/experiment-runtime-identity.ts +5 -243
  362. package/src/orchestrator/experiment-selection.ts +77 -0
  363. package/src/orchestrator/experiment.ts +26 -24
  364. package/src/orchestrator/fs-read.ts +2 -32
  365. package/src/orchestrator/grader-experiment.ts +72 -8
  366. package/src/orchestrator/grading.ts +15 -6
  367. package/src/orchestrator/list-runs.ts +29 -6
  368. package/src/orchestrator/optimization-lifecycle.ts +4 -1
  369. package/src/orchestrator/orchestrator.ts +26 -183
  370. package/src/orchestrator/paired-effects.ts +209 -0
  371. package/src/orchestrator/provenance.ts +23 -3
  372. package/src/orchestrator/run-execution.ts +18 -3
  373. package/src/orchestrator/run-lifecycle.ts +4 -2
  374. package/src/orchestrator/suite-runs.ts +10 -1
  375. package/src/orchestrator/suite-summary.ts +2 -1
  376. package/src/previewer/server.ts +27 -5
  377. package/viewer/app.js +27 -6
  378. package/viewer/detail.js +22 -5
  379. package/lib/answerers/scripted/index.d.ts +0 -18
  380. package/lib/answerers/scripted/index.d.ts.map +0 -1
  381. package/lib/answerers/scripted/index.js +0 -63
  382. package/lib/answerers/scripted/index.js.map +0 -1
  383. package/lib/cli/skills.d.ts +0 -38
  384. package/lib/cli/skills.d.ts.map +0 -1
  385. package/lib/cli/skills.js +0 -84
  386. package/lib/cli/skills.js.map +0 -1
  387. package/src/answerers/scripted/index.ts +0 -78
  388. package/src/cli/skills.ts +0 -129
@@ -1,6 +1,7 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { rm } from "node:fs/promises";
3
3
  import type { z } from "zod";
4
+ import { independentClusterCount } from "../core/evaluation-clusters.js";
4
5
  import {
5
6
  bootstrapMeanConfidenceInterval,
6
7
  type Candidate,
@@ -55,14 +56,7 @@ import {
55
56
  openExperimentRun,
56
57
  resumeExperimentRun,
57
58
  } from "./experiment-runs.js";
58
- import {
59
- claudeConfigRoot,
60
- claudeUserBehaviorHash,
61
- cliIdentity,
62
- configuredClaudeSourceHashes,
63
- LUX_VERSION,
64
- runtimeCliIdentityHashForReferences,
65
- } from "./experiment-runtime-identity.js";
59
+ import { LUX_VERSION, runtimeCliIdentityHashForReferences } from "./experiment-runtime-identity.js";
66
60
  import {
67
61
  candidateEvaluations,
68
62
  type ExperimentSelectionDerivationOptionsSchema,
@@ -254,50 +248,57 @@ export const planExperimentCampaign = async (
254
248
  const splitSelector = splitSelectors.find((split) => split.name === constraint.split)?.selector;
255
249
  let examples = splits.find((split) => split.split === constraint.split)?.examples ?? 0;
256
250
  if (corpus.kind === "grader" && splitSelector) {
257
- const selected = selectGraderAnnotations(graderAnnotations, splitSelector);
251
+ let selected = selectGraderAnnotations(graderAnnotations, splitSelector);
258
252
  if (constraint.metric === "grader.macroFalsePositiveRate") {
259
- examples = selected.filter((annotation) =>
253
+ selected = selected.filter((annotation) =>
260
254
  [
261
255
  annotation.expected.casePassed,
262
256
  ...Object.values(annotation.expected.assertions).map((label) => label.passed),
263
257
  ].includes(false),
264
- ).length;
258
+ );
265
259
  } else if (constraint.metric === "grader.macroFalseNegativeRate") {
266
- examples = selected.filter((annotation) =>
260
+ selected = selected.filter((annotation) =>
267
261
  [
268
262
  annotation.expected.casePassed,
269
263
  ...Object.values(annotation.expected.assertions).map((label) => label.passed),
270
264
  ].includes(true),
271
- ).length;
265
+ );
272
266
  } else if (constraint.metric === "grader.scoreMae") {
273
- examples = selected.filter(
267
+ selected = selected.filter(
274
268
  (annotation) =>
275
269
  annotation.expected.caseScore !== undefined ||
276
270
  Object.values(annotation.expected.assertions).some(
277
271
  (label) => label.score !== undefined,
278
272
  ),
279
- ).length;
273
+ );
280
274
  } else if (constraint.metric === "grader.caseAgreement") {
281
- examples = selected.filter(
275
+ selected = selected.filter(
282
276
  (annotation) =>
283
277
  annotation.expected.casePassed !== undefined ||
284
278
  annotation.expected.caseScore !== undefined,
285
- ).length;
279
+ );
286
280
  } else if (constraint.metric === "grader.assertionAgreement") {
287
- examples = selected.filter(
281
+ selected = selected.filter(
288
282
  (annotation) => Object.keys(annotation.expected.assertions).length > 0,
289
- ).length;
283
+ );
290
284
  } else if (
291
285
  constraint.metric === "grader.abstentionRate" ||
286
+ constraint.metric === "grader.insufficientEvidenceRate" ||
287
+ constraint.metric === "grader.operationalErrorRate" ||
292
288
  constraint.metric === "grader.coverage"
293
289
  ) {
294
- examples = selected.filter(
290
+ selected = selected.filter(
295
291
  (annotation) =>
296
292
  annotation.expected.casePassed !== undefined ||
297
293
  Object.keys(annotation.expected.assertions).length > 0,
298
- ).length;
294
+ );
299
295
  }
296
+ examples = independentClusterCount(
297
+ selected.map((annotation) => ({ id: annotation.id, cluster: annotation.meta?.cluster })),
298
+ );
300
299
  }
300
+ if (corpus.kind === "agent" && splitSelector)
301
+ examples = independentClusterCount(selectCases(corpus.cases, splitSelector));
301
302
  if (constraint.metric === "subject.bytes" || constraint.metric === "quality.caseRegressions") {
302
303
  examples = 1;
303
304
  }
@@ -318,6 +319,10 @@ export const planExperimentCampaign = async (
318
319
  Array<number>(examples).fill(0),
319
320
  constraint.confidence,
320
321
  );
322
+ if (constraint.relativeTo) {
323
+ bestForMin.lower = 2 * bestForMin.lower - 1;
324
+ bestForMax.upper = 2 * bestForMax.upper - 1;
325
+ }
321
326
  if (constraint.min !== undefined && bestForMin.lower < constraint.min) {
322
327
  notes.push(
323
328
  `${constraint.split} metric '${constraint.metric}' cannot attain confidence lower bound ${constraint.min} with only ${examples} samples (best ${bestForMin.lower.toFixed(3)})`,
@@ -986,6 +991,3 @@ export const optimizeExperimentCampaign = async (
986
991
  new CampaignExecution(execution, "optimize", runOptimizationCampaignWork),
987
992
  );
988
993
  };
989
-
990
- // Internal exports for identity contract tests.
991
- export { claudeConfigRoot, claudeUserBehaviorHash, cliIdentity, configuredClaudeSourceHashes };
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import type { FileHandle } from "node:fs/promises";
3
3
  import { readdir, readFile } from "node:fs/promises";
4
- import { join, relative, resolve } from "node:path";
4
+ import { join, relative } from "node:path";
5
5
  import type { z } from "zod";
6
6
 
7
7
  const errorMessage = (error: unknown): string =>
@@ -93,34 +93,4 @@ export const walkFiles = async (root: string, maxFiles?: number): Promise<string
93
93
  return out.sort();
94
94
  };
95
95
 
96
- /**
97
- * Walk authored trees without silently following or omitting a symlink that
98
- * can change outside the experiment identity. Exact ignored paths support
99
- * generated state directories whose names are project-configurable.
100
- */
101
- export const walkAuthoredFiles = async (
102
- root: string,
103
- ignoredDirectoryNames: ReadonlySet<string> = new Set(),
104
- ignoredPaths: ReadonlySet<string> = new Set(),
105
- ): Promise<string[]> => {
106
- if (!existsSync(root)) return [];
107
- const out: string[] = [];
108
- const stack = [root];
109
- while (stack.length > 0) {
110
- const dir = stack.pop();
111
- if (!dir) continue;
112
- for (const entry of await readdir(dir, { withFileTypes: true })) {
113
- const full = join(dir, entry.name);
114
- if (ignoredPaths.has(resolve(full))) continue;
115
- if (entry.isDirectory() && ignoredDirectoryNames.has(entry.name)) continue;
116
- if (entry.isSymbolicLink()) {
117
- throw new Error(
118
- `authored evaluation trees cannot contain symlinks: ${relative(root, full)}`,
119
- );
120
- }
121
- if (entry.isDirectory()) stack.push(full);
122
- else if (entry.isFile()) out.push(relative(root, full));
123
- }
124
- }
125
- return out.sort();
126
- };
96
+ export { walkAuthoredFiles } from "../core/file-tree.js";
@@ -28,6 +28,7 @@ import {
28
28
  import type { CampaignExecutionOptions } from "./experiment.js";
29
29
  import type { OpenedExperimentRun } from "./experiment-runs.js";
30
30
  import { gradeRun } from "./grading.js";
31
+ import { clusterCaseSamples, groupedCaseMetricSamples } from "./paired-effects.js";
31
32
  import { loadFrozenRegradableRun, releaseFrozenRegradableRun } from "./regrade.js";
32
33
  import { loadRubricDefinition } from "./rubric-loader.js";
33
34
 
@@ -38,10 +39,12 @@ const GraderJudgmentSchema = z.object({
38
39
  actual: z.union([z.boolean(), z.number()]).nullable(),
39
40
  matched: z.boolean(),
40
41
  absoluteError: z.exactOptional(z.number()),
42
+ unavailableReason: z.exactOptional(z.enum(["insufficient-evidence", "operational-error"])),
41
43
  });
42
44
  export type GraderJudgment = z.infer<typeof GraderJudgmentSchema>;
43
45
 
44
46
  const GraderEvidenceItemSchema = z.object({
47
+ clusterId: z.exactOptional(z.string().min(1)),
45
48
  annotationId: z.string(),
46
49
  repetition: z.number().int().positive(),
47
50
  runDir: z.string(),
@@ -95,6 +98,11 @@ const assertionOperationalError = (
95
98
  return detail.success && detail.data.graderError !== undefined;
96
99
  };
97
100
 
101
+ const assertionUnavailableReason = (
102
+ entry: GradingReport["assertions"][number] | undefined,
103
+ ): GraderJudgment["unavailableReason"] =>
104
+ assertionOperationalError(entry) ? "operational-error" : entry?.abstention;
105
+
98
106
  const assertionModelAccounting = (
99
107
  assertion: GradingReport["assertions"][number],
100
108
  ): { attempts: number; costUsd: number; unpricedModelCalls: number } => {
@@ -115,19 +123,22 @@ export const compareGraderAnnotation = (
115
123
  scoreTolerance: number,
116
124
  ): GraderJudgment[] => {
117
125
  const judgments: GraderJudgment[] = [];
118
- const reportFailed = report.assertions.some(assertionOperationalError);
126
+ const reportUnavailableReason = report.assertions.some(assertionOperationalError)
127
+ ? "operational-error"
128
+ : report.assertions.find((entry) => entry.abstention)?.abstention;
119
129
  if (annotation.expected.casePassed !== undefined) {
120
- const actual = reportFailed ? null : report.casePassed;
130
+ const actual = reportUnavailableReason ? null : report.casePassed;
121
131
  judgments.push({
122
132
  key: "case",
123
133
  kind: "case-pass",
124
134
  expected: annotation.expected.casePassed,
125
135
  actual,
126
136
  matched: actual === annotation.expected.casePassed,
137
+ ...(reportUnavailableReason ? { unavailableReason: reportUnavailableReason } : {}),
127
138
  });
128
139
  }
129
140
  if (annotation.expected.caseScore !== undefined) {
130
- const actual = reportFailed ? null : report.caseScore;
141
+ const actual = reportUnavailableReason ? null : report.caseScore;
131
142
  const absoluteError = actual === null ? 1 : Math.abs(actual - annotation.expected.caseScore);
132
143
  judgments.push({
133
144
  key: "case",
@@ -136,6 +147,7 @@ export const compareGraderAnnotation = (
136
147
  actual,
137
148
  matched: actual !== null && absoluteError <= scoreTolerance,
138
149
  absoluteError,
150
+ ...(reportUnavailableReason ? { unavailableReason: reportUnavailableReason } : {}),
139
151
  });
140
152
  }
141
153
  const entries = new Map(
@@ -143,13 +155,15 @@ export const compareGraderAnnotation = (
143
155
  );
144
156
  for (const [assertionId, expected] of Object.entries(annotation.expected.assertions)) {
145
157
  const entry = entries.get(assertionId);
146
- const actual = assertionOperationalError(entry) ? undefined : entry;
158
+ const unavailableReason = assertionUnavailableReason(entry);
159
+ const actual = unavailableReason ? undefined : entry;
147
160
  judgments.push({
148
161
  key: assertionId,
149
162
  kind: "assertion-pass",
150
163
  expected: expected.passed,
151
164
  actual: actual?.passed ?? null,
152
165
  matched: actual?.passed === expected.passed,
166
+ ...(unavailableReason ? { unavailableReason } : {}),
153
167
  });
154
168
  if (expected.score !== undefined) {
155
169
  const absoluteError = actual ? Math.abs(actual.score - expected.score) : 1;
@@ -160,6 +174,7 @@ export const compareGraderAnnotation = (
160
174
  actual: actual?.score ?? null,
161
175
  matched: actual !== undefined && absoluteError <= scoreTolerance,
162
176
  absoluteError,
177
+ ...(unavailableReason ? { unavailableReason } : {}),
163
178
  });
164
179
  }
165
180
  }
@@ -233,7 +248,7 @@ const collectGraderEvidence = (
233
248
 
234
249
  export const summarizeGraderEvidence = (
235
250
  items: readonly z.infer<typeof GraderEvidenceItemSchema>[],
236
- candidate: Candidate,
251
+ candidate: Pick<Candidate, "sourceBytes">,
237
252
  ): { metrics: Record<string, number>; samples: Record<string, number[]> } => {
238
253
  const samples: Record<string, number[]> = {};
239
254
  const { byAnnotation, itemsByAnnotation, counts } = collectGraderEvidence(items);
@@ -323,6 +338,18 @@ export const summarizeGraderEvidence = (
323
338
  "grader.abstentionRate",
324
339
  passes.filter((judgment) => judgment.actual === null).length / passes.length,
325
340
  );
341
+ addSample(
342
+ samples,
343
+ "grader.insufficientEvidenceRate",
344
+ passes.filter((judgment) => judgment.unavailableReason === "insufficient-evidence").length /
345
+ passes.length,
346
+ );
347
+ addSample(
348
+ samples,
349
+ "grader.operationalErrorRate",
350
+ passes.filter((judgment) => judgment.unavailableReason === "operational-error").length /
351
+ passes.length,
352
+ );
326
353
  }
327
354
  }
328
355
  const precision = ratio(
@@ -440,7 +467,42 @@ const evaluationFromEvidence = (
440
467
  evidencePath: string,
441
468
  evidence: GraderEvaluationEvidence,
442
469
  ): CandidateEvaluation & { evidencePath: string } => {
470
+ const caseSamples = clusterCaseSamples(
471
+ evidence.items.map((item) => {
472
+ const summary = summarizeGraderEvidence([item], {
473
+ sourceBytes: evidence.metrics["subject.bytes"] ?? 0,
474
+ });
475
+ return {
476
+ [item.annotationId]: {
477
+ ...(item.clusterId ? { clusterId: item.clusterId } : {}),
478
+ identityHash: experiment.manifest.evaluationHash
479
+ ? valueHash({
480
+ evaluationHash: experiment.manifest.evaluationHash,
481
+ annotationId: item.annotationId,
482
+ profileId: evidence.profileId,
483
+ split: evidence.split,
484
+ })
485
+ : null,
486
+ metrics: Object.fromEntries(
487
+ Object.entries(summary.samples).flatMap(([metric, values]) =>
488
+ values.length === 1 ? [[metric, { mean: values[0] ?? 0, n: 1 }]] : [],
489
+ ),
490
+ ),
491
+ },
492
+ };
493
+ }),
494
+ );
443
495
  const byAnnotation = new Map<string, number[]>();
496
+ const grouped = groupedCaseMetricSamples(caseSamples, evidence.repetitions);
497
+ const metrics = grouped
498
+ ? Object.fromEntries(
499
+ Object.entries(evidence.metrics).flatMap(([name, value]) => {
500
+ if (!Object.hasOwn(evidence.samples, name)) return [[name, value]];
501
+ const values = grouped[name];
502
+ return values ? [[name, mean(values)]] : [];
503
+ }),
504
+ )
505
+ : evidence.metrics;
444
506
  for (const item of evidence.items) {
445
507
  const values = byAnnotation.get(item.annotationId) ?? [];
446
508
  values.push(...item.judgments.map((judgment) => (judgment.matched ? 1 : 0)));
@@ -471,10 +533,11 @@ const evaluationFromEvidence = (
471
533
  profileId: evidence.profileId,
472
534
  split: evidence.split,
473
535
  evidencePath: relative(experiment.path, evidencePath),
474
- passRate: evidence.metrics["quality.passRate"] ?? 0,
536
+ passRate: metrics["quality.passRate"] ?? 0,
475
537
  casePassRates: Object.fromEntries([...byAnnotation].map(([id, values]) => [id, mean(values)])),
476
- metrics: evidence.metrics,
477
- samples: evidence.samples,
538
+ metrics,
539
+ samples: grouped ?? evidence.samples,
540
+ ...(caseSamples ? { caseSamples } : {}),
478
541
  metricCalls: evidence.items.length,
479
542
  judgeCalls: evidence.items.reduce(
480
543
  (total, item) =>
@@ -779,6 +842,7 @@ export const evaluateGraderCandidate = async (options: {
779
842
  );
780
843
  const item: GraderEvidenceItem = {
781
844
  annotationId: annotation.id,
845
+ ...(annotation.meta?.cluster ? { clusterId: annotation.meta.cluster } : {}),
782
846
  repetition,
783
847
  runDir: annotation.runDir,
784
848
  rubricPath: annotation.rubricPath,
@@ -3,6 +3,7 @@ import {
3
3
  type Assertion,
4
4
  type AssertionImpl,
5
5
  type AssertionProgress,
6
+ type AssertionResult,
6
7
  AssertionResultSchema,
7
8
  type GradingAssertionEntry,
8
9
  type GradingReport,
@@ -124,6 +125,12 @@ const describeAssertion = (a: Assertion): string => {
124
125
  return fields ? `${a.type} ${fields}` : a.type;
125
126
  };
126
127
 
128
+ const assertionPassed = (result: AssertionResult, threshold: number): boolean =>
129
+ result.errorMessage === undefined &&
130
+ result.abstention === undefined &&
131
+ result.passed &&
132
+ result.score >= threshold;
133
+
127
134
  export const gradeRun = async (
128
135
  run: Run,
129
136
  registry: Registry,
@@ -154,6 +161,7 @@ export const gradeRun = async (
154
161
  let weightSum = 0;
155
162
  let allPassed = true;
156
163
  let gradingIncomplete = false;
164
+ let gradingAbstained = false;
157
165
 
158
166
  for (const [index, a] of assertions.entries()) {
159
167
  if (skipJudge && a.type === "rubric") {
@@ -219,8 +227,7 @@ export const gradeRun = async (
219
227
  : {}),
220
228
  }),
221
229
  );
222
- const passed =
223
- result.errorMessage === undefined && result.passed && result.score >= threshold;
230
+ const passed = assertionPassed(result, threshold);
224
231
  entry = {
225
232
  id,
226
233
  type: a.type,
@@ -232,11 +239,14 @@ export const gradeRun = async (
232
239
  durationMs: Date.now() - startedAt,
233
240
  ...(result.comment !== undefined ? { comment: result.comment } : {}),
234
241
  detail: result.detail,
242
+ ...(result.abstention !== undefined ? { abstention: result.abstention } : {}),
235
243
  ...(result.errorMessage !== undefined ? { errorMessage: result.errorMessage } : {}),
236
244
  ...(result.usage ? { usage: result.usage } : {}),
237
245
  };
238
246
  if (result.errorMessage !== undefined) {
239
247
  gradingIncomplete = true;
248
+ } else if (result.abstention !== undefined) {
249
+ gradingAbstained = true;
240
250
  } else {
241
251
  if (!passed) allPassed = false;
242
252
  weightedScoreSum += weight * result.score;
@@ -264,12 +274,11 @@ export const gradeRun = async (
264
274
  await modelAttempts?.complete(assertionAttemptIds);
265
275
  }
266
276
 
267
- let caseScore: number | null = null;
268
- if (!gradingIncomplete && weightSum > 0) caseScore = weightedScoreSum / weightSum;
277
+ const hasVerdict = !gradingIncomplete && !gradingAbstained && weightSum > 0;
269
278
  return {
270
279
  schemaVersion: 1,
271
- casePassed: gradingIncomplete || weightSum === 0 ? null : allPassed,
272
- caseScore,
280
+ casePassed: hasVerdict ? allPassed : null,
281
+ caseScore: hasVerdict ? weightedScoreSum / weightSum : null,
273
282
  assertions: entries,
274
283
  ...(skippedAssertions.length > 0 ? { skippedAssertions } : {}),
275
284
  ...(gradingIncomplete
@@ -20,6 +20,7 @@ import {
20
20
  ToolResultPayloadSchema,
21
21
  totalTokens,
22
22
  } from "../core/index.js";
23
+ import { hasAgentUsage } from "../core/usage.js";
23
24
  import { readBoundedHandle, safeReadJson, walkFiles } from "./fs-read.js";
24
25
  import { MAX_RUN_TRACE_BYTES, MAX_RUN_TRACE_EVENTS } from "./trace-limits.js";
25
26
 
@@ -45,6 +46,7 @@ export type ListedRun = {
45
46
  caseScore: number | null;
46
47
  assertionPassed: number;
47
48
  assertionTotal: number;
49
+ readErrors?: string[];
48
50
  };
49
51
 
50
52
  const summarizeRun = async (
@@ -53,10 +55,19 @@ const summarizeRun = async (
53
55
  ts: string,
54
56
  runDir: string,
55
57
  ): Promise<ListedRun> => {
56
- const [meta, grading] = await Promise.all([
58
+ const [metadataResult, gradingResult] = await Promise.allSettled([
57
59
  safeReadJson(join(runDir, "run.json"), RunMetadataSchema),
58
60
  safeReadJson(join(runDir, "grading.json"), GradingReportSchema),
59
61
  ]);
62
+ const readErrors = [metadataResult, gradingResult].flatMap((result) =>
63
+ result.status === "rejected"
64
+ ? [result.reason instanceof Error ? result.reason.message : String(result.reason)]
65
+ : [],
66
+ );
67
+ const meta = metadataResult.status === "fulfilled" ? metadataResult.value : null;
68
+ // A valid grading file cannot establish a result when its run metadata is damaged.
69
+ const grading =
70
+ readErrors.length === 0 && gradingResult.status === "fulfilled" ? gradingResult.value : null;
60
71
  const startedAt = meta?.startedAt ?? null;
61
72
  const endedAt = meta?.endedAt ?? null;
62
73
  const started = Date.parse(startedAt ?? "");
@@ -83,6 +94,7 @@ const summarizeRun = async (
83
94
  caseScore: grading?.caseScore ?? null,
84
95
  assertionPassed: passing,
85
96
  assertionTotal: grading?.assertions.length ?? 0,
97
+ ...(readErrors.length > 0 ? { readErrors } : {}),
86
98
  };
87
99
  };
88
100
 
@@ -146,7 +158,8 @@ export const formatRunsTable = (runs: ListedRun[]): string => {
146
158
  ["status", "case", "driver", "agents", "ts", "exit", "score", "duration"],
147
159
  ...runs.map((r) => {
148
160
  let status = "ungraded";
149
- if (r.casePassed === true) status = "PASS";
161
+ if (r.readErrors?.length) status = "DAMAGED";
162
+ else if (r.casePassed === true) status = "PASS";
150
163
  else if (r.casePassed === false) status = "FAIL";
151
164
  const score =
152
165
  r.caseScore !== null
@@ -159,9 +172,11 @@ export const formatRunsTable = (runs: ListedRun[]): string => {
159
172
  ];
160
173
  const header = rows[0] ?? [];
161
174
  const widths = header.map((_, col) => Math.max(...rows.map((r) => r[col]?.length ?? 0)));
162
- return rows
175
+ const table = rows
163
176
  .map((row) => row.map((cell, col) => cell.padEnd(widths[col] ?? 0)).join(" "))
164
177
  .join("\n");
178
+ const diagnostics = runs.flatMap((run) => run.readErrors ?? []);
179
+ return diagnostics.length > 0 ? `${table}\n\n${diagnostics.join("\n")}` : table;
165
180
  };
166
181
 
167
182
  export type RunDetail = {
@@ -289,6 +304,12 @@ const appendMetadataDetail = (lines: string[], detail: RunDetail): void => {
289
304
  }`,
290
305
  );
291
306
  }
307
+ const environment = provenance?.environment;
308
+ if (environment) {
309
+ lines.push(`concurrency: ${environment.concurrency}`);
310
+ if (environment.declared)
311
+ lines.push(`declared environment: ${JSON.stringify(environment.declared)}`);
312
+ }
292
313
  const c = detail.metadata.interruptCounts;
293
314
  lines.push(`interrupts: ask=${c.ask} approve=${c.approve} custom=${c.custom}`);
294
315
  const tools = detail.metadata.toolOutcomes;
@@ -301,7 +322,7 @@ const appendMetadataDetail = (lines: string[], detail: RunDetail): void => {
301
322
  }
302
323
  const usage = detail.metadata.usage;
303
324
  lines.push(
304
- `tokens: agent=${totalTokens(usage.agent)} harness=${totalTokens(harnessUsage(usage))}` +
325
+ `tokens: agent=${hasAgentUsage(detail.metadata) ? totalTokens(usage.agent) : "unavailable"} harness=${totalTokens(harnessUsage(usage))}` +
305
326
  ` (answerer=${totalTokens(usage.answerer)} judge=${totalTokens(usage.grading)})`,
306
327
  );
307
328
  const phases = detail.metadata.phaseDurationMs;
@@ -347,9 +368,11 @@ const appendGradingDetail = (lines: string[], detail: RunDetail): void => {
347
368
  `grading: ${status} (${score}, ${detail.grading.assertions.filter((a) => a.passed).length}/${detail.grading.assertions.length})`,
348
369
  );
349
370
  for (const a of detail.grading.assertions) {
350
- const mark = a.passed ? "✓" : "✗";
371
+ let mark = a.passed ? "✓" : "✗";
372
+ if (a.abstention) mark = "?";
351
373
  const took = ` (${(a.durationMs / 1000).toFixed(1)}s)`;
352
- lines.push(` ${mark} ${a.name}${took}${a.comment ? ` — ${a.comment}` : ""}`);
374
+ const abstention = a.abstention ? " — insufficient evidence" : "";
375
+ lines.push(` ${mark} ${a.name}${took}${abstention}${a.comment ? ` — ${a.comment}` : ""}`);
353
376
  }
354
377
  }
355
378
  };
@@ -26,6 +26,7 @@ export const executeOptimizationLifecycle = async <Search, Deployment, Result>(
26
26
  deployment: Deployment | undefined;
27
27
  result: Result | undefined;
28
28
  error: unknown;
29
+ failed: boolean;
29
30
  };
30
31
 
31
32
  const machine = setup({
@@ -59,6 +60,7 @@ export const executeOptimizationLifecycle = async <Search, Deployment, Result>(
59
60
  result: ({ event }) => ("output" in event ? event.output : undefined),
60
61
  }),
61
62
  captureError: assign({
63
+ failed: true,
62
64
  error: ({ event }) =>
63
65
  "error" in event ? event.error : new Error("optimization lifecycle failed"),
64
66
  }),
@@ -70,6 +72,7 @@ export const executeOptimizationLifecycle = async <Search, Deployment, Result>(
70
72
  deployment: undefined,
71
73
  result: undefined,
72
74
  error: undefined,
75
+ failed: false,
73
76
  },
74
77
  initial: "evaluatingSearchSeeds",
75
78
  states: {
@@ -112,7 +115,7 @@ export const executeOptimizationLifecycle = async <Search, Deployment, Result>(
112
115
  failed: { type: "final" },
113
116
  },
114
117
  output: ({ context }) =>
115
- context.error === undefined
118
+ !context.failed
116
119
  ? { status: "succeeded", result: context.result }
117
120
  : { status: "failed", error: context.error },
118
121
  });