@prismatic-io/lux 0.0.2-preview.4 → 0.0.2-preview.40

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 (753) hide show
  1. package/lib/answerers/claude-code/index.d.ts +15 -3
  2. package/lib/answerers/claude-code/index.d.ts.map +1 -1
  3. package/lib/answerers/claude-code/index.js +6 -5
  4. package/lib/answerers/claude-code/index.js.map +1 -1
  5. package/lib/answerers/persona/index.d.ts +44 -5
  6. package/lib/answerers/persona/index.d.ts.map +1 -1
  7. package/lib/answerers/persona/index.js +60 -34
  8. package/lib/answerers/persona/index.js.map +1 -1
  9. package/lib/answerers/terminal/index.d.ts +9 -3
  10. package/lib/answerers/terminal/index.d.ts.map +1 -1
  11. package/lib/answerers/terminal/index.js +6 -4
  12. package/lib/answerers/terminal/index.js.map +1 -1
  13. package/lib/assertions/authoring.d.ts +2 -2
  14. package/lib/assertions/authoring.d.ts.map +1 -1
  15. package/lib/assertions/authoring.js.map +1 -1
  16. package/lib/assertions/core/command-exits-zero.d.ts +5 -2
  17. package/lib/assertions/core/command-exits-zero.d.ts.map +1 -1
  18. package/lib/assertions/core/command-exits-zero.js +59 -14
  19. package/lib/assertions/core/command-exits-zero.js.map +1 -1
  20. package/lib/assertions/core/event-checks.d.ts +3 -0
  21. package/lib/assertions/core/event-checks.d.ts.map +1 -1
  22. package/lib/assertions/core/event-checks.js +49 -3
  23. package/lib/assertions/core/event-checks.js.map +1 -1
  24. package/lib/assertions/core/file-checks.d.ts +6 -0
  25. package/lib/assertions/core/file-checks.d.ts.map +1 -1
  26. package/lib/assertions/core/index.d.ts.map +1 -1
  27. package/lib/assertions/core/index.js +2 -1
  28. package/lib/assertions/core/index.js.map +1 -1
  29. package/lib/assertions/core/json-pointer-equals.d.ts +1 -0
  30. package/lib/assertions/core/json-pointer-equals.d.ts.map +1 -1
  31. package/lib/assertions/core/output-checks.d.ts +3 -0
  32. package/lib/assertions/core/output-checks.d.ts.map +1 -1
  33. package/lib/assertions/core/predicate.d.ts +1 -0
  34. package/lib/assertions/core/predicate.d.ts.map +1 -1
  35. package/lib/assertions/core/resource-checks.d.ts +25 -0
  36. package/lib/assertions/core/resource-checks.d.ts.map +1 -1
  37. package/lib/assertions/core/resource-checks.js +35 -5
  38. package/lib/assertions/core/resource-checks.js.map +1 -1
  39. package/lib/assertions/core/safe-regex.d.ts.map +1 -1
  40. package/lib/assertions/core/safe-regex.js +7 -1
  41. package/lib/assertions/core/safe-regex.js.map +1 -1
  42. package/lib/assertions/rubric/evidence.d.ts +88 -0
  43. package/lib/assertions/rubric/evidence.d.ts.map +1 -0
  44. package/lib/assertions/rubric/evidence.js +75 -0
  45. package/lib/assertions/rubric/evidence.js.map +1 -0
  46. package/lib/assertions/rubric/index.d.ts +88 -34
  47. package/lib/assertions/rubric/index.d.ts.map +1 -1
  48. package/lib/assertions/rubric/index.js +59 -43
  49. package/lib/assertions/rubric/index.js.map +1 -1
  50. package/lib/assertions/rubric/internal.d.ts +30 -5
  51. package/lib/assertions/rubric/internal.d.ts.map +1 -1
  52. package/lib/assertions/rubric/internal.js +203 -41
  53. package/lib/assertions/rubric/internal.js.map +1 -1
  54. package/lib/authoring.d.ts +37 -2
  55. package/lib/authoring.d.ts.map +1 -1
  56. package/lib/authoring.js +36 -1
  57. package/lib/authoring.js.map +1 -1
  58. package/lib/cli/bin.js +2 -13
  59. package/lib/cli/bin.js.map +1 -1
  60. package/lib/cli/command-runtime.d.ts +3 -3
  61. package/lib/cli/command-runtime.d.ts.map +1 -1
  62. package/lib/cli/command-runtime.js +17 -6
  63. package/lib/cli/command-runtime.js.map +1 -1
  64. package/lib/cli/doctor.d.ts +55 -0
  65. package/lib/cli/doctor.d.ts.map +1 -0
  66. package/lib/cli/doctor.js +14 -0
  67. package/lib/cli/doctor.js.map +1 -0
  68. package/lib/cli/harness-plan.d.ts +27 -0
  69. package/lib/cli/harness-plan.d.ts.map +1 -0
  70. package/lib/cli/harness-plan.js +75 -0
  71. package/lib/cli/harness-plan.js.map +1 -0
  72. package/lib/cli/init-templates.d.ts +11 -0
  73. package/lib/cli/init-templates.d.ts.map +1 -0
  74. package/lib/cli/init-templates.js +215 -0
  75. package/lib/cli/init-templates.js.map +1 -0
  76. package/lib/cli/init.d.ts +10 -0
  77. package/lib/cli/init.d.ts.map +1 -1
  78. package/lib/cli/init.js +34 -173
  79. package/lib/cli/init.js.map +1 -1
  80. package/lib/cli/output-schemas.d.ts +1412 -0
  81. package/lib/cli/output-schemas.d.ts.map +1 -0
  82. package/lib/cli/output-schemas.js +94 -0
  83. package/lib/cli/output-schemas.js.map +1 -0
  84. package/lib/cli/program.d.ts +140 -12
  85. package/lib/cli/program.d.ts.map +1 -1
  86. package/lib/cli/program.js +783 -650
  87. package/lib/cli/program.js.map +1 -1
  88. package/lib/cli/render/format.d.ts.map +1 -1
  89. package/lib/cli/render/format.js +1 -1
  90. package/lib/cli/render/format.js.map +1 -1
  91. package/lib/cli/render/reporter.d.ts.map +1 -1
  92. package/lib/cli/render/reporter.js +35 -8
  93. package/lib/cli/render/reporter.js.map +1 -1
  94. package/lib/cli/run-options.d.ts +19 -4
  95. package/lib/cli/run-options.d.ts.map +1 -1
  96. package/lib/cli/run-options.js +100 -19
  97. package/lib/cli/run-options.js.map +1 -1
  98. package/lib/cli/view.d.ts +15 -0
  99. package/lib/cli/view.d.ts.map +1 -0
  100. package/lib/cli/view.js +168 -0
  101. package/lib/cli/view.js.map +1 -0
  102. package/lib/container/driver.d.ts +27 -0
  103. package/lib/container/driver.d.ts.map +1 -0
  104. package/lib/container/driver.js +199 -0
  105. package/lib/container/driver.js.map +1 -0
  106. package/lib/container/paths.d.ts +3 -0
  107. package/lib/container/paths.d.ts.map +1 -0
  108. package/lib/container/paths.js +27 -0
  109. package/lib/container/paths.js.map +1 -0
  110. package/lib/container/protocol.d.ts +12 -0
  111. package/lib/container/protocol.d.ts.map +1 -0
  112. package/lib/container/protocol.js +38 -0
  113. package/lib/container/protocol.js.map +1 -0
  114. package/lib/container/resources.d.ts +14 -0
  115. package/lib/container/resources.d.ts.map +1 -0
  116. package/lib/container/resources.js +141 -0
  117. package/lib/container/resources.js.map +1 -0
  118. package/lib/container/worker.d.ts +2 -0
  119. package/lib/container/worker.d.ts.map +1 -0
  120. package/lib/container/worker.js +85 -0
  121. package/lib/container/worker.js.map +1 -0
  122. package/lib/core/action-events.d.ts +29 -0
  123. package/lib/core/action-events.d.ts.map +1 -0
  124. package/lib/core/action-events.js +51 -0
  125. package/lib/core/action-events.js.map +1 -0
  126. package/lib/core/agent-activity.d.ts +49 -0
  127. package/lib/core/agent-activity.d.ts.map +1 -0
  128. package/lib/core/agent-activity.js +206 -0
  129. package/lib/core/agent-activity.js.map +1 -0
  130. package/lib/core/agent-environment.d.ts +5 -0
  131. package/lib/core/agent-environment.d.ts.map +1 -0
  132. package/lib/core/agent-environment.js +47 -0
  133. package/lib/core/agent-environment.js.map +1 -0
  134. package/lib/core/agent-events.d.ts +26 -0
  135. package/lib/core/agent-events.d.ts.map +1 -0
  136. package/lib/core/agent-events.js +13 -0
  137. package/lib/core/agent-events.js.map +1 -0
  138. package/lib/core/annotation.d.ts +6 -2
  139. package/lib/core/annotation.d.ts.map +1 -1
  140. package/lib/core/annotation.js +2 -1
  141. package/lib/core/annotation.js.map +1 -1
  142. package/lib/core/answerer.d.ts +12 -0
  143. package/lib/core/answerer.d.ts.map +1 -1
  144. package/lib/core/answerer.js +2 -0
  145. package/lib/core/answerer.js.map +1 -1
  146. package/lib/core/artifact-evidence.d.ts +6 -1
  147. package/lib/core/artifact-evidence.d.ts.map +1 -1
  148. package/lib/core/artifact-evidence.js +27 -6
  149. package/lib/core/artifact-evidence.js.map +1 -1
  150. package/lib/core/assertion.d.ts +10 -4
  151. package/lib/core/assertion.d.ts.map +1 -1
  152. package/lib/core/assertion.js +8 -2
  153. package/lib/core/assertion.js.map +1 -1
  154. package/lib/core/case-defaults.d.ts +16 -0
  155. package/lib/core/case-defaults.d.ts.map +1 -0
  156. package/lib/core/case-defaults.js +42 -0
  157. package/lib/core/case-defaults.js.map +1 -0
  158. package/lib/core/case.d.ts +120 -6
  159. package/lib/core/case.d.ts.map +1 -1
  160. package/lib/core/case.js +51 -5
  161. package/lib/core/case.js.map +1 -1
  162. package/lib/core/command-verification.d.ts +10 -0
  163. package/lib/core/command-verification.d.ts.map +1 -0
  164. package/lib/core/command-verification.js +66 -0
  165. package/lib/core/command-verification.js.map +1 -0
  166. package/lib/core/driver-execution.d.ts +83 -0
  167. package/lib/core/driver-execution.d.ts.map +1 -0
  168. package/lib/core/driver-execution.js +72 -0
  169. package/lib/core/driver-execution.js.map +1 -0
  170. package/lib/core/driver-metrics.d.ts +98 -0
  171. package/lib/core/driver-metrics.d.ts.map +1 -0
  172. package/lib/core/driver-metrics.js +36 -0
  173. package/lib/core/driver-metrics.js.map +1 -0
  174. package/lib/core/driver.d.ts +64 -0
  175. package/lib/core/driver.d.ts.map +1 -1
  176. package/lib/core/driver.js +28 -0
  177. package/lib/core/driver.js.map +1 -1
  178. package/lib/core/duration.d.ts +5 -0
  179. package/lib/core/duration.d.ts.map +1 -0
  180. package/lib/core/duration.js +49 -0
  181. package/lib/core/duration.js.map +1 -0
  182. package/lib/core/environment.d.ts +18 -0
  183. package/lib/core/environment.d.ts.map +1 -0
  184. package/lib/core/environment.js +21 -0
  185. package/lib/core/environment.js.map +1 -0
  186. package/lib/core/evaluation-clusters.d.ts +17 -0
  187. package/lib/core/evaluation-clusters.d.ts.map +1 -0
  188. package/lib/core/evaluation-clusters.js +23 -0
  189. package/lib/core/evaluation-clusters.js.map +1 -0
  190. package/lib/core/events.d.ts +34 -0
  191. package/lib/core/events.d.ts.map +1 -1
  192. package/lib/core/events.js +11 -2
  193. package/lib/core/events.js.map +1 -1
  194. package/lib/core/experiment.d.ts +33 -2
  195. package/lib/core/experiment.d.ts.map +1 -1
  196. package/lib/core/experiment.js +40 -19
  197. package/lib/core/experiment.js.map +1 -1
  198. package/lib/core/file-tree.d.ts +7 -0
  199. package/lib/core/file-tree.d.ts.map +1 -0
  200. package/lib/core/file-tree.js +35 -0
  201. package/lib/core/file-tree.js.map +1 -0
  202. package/lib/core/global-id.d.ts +6 -0
  203. package/lib/core/global-id.d.ts.map +1 -0
  204. package/lib/core/global-id.js +17 -0
  205. package/lib/core/global-id.js.map +1 -0
  206. package/lib/core/harness-catalog.d.ts +35 -0
  207. package/lib/core/harness-catalog.d.ts.map +1 -0
  208. package/lib/core/harness-catalog.js +45 -0
  209. package/lib/core/harness-catalog.js.map +1 -0
  210. package/lib/core/harness-catalogs/antigravity.d.ts +11 -0
  211. package/lib/core/harness-catalogs/antigravity.d.ts.map +1 -0
  212. package/lib/core/harness-catalogs/antigravity.js +23 -0
  213. package/lib/core/harness-catalogs/antigravity.js.map +1 -0
  214. package/lib/core/harness-catalogs/claude-code.d.ts +12 -0
  215. package/lib/core/harness-catalogs/claude-code.d.ts.map +1 -0
  216. package/lib/core/harness-catalogs/claude-code.js +24 -0
  217. package/lib/core/harness-catalogs/claude-code.js.map +1 -0
  218. package/lib/core/harness-catalogs/codex.d.ts +11 -0
  219. package/lib/core/harness-catalogs/codex.d.ts.map +1 -0
  220. package/lib/core/harness-catalogs/codex.js +26 -0
  221. package/lib/core/harness-catalogs/codex.js.map +1 -0
  222. package/lib/core/harness-catalogs/copilot.d.ts +29 -0
  223. package/lib/core/harness-catalogs/copilot.d.ts.map +1 -0
  224. package/lib/core/harness-catalogs/copilot.js +45 -0
  225. package/lib/core/harness-catalogs/copilot.js.map +1 -0
  226. package/lib/core/harness-catalogs/cursor.d.ts +2 -0
  227. package/lib/core/harness-catalogs/cursor.d.ts.map +1 -0
  228. package/lib/core/harness-catalogs/cursor.js +13 -0
  229. package/lib/core/harness-catalogs/cursor.js.map +1 -0
  230. package/lib/core/harness-catalogs/grok-build.d.ts +7 -0
  231. package/lib/core/harness-catalogs/grok-build.d.ts.map +1 -0
  232. package/lib/core/harness-catalogs/grok-build.js +18 -0
  233. package/lib/core/harness-catalogs/grok-build.js.map +1 -0
  234. package/lib/core/harness-catalogs/index.d.ts +73 -0
  235. package/lib/core/harness-catalogs/index.d.ts.map +1 -0
  236. package/lib/core/harness-catalogs/index.js +17 -0
  237. package/lib/core/harness-catalogs/index.js.map +1 -0
  238. package/lib/core/harness-matrix.d.ts +154 -0
  239. package/lib/core/harness-matrix.d.ts.map +1 -0
  240. package/lib/core/harness-matrix.js +204 -0
  241. package/lib/core/harness-matrix.js.map +1 -0
  242. package/lib/core/index.d.ts +12 -0
  243. package/lib/core/index.d.ts.map +1 -1
  244. package/lib/core/index.js +12 -0
  245. package/lib/core/index.js.map +1 -1
  246. package/lib/core/lifecycle-fixtures.d.ts.map +1 -1
  247. package/lib/core/lifecycle-fixtures.js +4 -2
  248. package/lib/core/lifecycle-fixtures.js.map +1 -1
  249. package/lib/core/model-cli.d.ts +9 -11
  250. package/lib/core/model-cli.d.ts.map +1 -1
  251. package/lib/core/model-cli.js +39 -22
  252. package/lib/core/model-cli.js.map +1 -1
  253. package/lib/core/platform-process.d.ts +7 -2
  254. package/lib/core/platform-process.d.ts.map +1 -1
  255. package/lib/core/platform-process.js +54 -16
  256. package/lib/core/platform-process.js.map +1 -1
  257. package/lib/core/reference-defaults.d.ts +5 -0
  258. package/lib/core/reference-defaults.d.ts.map +1 -0
  259. package/lib/core/reference-defaults.js +42 -0
  260. package/lib/core/reference-defaults.js.map +1 -0
  261. package/lib/core/rubric.d.ts +1 -0
  262. package/lib/core/rubric.d.ts.map +1 -1
  263. package/lib/core/run.d.ts +292 -1
  264. package/lib/core/run.d.ts.map +1 -1
  265. package/lib/core/run.js +27 -0
  266. package/lib/core/run.js.map +1 -1
  267. package/lib/core/secure-copy.d.ts.map +1 -0
  268. package/lib/core/secure-copy.js.map +1 -0
  269. package/lib/core/usage.d.ts +5 -0
  270. package/lib/core/usage.d.ts.map +1 -1
  271. package/lib/core/usage.js +3 -0
  272. package/lib/core/usage.js.map +1 -1
  273. package/lib/core/wire.d.ts +11 -0
  274. package/lib/core/wire.d.ts.map +1 -1
  275. package/lib/drivers/antigravity/artifacts.d.ts +2 -0
  276. package/lib/drivers/antigravity/artifacts.d.ts.map +1 -0
  277. package/lib/drivers/antigravity/artifacts.js +33 -0
  278. package/lib/drivers/antigravity/artifacts.js.map +1 -0
  279. package/lib/drivers/antigravity/config.d.ts +88 -0
  280. package/lib/drivers/antigravity/config.d.ts.map +1 -0
  281. package/lib/drivers/antigravity/config.js +87 -0
  282. package/lib/drivers/antigravity/config.js.map +1 -0
  283. package/lib/drivers/antigravity/events.d.ts +4 -0
  284. package/lib/drivers/antigravity/events.d.ts.map +1 -0
  285. package/lib/drivers/antigravity/events.js +241 -0
  286. package/lib/drivers/antigravity/events.js.map +1 -0
  287. package/lib/drivers/antigravity/index.d.ts +114 -0
  288. package/lib/drivers/antigravity/index.d.ts.map +1 -0
  289. package/lib/drivers/antigravity/index.js +113 -0
  290. package/lib/drivers/antigravity/index.js.map +1 -0
  291. package/lib/drivers/antigravity/runtime.d.ts +7 -0
  292. package/lib/drivers/antigravity/runtime.d.ts.map +1 -0
  293. package/lib/drivers/antigravity/runtime.js +83 -0
  294. package/lib/drivers/antigravity/runtime.js.map +1 -0
  295. package/lib/drivers/claude-code/deferred-process.d.ts +17 -0
  296. package/lib/drivers/claude-code/deferred-process.d.ts.map +1 -0
  297. package/lib/drivers/claude-code/deferred-process.js +108 -0
  298. package/lib/drivers/claude-code/deferred-process.js.map +1 -0
  299. package/lib/drivers/claude-code/index.d.ts +187 -10
  300. package/lib/drivers/claude-code/index.d.ts.map +1 -1
  301. package/lib/drivers/claude-code/index.js +197 -252
  302. package/lib/drivers/claude-code/index.js.map +1 -1
  303. package/lib/drivers/claude-code/isolation.d.ts +8 -0
  304. package/lib/drivers/claude-code/isolation.d.ts.map +1 -0
  305. package/lib/drivers/claude-code/isolation.js +199 -0
  306. package/lib/drivers/claude-code/isolation.js.map +1 -0
  307. package/lib/drivers/claude-code/parse-events.d.ts.map +1 -1
  308. package/lib/drivers/claude-code/parse-events.js +73 -8
  309. package/lib/drivers/claude-code/parse-events.js.map +1 -1
  310. package/lib/drivers/codex/app-events.d.ts +9 -2
  311. package/lib/drivers/codex/app-events.d.ts.map +1 -1
  312. package/lib/drivers/codex/app-events.js +104 -12
  313. package/lib/drivers/codex/app-events.js.map +1 -1
  314. package/lib/drivers/codex/config.d.ts +69 -5
  315. package/lib/drivers/codex/config.d.ts.map +1 -1
  316. package/lib/drivers/codex/config.js +48 -8
  317. package/lib/drivers/codex/config.js.map +1 -1
  318. package/lib/drivers/codex/exec-events.d.ts +4 -0
  319. package/lib/drivers/codex/exec-events.d.ts.map +1 -0
  320. package/lib/drivers/codex/exec-events.js +230 -0
  321. package/lib/drivers/codex/exec-events.js.map +1 -0
  322. package/lib/drivers/codex/index.d.ts +142 -4
  323. package/lib/drivers/codex/index.d.ts.map +1 -1
  324. package/lib/drivers/codex/index.js +114 -276
  325. package/lib/drivers/codex/index.js.map +1 -1
  326. package/lib/drivers/copilot/config.d.ts +84 -0
  327. package/lib/drivers/copilot/config.d.ts.map +1 -0
  328. package/lib/drivers/copilot/config.js +57 -0
  329. package/lib/drivers/copilot/config.js.map +1 -0
  330. package/lib/drivers/copilot/index.d.ts +107 -0
  331. package/lib/drivers/copilot/index.d.ts.map +1 -0
  332. package/lib/drivers/copilot/index.js +268 -0
  333. package/lib/drivers/copilot/index.js.map +1 -0
  334. package/lib/drivers/cursor/config.d.ts +28 -0
  335. package/lib/drivers/cursor/config.d.ts.map +1 -0
  336. package/lib/drivers/cursor/config.js +28 -0
  337. package/lib/drivers/cursor/config.js.map +1 -0
  338. package/lib/drivers/cursor/index.d.ts +44 -0
  339. package/lib/drivers/cursor/index.d.ts.map +1 -0
  340. package/lib/drivers/cursor/index.js +286 -0
  341. package/lib/drivers/cursor/index.js.map +1 -0
  342. package/lib/drivers/cursor/interaction.d.ts +6 -0
  343. package/lib/drivers/cursor/interaction.d.ts.map +1 -0
  344. package/lib/drivers/cursor/interaction.js +55 -0
  345. package/lib/drivers/cursor/interaction.js.map +1 -0
  346. package/lib/drivers/grok-build/config.d.ts +68 -0
  347. package/lib/drivers/grok-build/config.d.ts.map +1 -0
  348. package/lib/drivers/grok-build/config.js +40 -0
  349. package/lib/drivers/grok-build/config.js.map +1 -0
  350. package/lib/drivers/grok-build/index.d.ts +87 -0
  351. package/lib/drivers/grok-build/index.d.ts.map +1 -0
  352. package/lib/drivers/grok-build/index.js +293 -0
  353. package/lib/drivers/grok-build/index.js.map +1 -0
  354. package/lib/drivers/mcp/index.d.ts +37 -4
  355. package/lib/drivers/mcp/index.d.ts.map +1 -1
  356. package/lib/drivers/mcp/index.js +25 -11
  357. package/lib/drivers/mcp/index.js.map +1 -1
  358. package/lib/drivers/shared/acp-events.d.ts +15 -0
  359. package/lib/drivers/shared/acp-events.d.ts.map +1 -0
  360. package/lib/drivers/shared/acp-events.js +83 -0
  361. package/lib/drivers/shared/acp-events.js.map +1 -0
  362. package/lib/drivers/shared/acp-interaction.d.ts +7 -0
  363. package/lib/drivers/shared/acp-interaction.d.ts.map +1 -0
  364. package/lib/drivers/shared/acp-interaction.js +20 -0
  365. package/lib/drivers/shared/acp-interaction.js.map +1 -0
  366. package/lib/drivers/shared/acp-session.d.ts +4 -0
  367. package/lib/drivers/shared/acp-session.d.ts.map +1 -0
  368. package/lib/drivers/shared/acp-session.js +23 -0
  369. package/lib/drivers/shared/acp-session.js.map +1 -0
  370. package/lib/drivers/shared/acp-transport.d.ts +40 -0
  371. package/lib/drivers/shared/acp-transport.d.ts.map +1 -0
  372. package/lib/drivers/shared/acp-transport.js +152 -0
  373. package/lib/drivers/shared/acp-transport.js.map +1 -0
  374. package/lib/drivers/shared/artifacts.d.ts.map +1 -1
  375. package/lib/drivers/shared/artifacts.js +3 -2
  376. package/lib/drivers/shared/artifacts.js.map +1 -1
  377. package/lib/drivers/shared/experiment-behavior.d.ts +13 -0
  378. package/lib/drivers/shared/experiment-behavior.d.ts.map +1 -0
  379. package/lib/drivers/shared/experiment-behavior.js +200 -0
  380. package/lib/drivers/shared/experiment-behavior.js.map +1 -0
  381. package/lib/drivers/shared/experiment-policy.d.ts +4 -0
  382. package/lib/drivers/shared/experiment-policy.d.ts.map +1 -0
  383. package/lib/drivers/shared/experiment-policy.js +144 -0
  384. package/lib/drivers/shared/experiment-policy.js.map +1 -0
  385. package/lib/drivers/shared/skills.d.ts +3 -0
  386. package/lib/drivers/shared/skills.d.ts.map +1 -0
  387. package/lib/drivers/shared/skills.js +73 -0
  388. package/lib/drivers/shared/skills.js.map +1 -0
  389. package/lib/drivers/subprocess/index.d.ts +39 -4
  390. package/lib/drivers/subprocess/index.d.ts.map +1 -1
  391. package/lib/drivers/subprocess/index.js +56 -12
  392. package/lib/drivers/subprocess/index.js.map +1 -1
  393. package/lib/index.d.ts +24 -8
  394. package/lib/index.d.ts.map +1 -1
  395. package/lib/index.js +20 -5
  396. package/lib/index.js.map +1 -1
  397. package/lib/optimization/reflective.d.ts +3 -1
  398. package/lib/optimization/reflective.d.ts.map +1 -1
  399. package/lib/optimization/reflective.js +3 -2
  400. package/lib/optimization/reflective.js.map +1 -1
  401. package/lib/orchestrator/annotation-loader.d.ts +6 -2
  402. package/lib/orchestrator/annotation-loader.d.ts.map +1 -1
  403. package/lib/orchestrator/annotation-loader.js +8 -0
  404. package/lib/orchestrator/annotation-loader.js.map +1 -1
  405. package/lib/orchestrator/annotation-store.d.ts.map +1 -1
  406. package/lib/orchestrator/annotation-store.js +16 -2
  407. package/lib/orchestrator/annotation-store.js.map +1 -1
  408. package/lib/orchestrator/artifact-origin.d.ts +3 -0
  409. package/lib/orchestrator/artifact-origin.d.ts.map +1 -0
  410. package/lib/orchestrator/artifact-origin.js +40 -0
  411. package/lib/orchestrator/artifact-origin.js.map +1 -0
  412. package/lib/orchestrator/campaign-lifecycle.d.ts +1 -0
  413. package/lib/orchestrator/campaign-lifecycle.d.ts.map +1 -1
  414. package/lib/orchestrator/campaign-lifecycle.js +4 -1
  415. package/lib/orchestrator/campaign-lifecycle.js.map +1 -1
  416. package/lib/orchestrator/candidates.d.ts.map +1 -1
  417. package/lib/orchestrator/candidates.js +3 -2
  418. package/lib/orchestrator/candidates.js.map +1 -1
  419. package/lib/orchestrator/compare.d.ts +23 -6
  420. package/lib/orchestrator/compare.d.ts.map +1 -1
  421. package/lib/orchestrator/compare.js +45 -12
  422. package/lib/orchestrator/compare.js.map +1 -1
  423. package/lib/orchestrator/comparison-identity.d.ts.map +1 -1
  424. package/lib/orchestrator/comparison-identity.js +2 -0
  425. package/lib/orchestrator/comparison-identity.js.map +1 -1
  426. package/lib/orchestrator/config.d.ts +180 -1
  427. package/lib/orchestrator/config.d.ts.map +1 -1
  428. package/lib/orchestrator/config.js +21 -2
  429. package/lib/orchestrator/config.js.map +1 -1
  430. package/lib/orchestrator/discover.d.ts +1 -0
  431. package/lib/orchestrator/discover.d.ts.map +1 -1
  432. package/lib/orchestrator/discover.js +7 -1
  433. package/lib/orchestrator/discover.js.map +1 -1
  434. package/lib/orchestrator/doctor.d.ts +1 -0
  435. package/lib/orchestrator/doctor.d.ts.map +1 -1
  436. package/lib/orchestrator/doctor.js +134 -69
  437. package/lib/orchestrator/doctor.js.map +1 -1
  438. package/lib/orchestrator/driver-capabilities.d.ts +4 -0
  439. package/lib/orchestrator/driver-capabilities.d.ts.map +1 -0
  440. package/lib/orchestrator/driver-capabilities.js +13 -0
  441. package/lib/orchestrator/driver-capabilities.js.map +1 -0
  442. package/lib/orchestrator/driver-identity.d.ts +5 -0
  443. package/lib/orchestrator/driver-identity.d.ts.map +1 -0
  444. package/lib/orchestrator/driver-identity.js +51 -0
  445. package/lib/orchestrator/driver-identity.js.map +1 -0
  446. package/lib/orchestrator/experiment-context.d.ts +51 -3
  447. package/lib/orchestrator/experiment-context.d.ts.map +1 -1
  448. package/lib/orchestrator/experiment-context.js +2 -1
  449. package/lib/orchestrator/experiment-context.js.map +1 -1
  450. package/lib/orchestrator/experiment-contracts.d.ts +31 -1
  451. package/lib/orchestrator/experiment-contracts.d.ts.map +1 -1
  452. package/lib/orchestrator/experiment-corpus.d.ts +2 -1
  453. package/lib/orchestrator/experiment-corpus.d.ts.map +1 -1
  454. package/lib/orchestrator/experiment-corpus.js +28 -22
  455. package/lib/orchestrator/experiment-corpus.js.map +1 -1
  456. package/lib/orchestrator/experiment-effects.d.ts +33 -0
  457. package/lib/orchestrator/experiment-effects.d.ts.map +1 -0
  458. package/lib/orchestrator/experiment-effects.js +46 -0
  459. package/lib/orchestrator/experiment-effects.js.map +1 -0
  460. package/lib/orchestrator/experiment-evaluation.d.ts.map +1 -1
  461. package/lib/orchestrator/experiment-evaluation.js +70 -5
  462. package/lib/orchestrator/experiment-evaluation.js.map +1 -1
  463. package/lib/orchestrator/experiment-identity.d.ts +3 -0
  464. package/lib/orchestrator/experiment-identity.d.ts.map +1 -1
  465. package/lib/orchestrator/experiment-identity.js +22 -33
  466. package/lib/orchestrator/experiment-identity.js.map +1 -1
  467. package/lib/orchestrator/experiment-loader.d.ts +8 -3
  468. package/lib/orchestrator/experiment-loader.d.ts.map +1 -1
  469. package/lib/orchestrator/experiment-preflight.d.ts +3 -0
  470. package/lib/orchestrator/experiment-preflight.d.ts.map +1 -0
  471. package/lib/orchestrator/experiment-preflight.js +21 -0
  472. package/lib/orchestrator/experiment-preflight.js.map +1 -0
  473. package/lib/orchestrator/experiment-report.d.ts +91 -1
  474. package/lib/orchestrator/experiment-report.d.ts.map +1 -1
  475. package/lib/orchestrator/experiment-report.js +9 -1
  476. package/lib/orchestrator/experiment-report.js.map +1 -1
  477. package/lib/orchestrator/experiment-runs.d.ts +63 -2
  478. package/lib/orchestrator/experiment-runs.d.ts.map +1 -1
  479. package/lib/orchestrator/experiment-runs.js +13 -5
  480. package/lib/orchestrator/experiment-runs.js.map +1 -1
  481. package/lib/orchestrator/experiment-runtime-identity.d.ts +0 -16
  482. package/lib/orchestrator/experiment-runtime-identity.d.ts.map +1 -1
  483. package/lib/orchestrator/experiment-runtime-identity.js +5 -220
  484. package/lib/orchestrator/experiment-runtime-identity.js.map +1 -1
  485. package/lib/orchestrator/experiment-selection.d.ts.map +1 -1
  486. package/lib/orchestrator/experiment-selection.js +151 -43
  487. package/lib/orchestrator/experiment-selection.js.map +1 -1
  488. package/lib/orchestrator/experiment.d.ts +3 -3
  489. package/lib/orchestrator/experiment.d.ts.map +1 -1
  490. package/lib/orchestrator/experiment.js +26 -21
  491. package/lib/orchestrator/experiment.js.map +1 -1
  492. package/lib/orchestrator/fixture-identity.d.ts +1 -0
  493. package/lib/orchestrator/fixture-identity.d.ts.map +1 -1
  494. package/lib/orchestrator/fixture-identity.js +6 -1
  495. package/lib/orchestrator/fixture-identity.js.map +1 -1
  496. package/lib/orchestrator/fs-read.d.ts +1 -6
  497. package/lib/orchestrator/fs-read.d.ts.map +1 -1
  498. package/lib/orchestrator/fs-read.js +2 -32
  499. package/lib/orchestrator/fs-read.js.map +1 -1
  500. package/lib/orchestrator/grader-experiment.d.ts +23 -5
  501. package/lib/orchestrator/grader-experiment.d.ts.map +1 -1
  502. package/lib/orchestrator/grader-experiment.js +54 -9
  503. package/lib/orchestrator/grader-experiment.js.map +1 -1
  504. package/lib/orchestrator/grading.d.ts +1 -0
  505. package/lib/orchestrator/grading.d.ts.map +1 -1
  506. package/lib/orchestrator/grading.js +41 -33
  507. package/lib/orchestrator/grading.js.map +1 -1
  508. package/lib/orchestrator/harness-catalog-drift.d.ts +22 -0
  509. package/lib/orchestrator/harness-catalog-drift.d.ts.map +1 -0
  510. package/lib/orchestrator/harness-catalog-drift.js +90 -0
  511. package/lib/orchestrator/harness-catalog-drift.js.map +1 -0
  512. package/lib/orchestrator/harness-registry.d.ts +4 -0
  513. package/lib/orchestrator/harness-registry.d.ts.map +1 -0
  514. package/lib/orchestrator/harness-registry.js +5 -0
  515. package/lib/orchestrator/harness-registry.js.map +1 -0
  516. package/lib/orchestrator/index.d.ts +1 -1
  517. package/lib/orchestrator/index.d.ts.map +1 -1
  518. package/lib/orchestrator/index.js +1 -1
  519. package/lib/orchestrator/index.js.map +1 -1
  520. package/lib/orchestrator/list-runs.d.ts +8 -1
  521. package/lib/orchestrator/list-runs.d.ts.map +1 -1
  522. package/lib/orchestrator/list-runs.js +83 -18
  523. package/lib/orchestrator/list-runs.js.map +1 -1
  524. package/lib/orchestrator/optimization-lifecycle.d.ts.map +1 -1
  525. package/lib/orchestrator/optimization-lifecycle.js +3 -1
  526. package/lib/orchestrator/optimization-lifecycle.js.map +1 -1
  527. package/lib/orchestrator/orchestrator.d.ts +17 -2
  528. package/lib/orchestrator/orchestrator.d.ts.map +1 -1
  529. package/lib/orchestrator/orchestrator.js +55 -177
  530. package/lib/orchestrator/orchestrator.js.map +1 -1
  531. package/lib/orchestrator/paired-effects.d.ts +34 -0
  532. package/lib/orchestrator/paired-effects.d.ts.map +1 -0
  533. package/lib/orchestrator/paired-effects.js +164 -0
  534. package/lib/orchestrator/paired-effects.js.map +1 -0
  535. package/lib/orchestrator/profile.d.ts +4 -0
  536. package/lib/orchestrator/profile.d.ts.map +1 -0
  537. package/lib/orchestrator/profile.js +10 -0
  538. package/lib/orchestrator/profile.js.map +1 -0
  539. package/lib/orchestrator/provenance.d.ts +5 -1
  540. package/lib/orchestrator/provenance.d.ts.map +1 -1
  541. package/lib/orchestrator/provenance.js +16 -3
  542. package/lib/orchestrator/provenance.js.map +1 -1
  543. package/lib/orchestrator/regrade.d.ts +4 -2
  544. package/lib/orchestrator/regrade.d.ts.map +1 -1
  545. package/lib/orchestrator/rubric-loader.js +1 -1
  546. package/lib/orchestrator/rubric-loader.js.map +1 -1
  547. package/lib/orchestrator/run-dir.d.ts +2 -0
  548. package/lib/orchestrator/run-dir.d.ts.map +1 -1
  549. package/lib/orchestrator/run-dir.js +1 -1
  550. package/lib/orchestrator/run-dir.js.map +1 -1
  551. package/lib/orchestrator/run-execution.d.ts +3 -0
  552. package/lib/orchestrator/run-execution.d.ts.map +1 -1
  553. package/lib/orchestrator/run-execution.js +64 -10
  554. package/lib/orchestrator/run-execution.js.map +1 -1
  555. package/lib/orchestrator/run-lifecycle.d.ts +1 -0
  556. package/lib/orchestrator/run-lifecycle.d.ts.map +1 -1
  557. package/lib/orchestrator/run-lifecycle.js +3 -2
  558. package/lib/orchestrator/run-lifecycle.js.map +1 -1
  559. package/lib/orchestrator/run-workspace.d.ts +10 -0
  560. package/lib/orchestrator/run-workspace.d.ts.map +1 -0
  561. package/lib/orchestrator/run-workspace.js +58 -0
  562. package/lib/orchestrator/run-workspace.js.map +1 -0
  563. package/lib/orchestrator/suite-compare.d.ts +37 -0
  564. package/lib/orchestrator/suite-compare.d.ts.map +1 -1
  565. package/lib/orchestrator/suite-compare.js +44 -22
  566. package/lib/orchestrator/suite-compare.js.map +1 -1
  567. package/lib/orchestrator/suite-runs.d.ts +6 -1
  568. package/lib/orchestrator/suite-runs.d.ts.map +1 -1
  569. package/lib/orchestrator/suite-runs.js +14 -2
  570. package/lib/orchestrator/suite-runs.js.map +1 -1
  571. package/lib/orchestrator/suite-summary.d.ts +79 -0
  572. package/lib/orchestrator/suite-summary.d.ts.map +1 -1
  573. package/lib/orchestrator/suite-summary.js +67 -14
  574. package/lib/orchestrator/suite-summary.js.map +1 -1
  575. package/lib/previewer/artifacts.d.ts +25 -0
  576. package/lib/previewer/artifacts.d.ts.map +1 -0
  577. package/lib/previewer/artifacts.js +180 -0
  578. package/lib/previewer/artifacts.js.map +1 -0
  579. package/lib/previewer/server.d.ts +111 -0
  580. package/lib/previewer/server.d.ts.map +1 -0
  581. package/lib/previewer/server.js +559 -0
  582. package/lib/previewer/server.js.map +1 -0
  583. package/package.json +4 -2
  584. package/skills/lux-answerer/SKILL.md +2 -2
  585. package/src/answerers/claude-code/index.ts +6 -5
  586. package/src/answerers/persona/index.ts +75 -34
  587. package/src/answerers/terminal/index.ts +7 -11
  588. package/src/assertions/authoring.ts +2 -0
  589. package/src/assertions/core/command-exits-zero.ts +82 -17
  590. package/src/assertions/core/event-checks.ts +64 -3
  591. package/src/assertions/core/index.ts +2 -0
  592. package/src/assertions/core/resource-checks.ts +38 -5
  593. package/src/assertions/core/safe-regex.ts +16 -6
  594. package/src/assertions/rubric/evidence.ts +85 -0
  595. package/src/assertions/rubric/index.ts +63 -46
  596. package/src/assertions/rubric/internal.ts +256 -41
  597. package/src/authoring.ts +346 -2
  598. package/src/cli/bin.ts +2 -12
  599. package/src/cli/command-runtime.ts +20 -9
  600. package/src/cli/doctor.ts +17 -0
  601. package/src/cli/harness-plan.ts +123 -0
  602. package/src/cli/init-templates.ts +238 -0
  603. package/src/cli/init.ts +53 -184
  604. package/src/cli/output-schemas.ts +109 -0
  605. package/src/cli/program.ts +697 -730
  606. package/src/cli/render/format.ts +1 -1
  607. package/src/cli/render/reporter.ts +36 -8
  608. package/src/cli/run-options.ts +131 -25
  609. package/src/cli/view.ts +129 -0
  610. package/src/container/driver.ts +213 -0
  611. package/src/container/paths.ts +29 -0
  612. package/src/container/protocol.ts +48 -0
  613. package/src/container/resources.ts +165 -0
  614. package/src/container/worker.ts +107 -0
  615. package/src/core/action-events.ts +59 -0
  616. package/src/core/agent-activity.ts +236 -0
  617. package/src/core/agent-environment.ts +64 -0
  618. package/src/core/agent-events.ts +17 -0
  619. package/src/core/annotation.ts +2 -1
  620. package/src/core/answerer.ts +9 -0
  621. package/src/core/artifact-evidence.ts +40 -5
  622. package/src/core/assertion.ts +8 -2
  623. package/src/core/case-defaults.ts +65 -0
  624. package/src/core/case.ts +79 -8
  625. package/src/core/command-verification.ts +74 -0
  626. package/src/core/driver-execution.ts +84 -0
  627. package/src/core/driver-metrics.ts +51 -0
  628. package/src/core/driver.ts +76 -0
  629. package/src/core/duration.ts +52 -0
  630. package/src/core/environment.ts +22 -0
  631. package/src/core/evaluation-clusters.ts +35 -0
  632. package/src/core/events.ts +13 -2
  633. package/src/core/experiment.ts +71 -25
  634. package/src/core/file-tree.ts +35 -0
  635. package/src/core/global-id.ts +26 -0
  636. package/src/core/harness-catalog.ts +100 -0
  637. package/src/core/harness-catalogs/antigravity.ts +24 -0
  638. package/src/core/harness-catalogs/claude-code.ts +25 -0
  639. package/src/core/harness-catalogs/codex.ts +27 -0
  640. package/src/core/harness-catalogs/copilot.ts +46 -0
  641. package/src/core/harness-catalogs/cursor.ts +13 -0
  642. package/src/core/harness-catalogs/grok-build.ts +19 -0
  643. package/src/core/harness-catalogs/index.ts +31 -0
  644. package/src/core/harness-matrix.ts +316 -0
  645. package/src/core/index.ts +12 -0
  646. package/src/core/lifecycle-fixtures.ts +4 -2
  647. package/src/core/model-cli.ts +60 -26
  648. package/src/core/platform-process.ts +65 -16
  649. package/src/core/reference-defaults.ts +47 -0
  650. package/src/core/run.ts +31 -0
  651. package/src/core/usage.ts +8 -0
  652. package/src/drivers/antigravity/README.md +171 -0
  653. package/src/drivers/antigravity/artifacts.ts +37 -0
  654. package/src/drivers/antigravity/config.ts +92 -0
  655. package/src/drivers/antigravity/events.ts +290 -0
  656. package/src/drivers/antigravity/index.ts +132 -0
  657. package/src/drivers/antigravity/runtime.ts +94 -0
  658. package/src/drivers/claude-code/deferred-process.ts +118 -0
  659. package/src/drivers/claude-code/index.ts +227 -281
  660. package/src/drivers/claude-code/isolation.ts +228 -0
  661. package/src/drivers/claude-code/parse-events.ts +98 -12
  662. package/src/drivers/codex/app-events.ts +126 -16
  663. package/src/drivers/codex/config.ts +59 -8
  664. package/src/drivers/codex/exec-events.ts +258 -0
  665. package/src/drivers/codex/index.ts +146 -312
  666. package/src/drivers/copilot/README.md +60 -0
  667. package/src/drivers/copilot/config.ts +61 -0
  668. package/src/drivers/copilot/index.ts +310 -0
  669. package/src/drivers/cursor/README.md +66 -0
  670. package/src/drivers/cursor/config.ts +31 -0
  671. package/src/drivers/cursor/index.ts +326 -0
  672. package/src/drivers/cursor/interaction.ts +74 -0
  673. package/src/drivers/grok-build/README.md +112 -0
  674. package/src/drivers/grok-build/config.ts +43 -0
  675. package/src/drivers/grok-build/index.ts +331 -0
  676. package/src/drivers/mcp/index.ts +25 -11
  677. package/src/drivers/shared/acp-events.ts +94 -0
  678. package/src/drivers/shared/acp-interaction.ts +27 -0
  679. package/src/drivers/shared/acp-session.ts +40 -0
  680. package/src/drivers/shared/acp-transport.ts +187 -0
  681. package/src/drivers/shared/artifacts.ts +6 -2
  682. package/src/drivers/shared/experiment-behavior.ts +217 -0
  683. package/src/drivers/shared/experiment-policy.ts +196 -0
  684. package/src/drivers/shared/skills.ts +74 -0
  685. package/src/drivers/subprocess/index.ts +55 -12
  686. package/src/index.ts +117 -6
  687. package/src/optimization/reflective.ts +3 -2
  688. package/src/orchestrator/annotation-loader.ts +10 -0
  689. package/src/orchestrator/annotation-store.ts +24 -3
  690. package/src/orchestrator/artifact-origin.ts +50 -0
  691. package/src/orchestrator/campaign-lifecycle.ts +5 -1
  692. package/src/orchestrator/candidates.ts +3 -2
  693. package/src/orchestrator/compare.ts +62 -13
  694. package/src/orchestrator/comparison-identity.ts +2 -0
  695. package/src/orchestrator/config.ts +23 -1
  696. package/src/orchestrator/discover.ts +8 -1
  697. package/src/orchestrator/doctor.ts +211 -65
  698. package/src/orchestrator/driver-capabilities.ts +21 -0
  699. package/src/orchestrator/driver-identity.ts +69 -0
  700. package/src/orchestrator/experiment-context.ts +5 -3
  701. package/src/orchestrator/experiment-corpus.ts +58 -37
  702. package/src/orchestrator/experiment-effects.ts +63 -0
  703. package/src/orchestrator/experiment-evaluation.ts +88 -10
  704. package/src/orchestrator/experiment-identity.ts +57 -48
  705. package/src/orchestrator/experiment-preflight.ts +27 -0
  706. package/src/orchestrator/experiment-report.ts +21 -1
  707. package/src/orchestrator/experiment-runs.ts +11 -4
  708. package/src/orchestrator/experiment-runtime-identity.ts +5 -243
  709. package/src/orchestrator/experiment-selection.ts +178 -18
  710. package/src/orchestrator/experiment.ts +29 -29
  711. package/src/orchestrator/fixture-identity.ts +9 -1
  712. package/src/orchestrator/fs-read.ts +2 -32
  713. package/src/orchestrator/grader-experiment.ts +74 -13
  714. package/src/orchestrator/grading.ts +60 -31
  715. package/src/orchestrator/harness-catalog-drift.ts +132 -0
  716. package/src/orchestrator/harness-registry.ts +12 -0
  717. package/src/orchestrator/index.ts +1 -0
  718. package/src/orchestrator/list-runs.ts +102 -18
  719. package/src/orchestrator/optimization-lifecycle.ts +4 -1
  720. package/src/orchestrator/orchestrator.ts +105 -224
  721. package/src/orchestrator/paired-effects.ts +214 -0
  722. package/src/orchestrator/profile.ts +24 -0
  723. package/src/orchestrator/provenance.ts +23 -3
  724. package/src/orchestrator/rubric-loader.ts +1 -1
  725. package/src/orchestrator/run-dir.ts +8 -1
  726. package/src/orchestrator/run-execution.ts +75 -10
  727. package/src/orchestrator/run-lifecycle.ts +4 -2
  728. package/src/orchestrator/run-workspace.ts +62 -0
  729. package/src/orchestrator/suite-compare.ts +47 -23
  730. package/src/orchestrator/suite-runs.ts +13 -2
  731. package/src/orchestrator/suite-summary.ts +129 -15
  732. package/src/previewer/artifacts.ts +221 -0
  733. package/src/previewer/server.ts +789 -0
  734. package/viewer/app.css +2111 -0
  735. package/viewer/app.js +627 -0
  736. package/viewer/artifact-view.js +48 -0
  737. package/viewer/charts.js +98 -0
  738. package/viewer/detail.js +1266 -0
  739. package/viewer/format.js +129 -0
  740. package/viewer/index.html +151 -0
  741. package/lib/cli/skills.d.ts +0 -38
  742. package/lib/cli/skills.d.ts.map +0 -1
  743. package/lib/cli/skills.js +0 -84
  744. package/lib/cli/skills.js.map +0 -1
  745. package/lib/drivers/shared/secure-copy.d.ts.map +0 -1
  746. package/lib/drivers/shared/secure-copy.js.map +0 -1
  747. package/skills/lux/SKILL.md +0 -89
  748. package/skills/lux/references/cli.md +0 -125
  749. package/skills/lux/references/eval-authoring.md +0 -257
  750. package/src/cli/skills.ts +0 -129
  751. /package/lib/{drivers/shared → core}/secure-copy.d.ts +0 -0
  752. /package/lib/{drivers/shared → core}/secure-copy.js +0 -0
  753. /package/src/{drivers/shared → core}/secure-copy.ts +0 -0
@@ -1,10 +1,15 @@
1
- import { basename, extname, isAbsolute, join, resolve } from "node:path";
1
+ import { basename, extname, join, resolve } from "node:path";
2
+ import { ContainerDriver } from "../container/driver.js";
3
+ import { driverExecutionOf } from "../core/driver-execution.js";
4
+ import { type EnvironmentDeclaration, EnvironmentDeclarationSchema } from "../core/environment.js";
2
5
  import {
3
6
  type Answerer,
4
7
  type AnswererModelCallAccounting,
5
8
  type AnswererRef,
6
9
  bindSubjectRoot,
7
10
  type DriverRef,
11
+ driverConfigOf,
12
+ driverNameOf,
8
13
  type EvalCase,
9
14
  type GradingAssertionEntry,
10
15
  type GradingReport,
@@ -18,12 +23,19 @@ import {
18
23
  type SuiteLifecycleHookContext,
19
24
  valueHash,
20
25
  } from "../core/index.js";
26
+ import {
27
+ mergeAnswererReference,
28
+ mergeDriverReference,
29
+ withDriverDefaults,
30
+ } from "../core/reference-defaults.js";
21
31
  import {
22
32
  fixturesForEvalCase,
23
33
  mergeLifecycleFixtures,
24
34
  registryForEvalCase,
25
35
  valuesForFixtures,
26
36
  } from "./case-extensions.js";
37
+ import { isBuiltinDriver } from "./config.js";
38
+ import { validateDriverCapabilities } from "./driver-capabilities.js";
27
39
  import { evaluatorImplementationHash } from "./evaluator-identity.js";
28
40
  import {
29
41
  assertionEvaluatorIdentities,
@@ -102,11 +114,13 @@ const recordLifecycleCleanupFailure = async (result: RunResult, error: unknown):
102
114
  };
103
115
 
104
116
  export type OrchestratorOptions = {
117
+ environment?: EnvironmentDeclaration | undefined;
105
118
  registry: Registry;
106
119
  /** Answerer used when a case names none. Defaults to "persona". */
107
120
  defaultAnswerer?: AnswererRef;
108
121
  /** Driver used when a case names none. */
109
122
  defaultDriver?: DriverRef;
123
+ driverDefaults?: Record<string, unknown> | undefined;
110
124
  /** Shared provider/model defaults for built-in harness components. */
111
125
  harness?: HarnessModelConfig;
112
126
  /** Versioned project resource fixtures. */
@@ -114,6 +128,8 @@ export type OrchestratorOptions = {
114
128
  };
115
129
 
116
130
  export type RunRequest = {
131
+ /** Effective parent suite worker limit; direct runs default to one. */
132
+ suiteConcurrency?: number | undefined;
117
133
  /** Path to a TS case file. Mutually exclusive with `case`. */
118
134
  casePath?: string;
119
135
  /** Pre-loaded EvalCase. Mutually exclusive with `casePath`. */
@@ -137,6 +153,12 @@ export type RunRequest = {
137
153
  subjectRoot?: string | undefined;
138
154
  subjectHash?: string | undefined;
139
155
  profileId?: string | undefined;
156
+ /**
157
+ * Driver bound by a harness permutation. It replaces the project default;
158
+ * a case pinned to another driver is rejected rather than silently rerouted.
159
+ */
160
+ driver?: DriverRef | undefined;
161
+ permutationId?: string | undefined;
140
162
  experimentId?: string | undefined;
141
163
  variantId?: string | undefined;
142
164
  candidateId?: string | undefined;
@@ -195,7 +217,13 @@ export type SuiteObserver = RunObserver & {
195
217
  * `caseId` is the canonical id runs are filed under when the case declares
196
218
  * none — display decorations (a `--loop` suffix) must not fork run history.
197
219
  */
198
- export type SuiteItem = { path: string; id: string; caseId?: string | undefined };
220
+ export type SuiteItem = {
221
+ path: string;
222
+ id: string;
223
+ caseId?: string | undefined;
224
+ driver?: DriverRef | undefined;
225
+ permutationId?: string | undefined;
226
+ };
199
227
 
200
228
  const resolveCaseId = (casePath: string, evalCase: EvalCase, fallback?: string): string => {
201
229
  if (evalCase.id) return evalCase.id;
@@ -206,40 +234,24 @@ const resolveCaseId = (casePath: string, evalCase: EvalCase, fallback?: string):
206
234
  return ext ? base.slice(0, -ext.length) : base;
207
235
  };
208
236
 
209
- const driverNameOf = (ref: DriverRef): string => (typeof ref === "string" ? ref : ref.name);
210
-
211
- const isRecord = (value: unknown): value is Record<string, unknown> =>
212
- Boolean(value) && typeof value === "object" && !Array.isArray(value);
213
-
214
- /** Merge plugin config recursively so nested Codex `config`/`env` overrides stay additive. */
215
- const mergePluginConfig = (base: unknown, local: unknown): unknown => {
216
- if (!isRecord(base) || !isRecord(local)) return local ?? base;
217
- const merged: Record<string, unknown> = { ...base };
218
- for (const [key, value] of Object.entries(local)) {
219
- merged[key] = key in merged ? mergePluginConfig(merged[key], value) : value;
220
- }
221
- return merged;
222
- };
223
-
224
237
  export const resolveDriverReference = (
225
238
  evalCase: EvalCase,
226
239
  fallback: DriverRef | undefined,
240
+ permutation?: DriverRef | undefined,
241
+ defaults?: Record<string, unknown> | undefined,
227
242
  ): DriverRef => {
228
243
  const local = evalCase.driver;
229
- if (!local) {
230
- if (!fallback) throw new Error("case names no driver and no defaultDriver is configured");
231
- return fallback;
244
+ if (permutation && local && driverNameOf(local) !== driverNameOf(permutation)) {
245
+ throw new Error(
246
+ `case is pinned to driver '${driverNameOf(local)}' but the run selected '${driverNameOf(permutation)}'`,
247
+ );
232
248
  }
233
- if (!fallback || driverNameOf(local) !== driverNameOf(fallback)) return local;
234
-
235
- // Naming the same driver opts into project defaults. A case object only
236
- // needs to carry the fields it wants to override (for example a timeout).
237
- const baseConfig = typeof fallback === "object" ? fallback.config : undefined;
238
- const localConfig = typeof local === "object" ? local.config : undefined;
239
- return {
240
- name: driverNameOf(local),
241
- config: mergePluginConfig(baseConfig, localConfig),
242
- };
249
+ const reference = withDriverDefaults(
250
+ mergeDriverReference(permutation ?? fallback, local),
251
+ defaults,
252
+ );
253
+ if (!reference) throw new Error("case names no driver and no defaultDriver is configured");
254
+ return reference;
243
255
  };
244
256
 
245
257
  export const resolveAnswererReference = (
@@ -248,7 +260,18 @@ export const resolveAnswererReference = (
248
260
  harness: HarnessModelConfig | undefined,
249
261
  override?: string,
250
262
  ): AnswererRef => {
251
- const ref = override ?? evalCase.answerer ?? fallback;
263
+ const fallbackName = typeof fallback === "string" ? fallback : fallback.name;
264
+ const inherited =
265
+ harness && fallbackName === "persona"
266
+ ? {
267
+ name: "persona",
268
+ config: mergeHarnessModelConfig(
269
+ harness,
270
+ typeof fallback === "object" ? fallback.config : undefined,
271
+ ),
272
+ }
273
+ : fallback;
274
+ const ref = mergeAnswererReference(inherited, override ?? evalCase.answerer) as AnswererRef;
252
275
  const name = typeof ref === "string" ? ref : ref.name;
253
276
  if (!harness || name !== "persona") return ref;
254
277
  return {
@@ -259,197 +282,25 @@ export const resolveAnswererReference = (
259
282
 
260
283
  const answererNameOf = (ref: AnswererRef): string => (typeof ref === "string" ? ref : ref.name);
261
284
 
262
- const driverConfigOf = (ref: DriverRef): unknown =>
263
- typeof ref === "object" ? ref.config : undefined;
264
-
265
285
  const answererConfigOf = (ref: AnswererRef): unknown =>
266
286
  typeof ref === "object" ? ref.config : undefined;
267
287
 
268
- const EXPERIMENT_BEHAVIOR_SOURCE_ARGS = new Set([
269
- "--continue",
270
- "-c",
271
- "--fork-session",
272
- "--resume",
273
- "-r",
274
- "--add-dir",
275
- "--append-system-prompt-file",
276
- "--mcp-config",
277
- "--plugin-dir",
278
- "--settings",
279
- "--setting-sources",
280
- "--system-prompt-file",
281
- ]);
282
-
283
- const CODEX_EXPERIMENT_SOURCE_ARGS = new Set([
284
- "--add-dir",
285
- "--cd",
286
- "-C",
287
- "--config",
288
- "-c",
289
- "--profile",
290
- "-p",
291
- ]);
292
-
293
- const bindSubprocessExperimentConfig = (config: Record<string, unknown>): unknown => {
294
- if (typeof config.command !== "string" || !isAbsolute(config.command)) {
295
- throw new Error(
296
- "experiment subprocess commands must be absolute direct wrappers so Lux can fingerprint the invoked behavior",
297
- );
298
- }
299
- if (typeof config.cwd === "string") {
300
- throw new Error(
301
- "experiment runs do not allow an explicit subprocess cwd; use the candidate subject and staged fixtures",
302
- );
303
- }
304
- if (Array.isArray(config.args) && config.args.length > 0) {
305
- throw new Error(
306
- "experiment subprocesses do not allow args; put stable behavior in the fingerprinted direct wrapper",
307
- );
308
- }
309
- if (isRecord(config.env) && Object.keys(config.env).length > 0) {
310
- throw new Error(
311
- "experiment subprocesses do not allow custom env; put stable behavior in the fingerprinted direct wrapper",
312
- );
313
- }
314
- return { ...config, inheritEnv: false };
315
- };
316
-
317
- type AgentDriverName = "claude-code" | "codex";
318
-
319
- const validateAgentExperimentConfig = (
320
- driverName: AgentDriverName,
321
- config: Record<string, unknown>,
322
- ): { driverEnv: Record<string, unknown>; extraArgs: string[] } => {
323
- const driverEnv = isRecord(config.env) ? config.env : {};
324
- const commandResolutionOverride = Object.keys(driverEnv).find((name) =>
325
- ["PATH", "PATHEXT"].includes(name.toUpperCase()),
326
- );
327
- if (commandResolutionOverride) {
328
- throw new Error(
329
- `experiment runs do not allow driver env.${commandResolutionOverride}; command resolution must match the fingerprinted host executable`,
330
- );
331
- }
332
- if (typeof config.cwd === "string") {
333
- throw new Error(
334
- `experiment runs do not allow an explicit ${driverName} cwd; use the candidate subject and staged fixtures`,
335
- );
336
- }
337
-
338
- const extraArgs = Array.isArray(config.extraArgs)
339
- ? config.extraArgs.filter((value): value is string => typeof value === "string")
340
- : [];
341
- const disallowedArgs =
342
- driverName === "claude-code" ? EXPERIMENT_BEHAVIOR_SOURCE_ARGS : CODEX_EXPERIMENT_SOURCE_ARGS;
343
- const behaviorSourceArg = extraArgs.find((arg) =>
344
- [...disallowedArgs].some((name) => arg === name || arg.startsWith(`${name}=`)),
345
- );
346
- if (behaviorSourceArg) {
347
- throw new Error(
348
- `experiment runs do not allow behavior-bearing extraArgs '${behaviorSourceArg}'; use structured driver fields so Lux can fingerprint the source`,
349
- );
350
- }
351
-
352
- const isolation = isRecord(config.isolation) ? config.isolation : {};
353
- const structuredPaths = [
354
- ...(driverName === "claude-code" && Array.isArray(config.pluginDirs) ? config.pluginDirs : []),
355
- ...(Array.isArray(config.addDirs) ? config.addDirs : []),
356
- ...(driverName === "claude-code" && Array.isArray(isolation.allowRead)
357
- ? isolation.allowRead
358
- : []),
359
- ].filter((value): value is string => typeof value === "string");
360
- const relativeSource = structuredPaths.find((path) => !isAbsolute(path));
361
- if (relativeSource) {
362
- throw new Error(
363
- `experiment driver source paths must be absolute after subjectPath binding: ${relativeSource}`,
364
- );
365
- }
366
- return { driverEnv, extraArgs };
367
- };
368
-
369
- const bindCodexExperimentConfig = (
370
- config: Record<string, unknown>,
371
- extraArgs: readonly string[],
372
- ): unknown => {
373
- if (typeof config.profile === "string") {
374
- throw new Error(
375
- "experiment runs do not allow a Codex profile; use inline driver config so Lux can fingerprint it",
376
- );
377
- }
378
- if (config.ephemeral === false) {
379
- throw new Error("experiment runs require ephemeral Codex sessions");
380
- }
381
- const inlineConfig = isRecord(config.config) ? config.config : {};
382
- const externalConfigKey = ((): string | undefined => {
383
- const visit = (value: Record<string, unknown>, parent = ""): string | undefined => {
384
- for (const [key, nested] of Object.entries(value)) {
385
- const path = parent ? `${parent}.${key}` : key;
386
- if (/(?:mcp_servers|instructions_file|notify|project_doc)/i.test(key)) return path;
387
- if (isRecord(nested)) {
388
- const found = visit(nested, path);
389
- if (found) return found;
390
- }
391
- }
392
- return undefined;
393
- };
394
- return visit(inlineConfig);
395
- })();
396
- if (externalConfigKey) {
397
- throw new Error(
398
- `experiment runs do not allow path-bearing Codex config '${externalConfigKey}'`,
399
- );
400
- }
401
- const appServer = config.interactionMode !== "exec";
402
- return {
403
- ...config,
404
- ephemeral: true,
405
- ignoreUserConfig: true,
406
- ignoreRules: true,
407
- ...(appServer && !config.isolation ? { isolation: { allowRead: [] } } : {}),
408
- extraArgs,
409
- };
410
- };
411
-
412
- const bindClaudeExperimentConfig = (
413
- config: Record<string, unknown>,
414
- extraArgs: readonly string[],
415
- driverEnv: Record<string, unknown>,
416
- ): unknown => {
417
- if (config.isolation) return config;
418
- return {
419
- ...config,
420
- extraArgs: [
421
- ...extraArgs,
422
- "--setting-sources",
423
- "user",
424
- "--strict-mcp-config",
425
- "--settings",
426
- JSON.stringify({ disableAllHooks: true }),
427
- ],
428
- env: {
429
- ...driverEnv,
430
- CLAUDE_CODE_DISABLE_AUTO_MEMORY: "1",
431
- CLAUDE_CODE_DISABLE_CLAUDE_MDS: "1",
432
- CLAUDE_CODE_SKIP_PROMPT_HISTORY: "1",
433
- CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1",
434
- CLAUDE_CODE_AUTO_CONNECT_IDE: "false",
435
- CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL: "1",
436
- DISABLE_AUTOUPDATER: "1",
437
- },
438
- };
439
- };
440
-
441
288
  export const boundExperimentDriverConfig = (
442
- driverName: string,
289
+ plugin: import("../core/driver.js").DriverPlugin,
443
290
  config: unknown,
444
291
  experimentId: string | undefined,
445
292
  ): unknown => {
446
- if (!experimentId || !isRecord(config)) return config;
447
- if (driverName === "subprocess") return bindSubprocessExperimentConfig(config);
448
- if (driverName !== "claude-code" && driverName !== "codex") return config;
449
- const { driverEnv, extraArgs } = validateAgentExperimentConfig(driverName, config);
450
- return driverName === "codex"
451
- ? bindCodexExperimentConfig(config, extraArgs)
452
- : bindClaudeExperimentConfig(config, extraArgs, driverEnv);
293
+ if (!experimentId) return config;
294
+ if (!plugin.experiment) {
295
+ throw new Error(
296
+ `driver '${plugin.name}' supports ordinary eval runs but does not declare controlled experiment support`,
297
+ );
298
+ }
299
+ return validatePluginConfig(
300
+ plugin.configSchema,
301
+ plugin.experiment.prepare(config),
302
+ `driver '${plugin.name}' experiment configuration`,
303
+ );
453
304
  };
454
305
 
455
306
  const closeQuietly = async (close: () => Promise<void>, label: string): Promise<void> => {
@@ -463,17 +314,23 @@ const closeQuietly = async (close: () => Promise<void>, label: string): Promise<
463
314
  };
464
315
 
465
316
  export class Orchestrator {
317
+ private readonly environment: EnvironmentDeclaration | undefined;
466
318
  private evaluatorHash: Promise<string> | undefined;
467
319
  readonly registry: Registry;
468
320
  private readonly defaultAnswerer: AnswererRef;
469
321
  private readonly defaultDriver: DriverRef | undefined;
322
+ private readonly driverDefaults: Record<string, unknown> | undefined;
470
323
  private readonly harness: HarnessModelConfig | undefined;
471
324
  private readonly lifecycleFixtures: readonly LifecycleHooksPlugin[];
472
325
 
473
326
  constructor(options: OrchestratorOptions) {
327
+ this.environment = options.environment
328
+ ? EnvironmentDeclarationSchema.parse(options.environment)
329
+ : undefined;
474
330
  this.registry = options.registry;
475
331
  this.defaultAnswerer = options.defaultAnswerer ?? "persona";
476
332
  this.defaultDriver = options.defaultDriver;
333
+ this.driverDefaults = options.driverDefaults;
477
334
  this.harness = options.harness;
478
335
  this.lifecycleFixtures = [...(options.lifecycleFixtures ?? [])];
479
336
  }
@@ -512,13 +369,19 @@ export class Orchestrator {
512
369
  registry,
513
370
  );
514
371
 
515
- const driverRef = resolveDriverReference(evalCase, this.defaultDriver);
372
+ const driverRef = bindSubjectRoot(
373
+ resolveDriverReference(evalCase, this.defaultDriver, request.driver, this.driverDefaults),
374
+ request.subjectRoot,
375
+ );
516
376
  const driverName = driverNameOf(driverRef);
517
- const answererRef = resolveAnswererReference(
518
- evalCase,
519
- this.defaultAnswerer,
520
- this.harness,
521
- request.answererOverride,
377
+ const answererRef = bindSubjectRoot(
378
+ resolveAnswererReference(
379
+ evalCase,
380
+ this.defaultAnswerer,
381
+ this.harness,
382
+ request.answererOverride,
383
+ ),
384
+ request.subjectRoot,
522
385
  );
523
386
  const answererName = answererNameOf(answererRef);
524
387
 
@@ -534,7 +397,7 @@ export class Orchestrator {
534
397
  // Validate both configs before instantiating either plugin so a
535
398
  // schema failure can't leak a half-initialized driver/answerer.
536
399
  const driverCfg = boundExperimentDriverConfig(
537
- driverName,
400
+ driverPlugin,
538
401
  validatePluginConfig(
539
402
  driverPlugin.configSchema,
540
403
  driverConfigOf(driverRef),
@@ -548,7 +411,20 @@ export class Orchestrator {
548
411
  `answerer '${answererName}'`,
549
412
  );
550
413
 
551
- const driver = await driverPlugin.create(driverCfg);
414
+ const execution = driverExecutionOf(driverRef);
415
+ if (execution?.kind === "container" && request.experimentId)
416
+ throw new Error("container execution does not yet support controlled experiments");
417
+ if (
418
+ execution?.kind === "container" &&
419
+ !execution.driverModule &&
420
+ !isBuiltinDriver(driverPlugin)
421
+ )
422
+ throw new Error("custom container drivers require execution.driverModule in the image");
423
+ validateDriverCapabilities(driverPlugin, driverCfg, evalCase.requires, execution);
424
+ const driver =
425
+ execution?.kind === "container"
426
+ ? new ContainerDriver(driverName, driverCfg, execution)
427
+ : await driverPlugin.create(driverCfg);
552
428
  let answerer: Answerer;
553
429
  try {
554
430
  answerer = await answererPlugin.create(answererCfg);
@@ -581,9 +457,10 @@ export class Orchestrator {
581
457
  validatedAssertionConfigs,
582
458
  caseId,
583
459
  driverName,
460
+ permutationId: request.permutationId,
584
461
  answererName,
585
462
  answererConfig: answererCfg,
586
- driverConfigHash: valueHash(driverCfg),
463
+ driverConfigHash: valueHash(execution ? { config: driverCfg, execution } : driverCfg),
587
464
  answererConfigHash: valueHash(answererCfg),
588
465
  validatedAssertionsHash,
589
466
  graderConfigHash: graderHash,
@@ -599,6 +476,7 @@ export class Orchestrator {
599
476
  skipJudge: request.skipJudge ?? false,
600
477
  }),
601
478
  fixtureValues: valuesForFixtures(lifecycleFixtures),
479
+ environment: this.environment,
602
480
  driver,
603
481
  answerer,
604
482
  },
@@ -797,9 +675,12 @@ export class Orchestrator {
797
675
  observer: handle ?? observer,
798
676
  abortSignal: opts.abortSignal,
799
677
  suiteId: suite.manifest.suiteId,
678
+ suiteConcurrency: concurrency,
800
679
  subjectRoot: opts.subjectRoot,
801
680
  subjectHash: opts.subjectHash,
802
681
  profileId: opts.profileId,
682
+ driver: item.driver,
683
+ permutationId: item.permutationId,
803
684
  experimentId: opts.experimentId,
804
685
  variantId: opts.variantId,
805
686
  candidateId: opts.candidateId,
@@ -0,0 +1,214 @@
1
+ import { z } from "zod";
2
+ import { clusterKey } from "../core/evaluation-clusters.js";
3
+ import {
4
+ bootstrapMeanConfidenceInterval,
5
+ type CandidateEvaluation,
6
+ type ConfidenceConfig,
7
+ ConfidenceIntervalSchema,
8
+ } from "../core/index.js";
9
+
10
+ type CaseSamples = NonNullable<CandidateEvaluation["caseSamples"]>;
11
+ type Evaluation = CandidateEvaluation & { repetitions: number };
12
+
13
+ export const clusterCaseSamples = (
14
+ groups: readonly (CaseSamples | undefined)[],
15
+ ): CaseSamples | undefined => {
16
+ if (groups.some((group) => group === undefined)) return undefined;
17
+ const result = new Map<string, CaseSamples[string]>();
18
+ for (const group of groups) {
19
+ for (const [id, sample] of Object.entries(group ?? {})) {
20
+ const current = result.get(id);
21
+ if (!current) {
22
+ result.set(id, structuredClone(sample));
23
+ continue;
24
+ }
25
+ if (current.identityHash !== sample.identityHash) current.identityHash = null;
26
+ if (current.clusterId !== sample.clusterId) current.identityHash = null;
27
+ if (current.scoreBasis !== sample.scoreBasis) current.scoreBasis = null;
28
+ const metrics = new Map(Object.entries(current.metrics));
29
+ for (const [metric, value] of Object.entries(sample.metrics)) {
30
+ const before = metrics.get(metric);
31
+ metrics.set(
32
+ metric,
33
+ before
34
+ ? {
35
+ mean: (before.mean * before.n + value.mean * value.n) / (before.n + value.n),
36
+ n: before.n + value.n,
37
+ }
38
+ : { ...value },
39
+ );
40
+ }
41
+ current.metrics = Object.fromEntries(metrics);
42
+ }
43
+ }
44
+ return Object.fromEntries(result);
45
+ };
46
+
47
+ const caseGroups = (samples: CaseSamples): Map<string, string[]> => {
48
+ const groups = new Map<string, string[]>();
49
+ for (const id of Object.keys(samples).sort()) {
50
+ const key = clusterKey(id, samples[id]?.clusterId);
51
+ groups.set(key, [...(groups.get(key) ?? []), id]);
52
+ }
53
+ return groups;
54
+ };
55
+
56
+ export const groupedCaseMetricSamples = (
57
+ samples: CaseSamples | undefined,
58
+ repetitions: number,
59
+ ): Record<string, number[]> | undefined => {
60
+ if (!samples || !Object.values(samples).some((sample) => sample.clusterId !== undefined))
61
+ return undefined;
62
+ const groups = caseGroups(samples);
63
+ const metrics = new Set(Object.values(samples).flatMap((sample) => Object.keys(sample.metrics)));
64
+ return Object.fromEntries(
65
+ [...metrics].flatMap((metric) => {
66
+ if (
67
+ Object.values(samples).some(
68
+ (sample) =>
69
+ !Object.hasOwn(sample.metrics, metric) ||
70
+ sample.metrics[metric]?.n !== repetitions ||
71
+ (metric === "score" && !sample.scoreBasis),
72
+ )
73
+ )
74
+ return [];
75
+ return [
76
+ [
77
+ metric,
78
+ [...groups.values()].map(
79
+ (ids) =>
80
+ ids.reduce((sum, id) => sum + (samples[id]?.metrics[metric]?.mean ?? 0), 0) /
81
+ ids.length,
82
+ ),
83
+ ],
84
+ ];
85
+ }),
86
+ );
87
+ };
88
+
89
+ export const PairedEffectSchema = z.object({
90
+ caseIds: z.array(z.string()),
91
+ n: z.number().int().nonnegative(),
92
+ caseCount: z.number().int().nonnegative().optional(),
93
+ clusters: z.record(z.string(), z.array(z.string())).optional(),
94
+ meanDelta: z.number().finite().nullable(),
95
+ interval: ConfidenceIntervalSchema.nullable(),
96
+ note: z.string().nullable(),
97
+ });
98
+ export type PairedEffect = z.infer<typeof PairedEffectSchema>;
99
+
100
+ export const confidenceGateIssue = (
101
+ interval: z.infer<typeof ConfidenceIntervalSchema>,
102
+ ): string | undefined =>
103
+ interval.method === "percentile-bootstrap" && interval.lower === interval.upper
104
+ ? "zero-width percentile-bootstrap interval cannot establish promotion confidence; use Hoeffding for bounded means or collect more varied independent evidence"
105
+ : undefined;
106
+
107
+ const pairedDeltas = (
108
+ before: Evaluation | undefined,
109
+ after: Evaluation | undefined,
110
+ metric: string,
111
+ ): { caseIds: string[]; values: number[]; clusters: Record<string, string[]> } => {
112
+ if (!before?.caseSamples || !after?.caseSamples)
113
+ throw new Error("keyed case evidence unavailable");
114
+ if (
115
+ before.profileId !== after.profileId ||
116
+ before.split !== after.split ||
117
+ before.repetitions !== after.repetitions
118
+ ) {
119
+ throw new Error("paired evidence requires matching profile, split, and repetitions");
120
+ }
121
+ const caseIds = Object.keys(before.caseSamples).sort();
122
+ const afterIds = Object.keys(after.caseSamples).sort();
123
+ const beforeCases = Object.keys(before.casePassRates).sort();
124
+ const afterCases = Object.keys(after.casePassRates).sort();
125
+ if (
126
+ caseIds.length === 0 ||
127
+ [afterIds, beforeCases, afterCases].some(
128
+ (ids) => JSON.stringify(ids) !== JSON.stringify(caseIds),
129
+ )
130
+ ) {
131
+ throw new Error("paired evidence requires identical canonical case sets");
132
+ }
133
+ const values = caseIds.map((id) => {
134
+ const a = before.caseSamples?.[id];
135
+ const b = after.caseSamples?.[id];
136
+ if (!a?.identityHash || a.identityHash !== b?.identityHash)
137
+ throw new Error(`paired case '${id}' has incompatible evaluation identity`);
138
+ if (metric === "score" && (!a.scoreBasis || a.scoreBasis !== b.scoreBasis))
139
+ throw new Error(`paired score for case '${id}' has different or unavailable scoring basis`);
140
+ if (a.clusterId !== b.clusterId)
141
+ throw new Error(`paired case '${id}' has incompatible cluster membership`);
142
+ const av = Object.hasOwn(a.metrics, metric) ? a.metrics[metric] : undefined;
143
+ const bv = Object.hasOwn(b.metrics, metric) ? b.metrics[metric] : undefined;
144
+ if (!av || !bv || av.n !== before.repetitions || bv.n !== after.repetitions) {
145
+ throw new Error(
146
+ `paired metric '${metric}' lacks complete repetition coverage for case '${id}'`,
147
+ );
148
+ }
149
+ return bv.mean - av.mean;
150
+ });
151
+ const byCase = new Map(caseIds.map((id, index) => [id, values[index] ?? 0]));
152
+ const groups = caseGroups(before.caseSamples);
153
+ return {
154
+ caseIds,
155
+ clusters: Object.fromEntries(groups),
156
+ values: [...groups.values()].map(
157
+ (ids) => ids.reduce((sum, id) => sum + (byCase.get(id) ?? 0), 0) / ids.length,
158
+ ),
159
+ };
160
+ };
161
+
162
+ export const pairedEffect = (
163
+ before: Evaluation | undefined,
164
+ after: Evaluation | undefined,
165
+ metric: string,
166
+ confidence?: ConfidenceConfig,
167
+ ): PairedEffect => {
168
+ let paired: ReturnType<typeof pairedDeltas>;
169
+ try {
170
+ paired = pairedDeltas(before, after, metric);
171
+ } catch (error) {
172
+ return {
173
+ caseIds: [],
174
+ n: 0,
175
+ caseCount: 0,
176
+ clusters: {},
177
+ meanDelta: null,
178
+ interval: null,
179
+ note: error instanceof Error ? error.message : String(error),
180
+ };
181
+ }
182
+ const result: PairedEffect = {
183
+ caseIds: paired.caseIds,
184
+ n: paired.values.length,
185
+ caseCount: paired.caseIds.length,
186
+ clusters: paired.clusters,
187
+ meanDelta: paired.values.reduce((sum, value) => sum + value, 0) / paired.values.length,
188
+ interval: null,
189
+ note: null,
190
+ };
191
+ if (!confidence) return result;
192
+ try {
193
+ if (confidence.method === "wilson")
194
+ throw new Error("Wilson cannot estimate paired differences");
195
+ if (confidence.method === "hoeffding") {
196
+ const interval = bootstrapMeanConfidenceInterval(
197
+ paired.values.map((value) => (value + 1) / 2),
198
+ confidence,
199
+ );
200
+ result.interval = {
201
+ ...interval,
202
+ estimate: 2 * interval.estimate - 1,
203
+ lower: 2 * interval.lower - 1,
204
+ upper: 2 * interval.upper - 1,
205
+ };
206
+ } else {
207
+ result.interval = bootstrapMeanConfidenceInterval(paired.values, confidence);
208
+ }
209
+ result.note = confidenceGateIssue(result.interval) ?? null;
210
+ } catch (error) {
211
+ result.note = error instanceof Error ? error.message : String(error);
212
+ }
213
+ return result;
214
+ };