@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
@@ -2,6 +2,7 @@ import { basename } from "node:path";
2
2
  import { z } from "zod";
3
3
  import { valueHash } from "../core/index.js";
4
4
  import { deriveExperimentSelection, rankCandidates } from "./experiment.js";
5
+ import { ExperimentEffectsSchema, experimentEffects } from "./experiment-effects.js";
5
6
  import {
6
7
  type ExperimentRun,
7
8
  ExperimentRunSchema,
@@ -24,6 +25,7 @@ export const ExperimentDecisionReportSchema = z
24
25
  status: z.enum(["running", "passed", "failed", "aborted"]),
25
26
  outcome: z.enum(["promote", "retain", "reject", "error", "incomplete"]),
26
27
  error: z.string().nullable(),
28
+ effects: z.exactOptional(ExperimentEffectsSchema),
27
29
  candidateAndAccountingVerified: z.boolean(),
28
30
  championCandidateId: z.string().nullable(),
29
31
  ranking: z.array(z.string()),
@@ -39,6 +41,7 @@ export const ExperimentDecisionReportSchema = z
39
41
  z
40
42
  .object({
41
43
  metric: z.string(),
44
+ relativeTo: z.exactOptional(z.literal("baseline")),
42
45
  profile: z.string().nullable(),
43
46
  split: ExperimentReportSplitSchema,
44
47
  passed: z.boolean(),
@@ -596,6 +599,7 @@ const projectExperimentDecisionReport = (
596
599
  evaluationKind: experiment.evaluationKind,
597
600
  status: experiment.status,
598
601
  error: experiment.errorMessage ?? null,
602
+ effects: experimentEffects(experiment),
599
603
  candidateAndAccountingVerified,
600
604
  outcome: reportOutcome(experiment, championId),
601
605
  championCandidateId: championId,
@@ -610,6 +614,7 @@ const projectExperimentDecisionReport = (
610
614
  .filter((constraint) => constraint.candidateId === targetId)
611
615
  .map((constraint) => ({
612
616
  metric: constraint.metric,
617
+ ...(constraint.relativeTo ? { relativeTo: constraint.relativeTo } : {}),
613
618
  profile: constraint.profile ?? null,
614
619
  split: constraint.split,
615
620
  passed: constraint.passed,
@@ -733,7 +738,7 @@ export const formatExperimentDecisionMarkdown = (report: ExperimentDecisionRepor
733
738
  "| --- | --- | --- | --- | ---: | --- | --- |",
734
739
  ...report.gates.map(
735
740
  (gate) =>
736
- `| ${gate.passed ? "PASS" : "FAIL"} | ${markdown(gate.metric)} | ${markdown(gate.profile ?? "all")} | ${gate.split} | ${gate.values.map(concise).join(", ") || "—"} | ${markdown(gate.interval ?? "—")} | ${markdown(gate.note ?? "—")} |`,
741
+ `| ${gate.passed ? "PASS" : "FAIL"} | ${markdown(gate.metric)}${gate.relativeTo ? " Δ baseline" : ""} | ${markdown(gate.profile ?? "all")} | ${gate.split} | ${gate.values.map(concise).join(", ") || "—"} | ${markdown(gate.interval ?? "—")} | ${markdown(gate.note ?? "—")} |`,
737
742
  ),
738
743
  );
739
744
  }
@@ -763,6 +768,21 @@ export const formatExperimentDecisionMarkdown = (report: ExperimentDecisionRepor
763
768
  ),
764
769
  );
765
770
  }
771
+ if (report.effects?.length) {
772
+ lines.push(
773
+ "",
774
+ "## Paired case effects",
775
+ "",
776
+ "Differences are candidate minus baseline; repetitions are averaged within cases and authored clusters receive equal weight.",
777
+ "",
778
+ "| Candidate | Profile | Split | Metric | Mean difference | Cases | Clusters | Confidence | Note |",
779
+ "| --- | --- | --- | --- | ---: | ---: | ---: | --- | --- |",
780
+ ...report.effects.map(
781
+ (effect) =>
782
+ `| ${markdown(effect.candidateId)} | ${markdown(effect.profileId)} | ${effect.split} | ${markdown(effect.metric)} | ${effect.meanDelta === null ? "—" : signed(effect.meanDelta)} | ${effect.caseCount ?? effect.caseIds.length} | ${effect.n} | ${markdown(intervalText(effect.interval ?? undefined) ?? "—")} | ${markdown(effect.note ?? "—")} |`,
783
+ ),
784
+ );
785
+ }
766
786
  lines.push(
767
787
  "",
768
788
  "## Source and spend",
@@ -86,6 +86,7 @@ export const ExperimentSelectionSchema = z.object({
86
86
  z.object({
87
87
  candidateId: CandidateIdSchema,
88
88
  metric: z.string(),
89
+ relativeTo: z.exactOptional(z.literal("baseline")),
89
90
  profile: z.exactOptional(z.string()),
90
91
  split: z.enum(["train", "validation", "test"]),
91
92
  values: z.array(z.number()),
@@ -738,6 +739,7 @@ export const resumeExperimentRun = async (path: string): Promise<OpenedExperimen
738
739
 
739
740
  export const listExperimentRuns = async (
740
741
  runsRoot: string,
742
+ options: { onReadError?: (path: string, error: unknown) => void } = {},
741
743
  ): Promise<Array<ExperimentRun & { experimentDir: string }>> => {
742
744
  const root = join(resolve(runsRoot), EXPERIMENTS_DIR);
743
745
  if (!existsSync(root)) return [];
@@ -745,10 +747,15 @@ export const listExperimentRuns = async (
745
747
  .filter((entry) => entry.isDirectory())
746
748
  .map((entry) => join(root, entry.name));
747
749
  const runs = await Promise.all(
748
- directories.map(async (experimentDir) => ({
749
- experimentDir,
750
- experiment: await loadExperimentRun(experimentDir),
751
- })),
750
+ directories.map(async (experimentDir) => {
751
+ try {
752
+ return { experimentDir, experiment: await loadExperimentRun(experimentDir) };
753
+ } catch (error) {
754
+ if (!options.onReadError) throw error;
755
+ options.onReadError(experimentDir, error);
756
+ return { experimentDir, experiment: null };
757
+ }
758
+ }),
752
759
  );
753
760
  return runs
754
761
  .flatMap(({ experimentDir, experiment }) =>
@@ -1,61 +1,14 @@
1
1
  import { createHash } from "node:crypto";
2
- import { access, constants, lstat, open, readFile, realpath } from "node:fs/promises";
3
- import { homedir } from "node:os";
2
+ import { access, constants, lstat, open, realpath } from "node:fs/promises";
4
3
  import { delimiter, isAbsolute, join, resolve } from "node:path";
5
4
  import { z } from "zod";
6
- import { contentHash, discoverCliVersion, valueHash } from "../core/index.js";
7
- import { walkAuthoredFiles } from "./fs-read.js";
8
- import { boundExperimentDriverConfig } from "./orchestrator.js";
5
+ import { discoverCliVersion, valueHash } from "../core/index.js";
9
6
 
10
7
  export { LUX_VERSION } from "./package-version.js";
11
8
 
12
- const ClaudeSettingsFileSchema = z.looseObject({
13
- enabledPlugins: z.record(z.string(), z.boolean()).optional(),
14
- });
15
- const ClaudeInstalledPluginRecordSchema = z.looseObject({
16
- installPath: z.string(),
17
- });
18
- const ClaudeInstalledPluginsFileSchema = z.looseObject({
19
- plugins: z.record(z.string(), z.array(ClaudeInstalledPluginRecordSchema)),
20
- });
21
-
22
- export const referencedCli = (
23
- reference: unknown,
24
- ): { name: string; command: string } | undefined => {
25
- let name: string | undefined;
26
- if (typeof reference === "string") {
27
- name = reference;
28
- } else if (
29
- typeof reference === "object" &&
30
- reference !== null &&
31
- typeof (reference as { name?: unknown }).name === "string"
32
- ) {
33
- name = (reference as { name: string }).name;
34
- }
35
- const config =
36
- typeof reference === "object" && reference !== null
37
- ? (reference as { config?: unknown }).config
38
- : undefined;
39
- if (name === "subprocess") {
40
- if (
41
- typeof config !== "object" ||
42
- config === null ||
43
- typeof (config as { command?: unknown }).command !== "string"
44
- ) {
45
- return undefined;
46
- }
47
- return { name, command: (config as { command: string }).command };
48
- }
49
- if (name !== "claude-code" && name !== "codex") return undefined;
50
- let command = name === "codex" ? "codex" : "claude";
51
- if (
52
- typeof config === "object" &&
53
- config !== null &&
54
- typeof (config as { command?: unknown }).command === "string"
55
- ) {
56
- command = (config as { command: string }).command;
57
- }
58
- return { name, command };
9
+ const driverConfigRecord = (reference: unknown): Record<string, unknown> => {
10
+ const config = (reference as { config?: unknown } | null)?.config;
11
+ return config && typeof config === "object" ? (config as Record<string, unknown>) : {};
59
12
  };
60
13
 
61
14
  export const referencedAnswererCli = (
@@ -261,197 +214,6 @@ export const cliIdentity = async (command: string, baseRoot: string): Promise<Cl
261
214
  });
262
215
  };
263
216
 
264
- const optionalRegularFileHash = async (path: string): Promise<string | null> => {
265
- try {
266
- const info = await lstat(path);
267
- if (info.isSymbolicLink() || !info.isFile()) {
268
- throw new Error(`behavior-affecting settings must be a regular file: ${path}`);
269
- }
270
- return contentHash(await readFile(path));
271
- } catch (error) {
272
- if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
273
- throw error;
274
- }
275
- };
276
-
277
- const driverConfigRecord = (driver: unknown): Record<string, unknown> => {
278
- if (!driver || typeof driver !== "object") return {};
279
- const config = (driver as { config?: unknown }).config;
280
- return config && typeof config === "object" ? (config as Record<string, unknown>) : {};
281
- };
282
-
283
- export const claudeConfigRoot = (driver: unknown): string => {
284
- const config = driverConfigRecord(driver);
285
- const env =
286
- config.env && typeof config.env === "object"
287
- ? (config.env as Record<string, unknown>)
288
- : undefined;
289
- const configured = env?.CLAUDE_CONFIG_DIR;
290
- const root =
291
- typeof configured === "string"
292
- ? configured
293
- : (process.env.CLAUDE_CONFIG_DIR ?? join(homedir(), ".claude"));
294
- if (!isAbsolute(root)) {
295
- throw new Error("CLAUDE_CONFIG_DIR must be absolute for reproducible experiment identity");
296
- }
297
- return resolve(root);
298
- };
299
-
300
- const hashBehaviorDirectory = async (
301
- root: string,
302
- label: string,
303
- ): Promise<Array<{ path: string; hash: string }>> => {
304
- try {
305
- const info = await lstat(root);
306
- if (info.isSymbolicLink() || !info.isDirectory()) {
307
- throw new Error(`behavior-affecting Claude source must be a real directory: ${root}`);
308
- }
309
- } catch (error) {
310
- if ((error as NodeJS.ErrnoException).code === "ENOENT") return [];
311
- throw error;
312
- }
313
- const paths = await walkAuthoredFiles(root);
314
- if (paths.length > 5_000) {
315
- throw new Error(`behavior-affecting Claude source '${label}' exceeds 5000 files`);
316
- }
317
- let bytes = 0;
318
- const hashes: Array<{ path: string; hash: string }> = [];
319
- for (const path of paths) {
320
- const content = await readFile(join(root, path));
321
- bytes += content.length;
322
- if (bytes > 256 * 1024 * 1024) {
323
- throw new Error(`behavior-affecting Claude source '${label}' exceeds 256 MiB`);
324
- }
325
- hashes.push({ path: `${label}/${path}`, hash: contentHash(content) });
326
- }
327
- return hashes;
328
- };
329
-
330
- /**
331
- * Hash every intentionally loaded user behavior source without persisting its
332
- * contents. This covers user instructions/rules/output styles and the exact
333
- * installed contents of plugins enabled by settings.json.
334
- */
335
- export const claudeUserBehaviorHash = async (configRoot: string): Promise<string | null> => {
336
- const settingsPath = join(configRoot, "settings.json");
337
- const settingsHash = await optionalRegularFileHash(settingsPath);
338
- const sources: Array<{ path: string; hash: string }> = [];
339
- if (settingsHash) sources.push({ path: "settings.json", hash: settingsHash });
340
- const claudeMdHash = await optionalRegularFileHash(join(configRoot, "CLAUDE.md"));
341
- if (claudeMdHash) sources.push({ path: "CLAUDE.md", hash: claudeMdHash });
342
- for (const directory of ["rules", "output-styles", "agents", "commands", "skills"]) {
343
- sources.push(...(await hashBehaviorDirectory(join(configRoot, directory), directory)));
344
- }
345
-
346
- let settings: unknown;
347
- try {
348
- const contents = await readFile(settingsPath, "utf8");
349
- try {
350
- settings = JSON.parse(contents);
351
- } catch {
352
- throw new Error("Claude settings.json contains invalid JSON");
353
- }
354
- } catch (error) {
355
- if ((error as NodeJS.ErrnoException).code === "ENOENT") {
356
- settings = undefined;
357
- } else {
358
- throw error;
359
- }
360
- }
361
- const parsedSettings = ClaudeSettingsFileSchema.safeParse(settings);
362
- if (settings !== undefined && !parsedSettings.success) {
363
- throw new Error("Claude settings.json has an invalid enabledPlugins map");
364
- }
365
- const enabledPlugins = parsedSettings.success ? parsedSettings.data.enabledPlugins : undefined;
366
- const enabledIds = Object.entries(enabledPlugins ?? {})
367
- .filter(([, value]) => value === true)
368
- .map(([id]) => id)
369
- .sort();
370
- if (enabledIds.length > 0) {
371
- const installedPath = join(configRoot, "plugins", "installed_plugins.json");
372
- const installedHash = await optionalRegularFileHash(installedPath);
373
- if (installedHash) {
374
- sources.push({ path: "plugins/installed_plugins.json", hash: installedHash });
375
- }
376
- let installed: unknown;
377
- try {
378
- installed = JSON.parse(await readFile(installedPath, "utf8"));
379
- } catch {
380
- installed = undefined;
381
- }
382
- const parsedInstalled = ClaudeInstalledPluginsFileSchema.safeParse(installed);
383
- if (!parsedInstalled.success) {
384
- throw new Error("enabled Claude plugins have invalid installed metadata");
385
- }
386
- const plugins = parsedInstalled.data.plugins;
387
- for (const id of enabledIds) {
388
- const records = plugins[id];
389
- if (!records || records.length === 0) {
390
- throw new Error(`enabled Claude plugin '${id}' has no installed content to hash`);
391
- }
392
- for (const [index, record] of records.entries()) {
393
- const installPath = record.installPath;
394
- sources.push(
395
- ...(await hashBehaviorDirectory(resolve(installPath), `plugins/enabled/${id}/${index}`)),
396
- );
397
- }
398
- }
399
- }
400
- return sources.length === 0 ? null : valueHash(sources);
401
- };
402
-
403
- export const configuredClaudeSourceHashes = async (
404
- driver: unknown,
405
- baseRoot: string,
406
- cache: Map<string, Promise<string>> = new Map(),
407
- ): Promise<Array<{ kind: "plugin" | "read"; path: string; hash: string }>> => {
408
- const driverCli = referencedCli(driver);
409
- if (!driverCli) return [];
410
- const config = driverConfigRecord(driver);
411
- // This also rejects path-bearing extraArgs that would evade the source
412
- // hashes below. Runtime applies the same guard before driver creation.
413
- boundExperimentDriverConfig(driverCli.name, config, "identity-check");
414
- const isolation =
415
- config.isolation && typeof config.isolation === "object"
416
- ? (config.isolation as Record<string, unknown>)
417
- : undefined;
418
- const configured = [
419
- ...(driverCli.name === "claude-code" && Array.isArray(config.pluginDirs)
420
- ? config.pluginDirs.map((path) => ({ kind: "plugin" as const, path }))
421
- : []),
422
- ...(Array.isArray(config.addDirs)
423
- ? config.addDirs.map((path) => ({ kind: "read" as const, path }))
424
- : []),
425
- ...(driverCli.name === "claude-code" && isolation && Array.isArray(isolation.allowRead)
426
- ? isolation.allowRead.map((path) => ({ kind: "read" as const, path }))
427
- : []),
428
- ].filter(
429
- (entry): entry is { kind: "plugin" | "read"; path: string } =>
430
- typeof entry.path === "string" && entry.path.length > 0,
431
- );
432
- return Promise.all(
433
- configured
434
- .sort((a, b) => `${a.kind}:${a.path}`.localeCompare(`${b.kind}:${b.path}`))
435
- .map(async ({ kind, path }) => {
436
- const absolute = resolve(baseRoot, path);
437
- const key = `${kind}:${absolute}`;
438
- let hash = cache.get(key);
439
- if (!hash) {
440
- hash = hashBehaviorDirectory(
441
- absolute,
442
- `driver/${kind}/${contentHash(absolute).slice(0, 12)}`,
443
- ).then(valueHash);
444
- cache.set(key, hash);
445
- }
446
- return {
447
- kind,
448
- path: absolute,
449
- hash: await hash,
450
- };
451
- }),
452
- );
453
- };
454
-
455
217
  export const runtimeCliIdentityHashForReferences = async (
456
218
  references: readonly RuntimeCliReference[],
457
219
  ): Promise<string> =>
@@ -13,6 +13,7 @@ import {
13
13
  ExperimentSelectionSchema,
14
14
  type OpenedExperimentRun,
15
15
  } from "./experiment-runs.js";
16
+ import { confidenceGateIssue, type PairedEffect, pairedEffect } from "./paired-effects.js";
16
17
 
17
18
  type ExperimentSplit = "train" | "validation" | "test";
18
19
 
@@ -103,6 +104,7 @@ const satisfiesConstraint = (
103
104
  constraint: ExperimentConstraint,
104
105
  experiment: OpenedExperimentRun["manifest"],
105
106
  ): boolean => {
107
+ if (constraint.relativeTo && candidate.id === "baseline") return true;
106
108
  let profiles: (string | undefined)[];
107
109
  if (constraint.metric === "subject.bytes" || constraint.profile) {
108
110
  profiles = [constraint.profile];
@@ -110,6 +112,16 @@ const satisfiesConstraint = (
110
112
  profiles = campaign.profiles;
111
113
  }
112
114
  return profiles.every((profile) => {
115
+ if (constraint.relativeTo) {
116
+ const effect = relativeConstraintEffect(candidate, constraint, profile, experiment);
117
+ if (effect.note || effect.meanDelta === null) return false;
118
+ const lower = effect.interval?.lower ?? effect.meanDelta;
119
+ const upper = effect.interval?.upper ?? effect.meanDelta;
120
+ return (
121
+ (constraint.min === undefined || lower >= constraint.min) &&
122
+ (constraint.max === undefined || upper <= constraint.max)
123
+ );
124
+ }
113
125
  const values = metricValues(
114
126
  candidate,
115
127
  constraint.metric,
@@ -135,6 +147,7 @@ const satisfiesConstraint = (
135
147
  return sampleGroups.every((samples) => {
136
148
  try {
137
149
  const interval = bootstrapMeanConfidenceInterval(samples, constraint.confidence);
150
+ if (confidenceGateIssue(interval)) return false;
138
151
  return (
139
152
  (constraint.min === undefined || interval.lower >= constraint.min) &&
140
153
  (constraint.max === undefined || interval.upper <= constraint.max)
@@ -156,12 +169,29 @@ const satisfiesConstraint = (
156
169
  export const average = (values: readonly number[]): number =>
157
170
  values.reduce((sum, value) => sum + value, 0) / Math.max(values.length, 1);
158
171
 
172
+ const relativeConstraintEffect = (
173
+ candidate: ExperimentDecisionCandidate,
174
+ constraint: ExperimentConstraint,
175
+ profile: string | undefined,
176
+ experiment: OpenedExperimentRun["manifest"],
177
+ ): PairedEffect => {
178
+ const scope = (entry: ExperimentEvaluation): boolean =>
179
+ entry.profileId === profile && entry.split === constraint.split;
180
+ return pairedEffect(
181
+ candidateEvaluations(experiment, "baseline").find(scope),
182
+ candidateEvaluations(experiment, candidate.id).find(scope),
183
+ constraint.metric,
184
+ constraint.confidence,
185
+ );
186
+ };
187
+
159
188
  const normalizedConstraintViolation = (
160
189
  campaign: ExperimentCampaign,
161
190
  candidate: ExperimentDecisionCandidate,
162
191
  constraint: ExperimentConstraint,
163
192
  experiment: OpenedExperimentRun["manifest"],
164
193
  ): number => {
194
+ if (constraint.relativeTo && candidate.id === "baseline") return 0;
165
195
  let profiles: Array<string | undefined> = campaign.profiles;
166
196
  if (constraint.metric === "subject.bytes" || constraint.profile) {
167
197
  profiles = [constraint.profile];
@@ -177,6 +207,18 @@ const normalizedConstraintViolation = (
177
207
  );
178
208
  let worst = 0;
179
209
  for (const profile of profiles) {
210
+ if (constraint.relativeTo) {
211
+ const effect = relativeConstraintEffect(candidate, constraint, profile, experiment);
212
+ if (effect.note || effect.meanDelta === null) return Number.POSITIVE_INFINITY;
213
+ worst = Math.max(
214
+ worst,
215
+ violation(
216
+ effect.interval?.lower ?? effect.meanDelta,
217
+ effect.interval?.upper ?? effect.meanDelta,
218
+ ),
219
+ );
220
+ continue;
221
+ }
180
222
  if (constraint.confidence) {
181
223
  const groups = metricSampleGroups(
182
224
  candidate,
@@ -189,6 +231,7 @@ const normalizedConstraintViolation = (
189
231
  for (const samples of groups) {
190
232
  try {
191
233
  const interval = bootstrapMeanConfidenceInterval(samples, constraint.confidence);
234
+ if (confidenceGateIssue(interval)) return Number.POSITIVE_INFINITY;
192
235
  worst = Math.max(worst, violation(interval.lower, interval.upper));
193
236
  } catch {
194
237
  return Number.POSITIVE_INFINITY;
@@ -209,13 +252,65 @@ const normalizedConstraintViolation = (
209
252
  return worst;
210
253
  };
211
254
 
255
+ const hasScoreEvidence = (
256
+ experiment: OpenedExperimentRun["manifest"],
257
+ split: ExperimentSplit,
258
+ ): boolean =>
259
+ [...new Set(experiment.evaluations.map((entry) => entry.candidateId))]
260
+ .flatMap((id) => candidateEvaluations(experiment, id))
261
+ .some(
262
+ (entry) =>
263
+ entry.split === split &&
264
+ (entry.metricDefinitions?.score !== undefined ||
265
+ entry.metrics.score !== undefined ||
266
+ Object.values(entry.caseSamples ?? {}).some(
267
+ (sample) => sample.metrics.score !== undefined,
268
+ )),
269
+ );
270
+
271
+ const completeScoreEvidence = (entry: ExperimentEvaluation): boolean =>
272
+ entry.metrics.score !== undefined &&
273
+ (!entry.caseSamples ||
274
+ Object.keys(entry.casePassRates).every((id) => {
275
+ const sample = entry.caseSamples?.[id];
276
+ return sample?.metrics.score?.n === entry.repetitions && Boolean(sample.scoreBasis);
277
+ }));
278
+
279
+ const comparableScoreBasis = (
280
+ entry: ExperimentEvaluation,
281
+ reference: ExperimentEvaluation | undefined,
282
+ ): boolean => {
283
+ if (!reference || !completeScoreEvidence(reference)) return false;
284
+ if (!entry.caseSamples || !reference.caseSamples)
285
+ return !entry.caseSamples && !reference.caseSamples;
286
+ const ids = new Set([
287
+ ...Object.keys(entry.casePassRates),
288
+ ...Object.keys(reference.casePassRates),
289
+ ]);
290
+ return [...ids].every((id) => {
291
+ const basis = entry.caseSamples?.[id]?.scoreBasis;
292
+ return Boolean(basis) && basis === reference.caseSamples?.[id]?.scoreBasis;
293
+ });
294
+ };
295
+
212
296
  export const rankCandidates = <T extends ExperimentDecisionCandidate>(
213
297
  campaign: ExperimentCampaign,
214
298
  candidates: readonly T[],
215
299
  experiment: OpenedExperimentRun["manifest"],
216
300
  constraintSplits: readonly ExperimentSplit[] = ["train", "validation", "test"],
217
- ): T[] =>
218
- [...candidates].sort((a, b) => {
301
+ ): T[] => {
302
+ const validationEvaluations = (id: string): ExperimentEvaluation[] =>
303
+ candidateEvaluations(experiment, id).filter((entry) => entry.split === "validation");
304
+ const referenceId = ["baseline", ...candidates.map((candidate) => candidate.id).sort()].find(
305
+ (id) => {
306
+ const entries = validationEvaluations(id);
307
+ return campaign.profiles.every((profile) =>
308
+ entries.some((entry) => entry.profileId === profile && completeScoreEvidence(entry)),
309
+ );
310
+ },
311
+ );
312
+ const reference = referenceId ? validationEvaluations(referenceId) : [];
313
+ return [...candidates].sort((a, b) => {
219
314
  const activeConstraints = campaign.objectives.constraints.filter((constraint) =>
220
315
  constraintSplits.includes(constraint.split),
221
316
  );
@@ -267,20 +362,40 @@ export const rankCandidates = <T extends ExperimentDecisionCandidate>(
267
362
  }
268
363
  }
269
364
  const quality = (candidate: ExperimentDecisionCandidate): number => {
270
- const values = metricValues(
271
- candidate,
272
- "quality.passRate",
273
- undefined,
274
- "validation",
275
- experiment,
276
- );
277
- return values.length > 0 ? Math.min(...values) : -1;
365
+ if (!hasScoreEvidence(experiment, "validation")) {
366
+ const values = metricValues(
367
+ candidate,
368
+ "quality.passRate",
369
+ undefined,
370
+ "validation",
371
+ experiment,
372
+ );
373
+ return values.length > 0 ? Math.min(...values) : -1;
374
+ }
375
+ const evaluations = candidateEvaluations(experiment, candidate.id);
376
+ const scores = campaign.profiles.map((profile) => {
377
+ const entry = evaluations.find(
378
+ (value) => value.profileId === profile && value.split === "validation",
379
+ );
380
+ if (
381
+ !entry ||
382
+ !completeScoreEvidence(entry) ||
383
+ !comparableScoreBasis(
384
+ entry,
385
+ reference.find((value) => value.profileId === profile),
386
+ )
387
+ )
388
+ return -1;
389
+ return entry.metrics.score ?? -1;
390
+ });
391
+ return scores.length > 0 ? Math.min(...scores) : -1;
278
392
  };
279
393
  const qualityDelta = quality(b) - quality(a);
280
394
  if (qualityDelta !== 0) return qualityDelta;
281
395
  if (a.sourceBytes !== b.sourceBytes) return a.sourceBytes - b.sourceBytes;
282
396
  return a.id.localeCompare(b.id);
283
397
  });
398
+ };
284
399
 
285
400
  const candidateCaseVector = (
286
401
  candidate: Candidate,
@@ -295,10 +410,15 @@ const candidateCaseVector = (
295
410
  evaluations
296
411
  .filter((entry) => entry.split === split)
297
412
  .flatMap((entry) =>
298
- Object.entries(entry.casePassRates).map(([caseId, passRate]) => [
299
- `${entry.profileId}:${caseId}`,
300
- passRate,
301
- ]),
413
+ Object.entries(entry.casePassRates).flatMap(([caseId, passRate]) => {
414
+ if (!hasScoreEvidence(experiment, split))
415
+ return [[`${entry.profileId}:${caseId}`, passRate]];
416
+ const sample = entry.caseSamples?.[caseId];
417
+ const score = sample?.metrics.score;
418
+ return score?.n === entry.repetitions && sample?.scoreBasis
419
+ ? [[JSON.stringify([entry.profileId, caseId, sample.scoreBasis]), score.mean]]
420
+ : [];
421
+ }),
302
422
  ),
303
423
  );
304
424
  };
@@ -308,8 +428,9 @@ const dominates = (a: Record<string, number>, b: Record<string, number>): boolea
308
428
  if (keys.size === 0) return false;
309
429
  let strictlyBetter = false;
310
430
  for (const key of keys) {
311
- const av = a[key] ?? 0;
312
- const bv = b[key] ?? 0;
431
+ const av = a[key];
432
+ const bv = b[key];
433
+ if (av === undefined || bv === undefined) return false;
313
434
  if (av < bv) return false;
314
435
  if (av > bv) strictlyBetter = true;
315
436
  }
@@ -361,8 +482,13 @@ const frontierCoverage = (
361
482
  const candidateVector = candidateCaseVector(candidate, experiment, "train");
362
483
  const keys = new Set(vectors.flatMap((vector) => Object.keys(vector)));
363
484
  return [...keys].filter((key) => {
364
- const best = Math.max(...vectors.map((vector) => vector[key] ?? 0));
365
- return (candidateVector[key] ?? 0) === best;
485
+ const values = vectors.flatMap((vector) => (vector[key] === undefined ? [] : [vector[key]]));
486
+ const best = Math.max(...values);
487
+ return (
488
+ (frontier.length === 1 || values.length > 1) &&
489
+ candidateVector[key] !== undefined &&
490
+ candidateVector[key] === best
491
+ );
366
492
  }).length;
367
493
  };
368
494
 
@@ -379,6 +505,36 @@ export const searchFrontier = (
379
505
  });
380
506
  };
381
507
 
508
+ const relativeConstraintReport = (
509
+ campaign: ExperimentCampaign,
510
+ candidate: ExperimentDecisionCandidate,
511
+ constraint: ExperimentConstraint,
512
+ profile: string | undefined,
513
+ experiment: OpenedExperimentRun["manifest"],
514
+ ): ExperimentSelection["constraints"][number] => {
515
+ const effect = relativeConstraintEffect(candidate, constraint, profile, experiment);
516
+ const reference = candidate.id === "baseline";
517
+ let values = effect.meanDelta === null ? [] : [effect.meanDelta];
518
+ if (reference) values = [0];
519
+ const note = reference ? "baseline reference; relative gate does not apply" : effect.note;
520
+ return {
521
+ candidateId: candidate.id,
522
+ metric: constraint.metric,
523
+ relativeTo: "baseline",
524
+ ...(profile ? { profile } : {}),
525
+ split: constraint.split,
526
+ values,
527
+ passed: satisfiesConstraint(
528
+ campaign,
529
+ candidate,
530
+ { ...constraint, ...(profile ? { profile } : {}) },
531
+ experiment,
532
+ ),
533
+ ...(!reference && effect.interval ? { interval: effect.interval } : {}),
534
+ ...(note ? { note } : {}),
535
+ };
536
+ };
537
+
382
538
  export const deriveExperimentSelection = (
383
539
  campaign: ExperimentCampaign,
384
540
  candidates: readonly ExperimentDecisionCandidate[],
@@ -405,6 +561,9 @@ export const deriveExperimentSelection = (
405
561
  ? [constraint.profile]
406
562
  : campaign.profiles;
407
563
  return profiles.map((profile) => {
564
+ if (constraint.relativeTo) {
565
+ return relativeConstraintReport(campaign, candidate, constraint, profile, experiment);
566
+ }
408
567
  const values = metricValues(
409
568
  candidate,
410
569
  constraint.metric,
@@ -426,6 +585,7 @@ export const deriveExperimentSelection = (
426
585
  if (samples) {
427
586
  try {
428
587
  interval = bootstrapMeanConfidenceInterval(samples, constraint.confidence);
588
+ note = confidenceGateIssue(interval);
429
589
  } catch (error) {
430
590
  note = error instanceof Error ? error.message : String(error);
431
591
  }