@prismatic-io/lux 0.0.2-preview.17 → 0.0.2-preview.20

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 (273) hide show
  1. package/lib/answerers/persona/index.d.ts +5 -1
  2. package/lib/answerers/persona/index.d.ts.map +1 -1
  3. package/lib/assertions/rubric/index.d.ts +3 -1
  4. package/lib/assertions/rubric/index.d.ts.map +1 -1
  5. package/lib/authoring.d.ts +3 -1
  6. package/lib/authoring.d.ts.map +1 -1
  7. package/lib/authoring.js +2 -1
  8. package/lib/authoring.js.map +1 -1
  9. package/lib/cli/doctor.d.ts +55 -0
  10. package/lib/cli/doctor.d.ts.map +1 -0
  11. package/lib/cli/doctor.js +14 -0
  12. package/lib/cli/doctor.js.map +1 -0
  13. package/lib/cli/harness-plan.d.ts +26 -0
  14. package/lib/cli/harness-plan.d.ts.map +1 -0
  15. package/lib/cli/harness-plan.js +75 -0
  16. package/lib/cli/harness-plan.js.map +1 -0
  17. package/lib/cli/init-templates.d.ts +2 -2
  18. package/lib/cli/init-templates.d.ts.map +1 -1
  19. package/lib/cli/init-templates.js +11 -4
  20. package/lib/cli/init-templates.js.map +1 -1
  21. package/lib/cli/init.d.ts +2 -0
  22. package/lib/cli/init.d.ts.map +1 -1
  23. package/lib/cli/init.js +6 -3
  24. package/lib/cli/init.js.map +1 -1
  25. package/lib/cli/output-schemas.d.ts +7 -0
  26. package/lib/cli/output-schemas.d.ts.map +1 -1
  27. package/lib/cli/program.d.ts +8 -11
  28. package/lib/cli/program.d.ts.map +1 -1
  29. package/lib/cli/program.js +54 -89
  30. package/lib/cli/program.js.map +1 -1
  31. package/lib/cli/run-options.d.ts +19 -0
  32. package/lib/cli/run-options.d.ts.map +1 -1
  33. package/lib/cli/run-options.js +92 -0
  34. package/lib/cli/run-options.js.map +1 -1
  35. package/lib/core/case.d.ts +2 -0
  36. package/lib/core/case.d.ts.map +1 -1
  37. package/lib/core/case.js +3 -0
  38. package/lib/core/case.js.map +1 -1
  39. package/lib/core/driver.d.ts +13 -0
  40. package/lib/core/driver.d.ts.map +1 -1
  41. package/lib/core/driver.js +10 -0
  42. package/lib/core/driver.js.map +1 -1
  43. package/lib/core/harness-catalog.d.ts +35 -0
  44. package/lib/core/harness-catalog.d.ts.map +1 -0
  45. package/lib/core/harness-catalog.js +45 -0
  46. package/lib/core/harness-catalog.js.map +1 -0
  47. package/lib/core/harness-catalogs/antigravity.d.ts +11 -0
  48. package/lib/core/harness-catalogs/antigravity.d.ts.map +1 -0
  49. package/lib/core/harness-catalogs/antigravity.js +23 -0
  50. package/lib/core/harness-catalogs/antigravity.js.map +1 -0
  51. package/lib/core/harness-catalogs/claude-code.d.ts +12 -0
  52. package/lib/core/harness-catalogs/claude-code.d.ts.map +1 -0
  53. package/lib/core/harness-catalogs/claude-code.js +24 -0
  54. package/lib/core/harness-catalogs/claude-code.js.map +1 -0
  55. package/lib/core/harness-catalogs/codex.d.ts +11 -0
  56. package/lib/core/harness-catalogs/codex.d.ts.map +1 -0
  57. package/lib/core/harness-catalogs/codex.js +26 -0
  58. package/lib/core/harness-catalogs/codex.js.map +1 -0
  59. package/lib/core/harness-catalogs/copilot.d.ts +29 -0
  60. package/lib/core/harness-catalogs/copilot.d.ts.map +1 -0
  61. package/lib/core/harness-catalogs/copilot.js +45 -0
  62. package/lib/core/harness-catalogs/copilot.js.map +1 -0
  63. package/lib/core/harness-catalogs/cursor.d.ts +2 -0
  64. package/lib/core/harness-catalogs/cursor.d.ts.map +1 -0
  65. package/lib/core/harness-catalogs/cursor.js +13 -0
  66. package/lib/core/harness-catalogs/cursor.js.map +1 -0
  67. package/lib/core/harness-catalogs/index.d.ts +67 -0
  68. package/lib/core/harness-catalogs/index.d.ts.map +1 -0
  69. package/lib/core/harness-catalogs/index.js +15 -0
  70. package/lib/core/harness-catalogs/index.js.map +1 -0
  71. package/lib/core/harness-matrix.d.ts +70 -0
  72. package/lib/core/harness-matrix.d.ts.map +1 -0
  73. package/lib/core/harness-matrix.js +194 -0
  74. package/lib/core/harness-matrix.js.map +1 -0
  75. package/lib/core/index.d.ts +3 -0
  76. package/lib/core/index.d.ts.map +1 -1
  77. package/lib/core/index.js +3 -0
  78. package/lib/core/index.js.map +1 -1
  79. package/lib/core/model-cli.d.ts +4 -11
  80. package/lib/core/model-cli.d.ts.map +1 -1
  81. package/lib/core/model-cli.js +23 -17
  82. package/lib/core/model-cli.js.map +1 -1
  83. package/lib/core/platform-process.d.ts +1 -0
  84. package/lib/core/platform-process.d.ts.map +1 -1
  85. package/lib/core/platform-process.js +1 -1
  86. package/lib/core/platform-process.js.map +1 -1
  87. package/lib/core/run.d.ts +4 -0
  88. package/lib/core/run.d.ts.map +1 -1
  89. package/lib/core/run.js +2 -0
  90. package/lib/core/run.js.map +1 -1
  91. package/lib/drivers/antigravity/config.d.ts +46 -0
  92. package/lib/drivers/antigravity/config.d.ts.map +1 -0
  93. package/lib/drivers/antigravity/config.js +39 -0
  94. package/lib/drivers/antigravity/config.js.map +1 -0
  95. package/lib/drivers/antigravity/events.d.ts +4 -0
  96. package/lib/drivers/antigravity/events.d.ts.map +1 -0
  97. package/lib/drivers/antigravity/events.js +193 -0
  98. package/lib/drivers/antigravity/events.js.map +1 -0
  99. package/lib/drivers/antigravity/index.d.ts +60 -0
  100. package/lib/drivers/antigravity/index.d.ts.map +1 -0
  101. package/lib/drivers/antigravity/index.js +90 -0
  102. package/lib/drivers/antigravity/index.js.map +1 -0
  103. package/lib/drivers/claude-code/index.d.ts +93 -7
  104. package/lib/drivers/claude-code/index.d.ts.map +1 -1
  105. package/lib/drivers/claude-code/index.js +8 -6
  106. package/lib/drivers/claude-code/index.js.map +1 -1
  107. package/lib/drivers/codex/config.d.ts +55 -4
  108. package/lib/drivers/codex/config.d.ts.map +1 -1
  109. package/lib/drivers/codex/config.js +9 -5
  110. package/lib/drivers/codex/config.js.map +1 -1
  111. package/lib/drivers/codex/index.d.ts +56 -5
  112. package/lib/drivers/codex/index.d.ts.map +1 -1
  113. package/lib/drivers/codex/index.js +5 -2
  114. package/lib/drivers/codex/index.js.map +1 -1
  115. package/lib/drivers/copilot/config.d.ts +81 -0
  116. package/lib/drivers/copilot/config.d.ts.map +1 -0
  117. package/lib/drivers/copilot/config.js +54 -0
  118. package/lib/drivers/copilot/config.js.map +1 -0
  119. package/lib/drivers/copilot/index.d.ts +103 -0
  120. package/lib/drivers/copilot/index.d.ts.map +1 -0
  121. package/lib/drivers/copilot/index.js +256 -0
  122. package/lib/drivers/copilot/index.js.map +1 -0
  123. package/lib/drivers/cursor/config.d.ts +6 -1
  124. package/lib/drivers/cursor/config.d.ts.map +1 -1
  125. package/lib/drivers/cursor/config.js +2 -3
  126. package/lib/drivers/cursor/config.js.map +1 -1
  127. package/lib/drivers/cursor/index.d.ts +7 -2
  128. package/lib/drivers/cursor/index.d.ts.map +1 -1
  129. package/lib/drivers/cursor/index.js +9 -6
  130. package/lib/drivers/cursor/index.js.map +1 -1
  131. package/lib/drivers/cursor/interaction.d.ts +1 -2
  132. package/lib/drivers/cursor/interaction.d.ts.map +1 -1
  133. package/lib/drivers/cursor/interaction.js +3 -14
  134. package/lib/drivers/cursor/interaction.js.map +1 -1
  135. package/lib/drivers/{cursor/events.d.ts → shared/acp-events.d.ts} +5 -3
  136. package/lib/drivers/shared/acp-events.d.ts.map +1 -0
  137. package/lib/drivers/{cursor/events.js → shared/acp-events.js} +20 -10
  138. package/lib/drivers/shared/acp-events.js.map +1 -0
  139. package/lib/drivers/shared/acp-interaction.d.ts +7 -0
  140. package/lib/drivers/shared/acp-interaction.d.ts.map +1 -0
  141. package/lib/drivers/shared/acp-interaction.js +20 -0
  142. package/lib/drivers/shared/acp-interaction.js.map +1 -0
  143. package/lib/drivers/{cursor → shared}/acp-transport.d.ts +2 -0
  144. package/lib/drivers/shared/acp-transport.d.ts.map +1 -0
  145. package/lib/drivers/{cursor → shared}/acp-transport.js +10 -10
  146. package/lib/drivers/shared/acp-transport.js.map +1 -0
  147. package/lib/index.d.ts +7 -2
  148. package/lib/index.d.ts.map +1 -1
  149. package/lib/index.js +7 -2
  150. package/lib/index.js.map +1 -1
  151. package/lib/optimization/reflective.d.ts +2 -0
  152. package/lib/optimization/reflective.d.ts.map +1 -1
  153. package/lib/orchestrator/comparison-identity.d.ts.map +1 -1
  154. package/lib/orchestrator/comparison-identity.js +1 -0
  155. package/lib/orchestrator/comparison-identity.js.map +1 -1
  156. package/lib/orchestrator/config.d.ts +7 -0
  157. package/lib/orchestrator/config.d.ts.map +1 -1
  158. package/lib/orchestrator/config.js +8 -1
  159. package/lib/orchestrator/config.js.map +1 -1
  160. package/lib/orchestrator/doctor.d.ts +1 -0
  161. package/lib/orchestrator/doctor.d.ts.map +1 -1
  162. package/lib/orchestrator/doctor.js +86 -8
  163. package/lib/orchestrator/doctor.js.map +1 -1
  164. package/lib/orchestrator/experiment-context.d.ts +5 -3
  165. package/lib/orchestrator/experiment-context.d.ts.map +1 -1
  166. package/lib/orchestrator/experiment-context.js.map +1 -1
  167. package/lib/orchestrator/experiment-corpus.d.ts +2 -1
  168. package/lib/orchestrator/experiment-corpus.d.ts.map +1 -1
  169. package/lib/orchestrator/experiment-corpus.js +9 -1
  170. package/lib/orchestrator/experiment-corpus.js.map +1 -1
  171. package/lib/orchestrator/experiment-identity.d.ts +3 -0
  172. package/lib/orchestrator/experiment-identity.d.ts.map +1 -1
  173. package/lib/orchestrator/experiment-identity.js +1 -1
  174. package/lib/orchestrator/experiment-identity.js.map +1 -1
  175. package/lib/orchestrator/experiment-preflight.d.ts +3 -0
  176. package/lib/orchestrator/experiment-preflight.d.ts.map +1 -0
  177. package/lib/orchestrator/experiment-preflight.js +21 -0
  178. package/lib/orchestrator/experiment-preflight.js.map +1 -0
  179. package/lib/orchestrator/experiment.d.ts +3 -1
  180. package/lib/orchestrator/experiment.d.ts.map +1 -1
  181. package/lib/orchestrator/experiment.js +3 -6
  182. package/lib/orchestrator/experiment.js.map +1 -1
  183. package/lib/orchestrator/harness-catalog-drift.d.ts +22 -0
  184. package/lib/orchestrator/harness-catalog-drift.d.ts.map +1 -0
  185. package/lib/orchestrator/harness-catalog-drift.js +90 -0
  186. package/lib/orchestrator/harness-catalog-drift.js.map +1 -0
  187. package/lib/orchestrator/orchestrator.d.ts +9 -1
  188. package/lib/orchestrator/orchestrator.d.ts.map +1 -1
  189. package/lib/orchestrator/orchestrator.js +14 -22
  190. package/lib/orchestrator/orchestrator.js.map +1 -1
  191. package/lib/orchestrator/run-dir.d.ts +2 -0
  192. package/lib/orchestrator/run-dir.d.ts.map +1 -1
  193. package/lib/orchestrator/run-dir.js +1 -1
  194. package/lib/orchestrator/run-dir.js.map +1 -1
  195. package/lib/orchestrator/run-execution.d.ts +1 -0
  196. package/lib/orchestrator/run-execution.d.ts.map +1 -1
  197. package/lib/orchestrator/run-execution.js +2 -0
  198. package/lib/orchestrator/run-execution.js.map +1 -1
  199. package/lib/orchestrator/suite-compare.d.ts +3 -0
  200. package/lib/orchestrator/suite-compare.d.ts.map +1 -1
  201. package/lib/orchestrator/suite-compare.js +27 -17
  202. package/lib/orchestrator/suite-compare.js.map +1 -1
  203. package/lib/orchestrator/suite-runs.d.ts +3 -0
  204. package/lib/orchestrator/suite-runs.d.ts.map +1 -1
  205. package/lib/orchestrator/suite-runs.js +2 -0
  206. package/lib/orchestrator/suite-runs.js.map +1 -1
  207. package/lib/orchestrator/suite-summary.d.ts +9 -0
  208. package/lib/orchestrator/suite-summary.d.ts.map +1 -1
  209. package/lib/orchestrator/suite-summary.js +14 -4
  210. package/lib/orchestrator/suite-summary.js.map +1 -1
  211. package/package.json +1 -1
  212. package/skills/lux-answerer/SKILL.md +1 -1
  213. package/src/authoring.ts +10 -3
  214. package/src/cli/doctor.ts +17 -0
  215. package/src/cli/harness-plan.ts +117 -0
  216. package/src/cli/init-templates.ts +12 -5
  217. package/src/cli/init.ts +12 -5
  218. package/src/cli/program.ts +60 -107
  219. package/src/cli/run-options.ts +123 -0
  220. package/src/core/case.ts +3 -0
  221. package/src/core/driver.ts +26 -0
  222. package/src/core/harness-catalog.ts +100 -0
  223. package/src/core/harness-catalogs/antigravity.ts +24 -0
  224. package/src/core/harness-catalogs/claude-code.ts +25 -0
  225. package/src/core/harness-catalogs/codex.ts +27 -0
  226. package/src/core/harness-catalogs/copilot.ts +46 -0
  227. package/src/core/harness-catalogs/cursor.ts +13 -0
  228. package/src/core/harness-catalogs/index.ts +22 -0
  229. package/src/core/harness-matrix.ts +298 -0
  230. package/src/core/index.ts +3 -0
  231. package/src/core/model-cli.ts +38 -21
  232. package/src/core/platform-process.ts +4 -4
  233. package/src/core/run.ts +2 -0
  234. package/src/drivers/antigravity/README.md +46 -0
  235. package/src/drivers/antigravity/config.ts +44 -0
  236. package/src/drivers/antigravity/events.ts +235 -0
  237. package/src/drivers/antigravity/index.ts +109 -0
  238. package/src/drivers/claude-code/index.ts +12 -5
  239. package/src/drivers/codex/config.ts +11 -5
  240. package/src/drivers/codex/index.ts +5 -1
  241. package/src/drivers/copilot/README.md +52 -0
  242. package/src/drivers/copilot/config.ts +58 -0
  243. package/src/drivers/copilot/index.ts +292 -0
  244. package/src/drivers/cursor/README.md +9 -6
  245. package/src/drivers/cursor/config.ts +2 -3
  246. package/src/drivers/cursor/index.ts +10 -6
  247. package/src/drivers/cursor/interaction.ts +3 -19
  248. package/src/drivers/{cursor/events.ts → shared/acp-events.ts} +20 -9
  249. package/src/drivers/shared/acp-interaction.ts +27 -0
  250. package/src/drivers/{cursor → shared}/acp-transport.ts +15 -10
  251. package/src/index.ts +44 -3
  252. package/src/orchestrator/comparison-identity.ts +1 -0
  253. package/src/orchestrator/config.ts +8 -0
  254. package/src/orchestrator/doctor.ts +149 -8
  255. package/src/orchestrator/experiment-context.ts +3 -2
  256. package/src/orchestrator/experiment-corpus.ts +20 -2
  257. package/src/orchestrator/experiment-identity.ts +2 -2
  258. package/src/orchestrator/experiment-preflight.ts +27 -0
  259. package/src/orchestrator/experiment.ts +3 -5
  260. package/src/orchestrator/harness-catalog-drift.ts +132 -0
  261. package/src/orchestrator/orchestrator.ts +31 -26
  262. package/src/orchestrator/run-dir.ts +8 -1
  263. package/src/orchestrator/run-execution.ts +3 -0
  264. package/src/orchestrator/suite-compare.ts +29 -19
  265. package/src/orchestrator/suite-runs.ts +3 -1
  266. package/src/orchestrator/suite-summary.ts +19 -4
  267. package/lib/drivers/cursor/acp-transport.d.ts.map +0 -1
  268. package/lib/drivers/cursor/acp-transport.js.map +0 -1
  269. package/lib/drivers/cursor/events.d.ts.map +0 -1
  270. package/lib/drivers/cursor/events.js.map +0 -1
  271. package/skills/lux/SKILL.md +0 -89
  272. package/skills/lux/references/cli.md +0 -128
  273. package/skills/lux/references/eval-authoring.md +0 -266
@@ -6,6 +6,8 @@ import {
6
6
  type AnswererRef,
7
7
  bindSubjectRoot,
8
8
  type DriverRef,
9
+ driverConfigOf,
10
+ driverNameOf,
9
11
  type EvalCase,
10
12
  type GradingAssertionEntry,
11
13
  type GradingReport,
@@ -13,6 +15,7 @@ import {
13
15
  type HarnessModelConfig,
14
16
  type LifecycleHooksPlugin,
15
17
  mergeHarnessModelConfig,
18
+ mergePluginConfig,
16
19
  type Registry,
17
20
  type RunMetadata,
18
21
  type RunObserver,
@@ -142,6 +145,12 @@ export type RunRequest = {
142
145
  subjectRoot?: string | undefined;
143
146
  subjectHash?: string | undefined;
144
147
  profileId?: string | undefined;
148
+ /**
149
+ * Driver bound by a harness permutation. It replaces the project default;
150
+ * a case pinned to another driver is rejected rather than silently rerouted.
151
+ */
152
+ driver?: DriverRef | undefined;
153
+ permutationId?: string | undefined;
145
154
  experimentId?: string | undefined;
146
155
  variantId?: string | undefined;
147
156
  candidateId?: string | undefined;
@@ -200,7 +209,13 @@ export type SuiteObserver = RunObserver & {
200
209
  * `caseId` is the canonical id runs are filed under when the case declares
201
210
  * none — display decorations (a `--loop` suffix) must not fork run history.
202
211
  */
203
- export type SuiteItem = { path: string; id: string; caseId?: string | undefined };
212
+ export type SuiteItem = {
213
+ path: string;
214
+ id: string;
215
+ caseId?: string | undefined;
216
+ driver?: DriverRef | undefined;
217
+ permutationId?: string | undefined;
218
+ };
204
219
 
205
220
  const resolveCaseId = (casePath: string, evalCase: EvalCase, fallback?: string): string => {
206
221
  if (evalCase.id) return evalCase.id;
@@ -211,39 +226,29 @@ const resolveCaseId = (casePath: string, evalCase: EvalCase, fallback?: string):
211
226
  return ext ? base.slice(0, -ext.length) : base;
212
227
  };
213
228
 
214
- const driverNameOf = (ref: DriverRef): string => (typeof ref === "string" ? ref : ref.name);
215
-
216
- const isRecord = (value: unknown): value is Record<string, unknown> =>
217
- Boolean(value) && typeof value === "object" && !Array.isArray(value);
218
-
219
- /** Merge plugin config recursively so nested Codex `config`/`env` overrides stay additive. */
220
- const mergePluginConfig = (base: unknown, local: unknown): unknown => {
221
- if (!isRecord(base) || !isRecord(local)) return local ?? base;
222
- const merged: Record<string, unknown> = { ...base };
223
- for (const [key, value] of Object.entries(local)) {
224
- merged[key] = key in merged ? mergePluginConfig(merged[key], value) : value;
225
- }
226
- return merged;
227
- };
228
-
229
229
  export const resolveDriverReference = (
230
230
  evalCase: EvalCase,
231
231
  fallback: DriverRef | undefined,
232
+ permutation?: DriverRef | undefined,
232
233
  ): DriverRef => {
233
234
  const local = evalCase.driver;
235
+ if (permutation && local && driverNameOf(local) !== driverNameOf(permutation)) {
236
+ throw new Error(
237
+ `case is pinned to driver '${driverNameOf(local)}' but the run selected '${driverNameOf(permutation)}'`,
238
+ );
239
+ }
240
+ const base = permutation ?? fallback;
234
241
  if (!local) {
235
- if (!fallback) throw new Error("case names no driver and no defaultDriver is configured");
236
- return fallback;
242
+ if (!base) throw new Error("case names no driver and no defaultDriver is configured");
243
+ return base;
237
244
  }
238
- if (!fallback || driverNameOf(local) !== driverNameOf(fallback)) return local;
245
+ if (!base || driverNameOf(local) !== driverNameOf(base)) return local;
239
246
 
240
247
  // Naming the same driver opts into project defaults. A case object only
241
248
  // needs to carry the fields it wants to override (for example a timeout).
242
- const baseConfig = typeof fallback === "object" ? fallback.config : undefined;
243
- const localConfig = typeof local === "object" ? local.config : undefined;
244
249
  return {
245
250
  name: driverNameOf(local),
246
- config: mergePluginConfig(baseConfig, localConfig),
251
+ config: mergePluginConfig(driverConfigOf(base), driverConfigOf(local)),
247
252
  };
248
253
  };
249
254
 
@@ -264,9 +269,6 @@ export const resolveAnswererReference = (
264
269
 
265
270
  const answererNameOf = (ref: AnswererRef): string => (typeof ref === "string" ? ref : ref.name);
266
271
 
267
- const driverConfigOf = (ref: DriverRef): unknown =>
268
- typeof ref === "object" ? ref.config : undefined;
269
-
270
272
  const answererConfigOf = (ref: AnswererRef): unknown =>
271
273
  typeof ref === "object" ? ref.config : undefined;
272
274
 
@@ -352,7 +354,7 @@ export class Orchestrator {
352
354
  registry,
353
355
  );
354
356
 
355
- const driverRef = resolveDriverReference(evalCase, this.defaultDriver);
357
+ const driverRef = resolveDriverReference(evalCase, this.defaultDriver, request.driver);
356
358
  const driverName = driverNameOf(driverRef);
357
359
  const answererRef = resolveAnswererReference(
358
360
  evalCase,
@@ -422,6 +424,7 @@ export class Orchestrator {
422
424
  validatedAssertionConfigs,
423
425
  caseId,
424
426
  driverName,
427
+ permutationId: request.permutationId,
425
428
  answererName,
426
429
  answererConfig: answererCfg,
427
430
  driverConfigHash: valueHash(driverCfg),
@@ -643,6 +646,8 @@ export class Orchestrator {
643
646
  subjectRoot: opts.subjectRoot,
644
647
  subjectHash: opts.subjectHash,
645
648
  profileId: opts.profileId,
649
+ driver: item.driver,
650
+ permutationId: item.permutationId,
646
651
  experimentId: opts.experimentId,
647
652
  variantId: opts.variantId,
648
653
  candidateId: opts.candidateId,
@@ -154,6 +154,8 @@ export type OpenRunDirOptions = {
154
154
  runsRoot: string;
155
155
  caseId: string;
156
156
  driverName: string;
157
+ /** Files the run under the permutation instead of the bare driver name. */
158
+ permutationId?: string | undefined;
157
159
  startedAt?: Date | undefined;
158
160
  /** Tap on the event stream, called for every appended event. Must not throw. */
159
161
  onEvent?: ((event: RunEvent) => void) | undefined;
@@ -164,7 +166,12 @@ export type OpenRunDirOptions = {
164
166
  export const openRunDir = async (options: OpenRunDirOptions): Promise<OpenedRunDir> => {
165
167
  const ts = isoTimestampSafe(options.startedAt ?? new Date());
166
168
  const slug = slugifyCaseId(options.caseId);
167
- const basePath = join(options.runsRoot, slug, slugifyCaseId(options.driverName), ts);
169
+ const basePath = join(
170
+ options.runsRoot,
171
+ slug,
172
+ slugifyCaseId(options.permutationId ?? options.driverName),
173
+ ts,
174
+ );
168
175
  await mkdir(dirname(basePath), { recursive: true });
169
176
  // Same case+driver+millisecond must not share a dir — their events.jsonl
170
177
  // streams (opened with flags "a") would interleave silently. A bare mkdir
@@ -69,6 +69,7 @@ export type RunWithPluginsArgs = {
69
69
  validatedAssertionConfigs: readonly unknown[];
70
70
  caseId: string;
71
71
  driverName: string;
72
+ permutationId?: string | undefined;
72
73
  answererName: string;
73
74
  answererConfig: unknown;
74
75
  driverConfigHash: string;
@@ -338,6 +339,7 @@ class RunExecution implements RunLifecycleEffects<RunResult> {
338
339
  runsRoot: resolve(args.request.runsRoot),
339
340
  caseId: args.caseId,
340
341
  driverName: args.driverName,
342
+ permutationId: args.permutationId,
341
343
  startedAt,
342
344
  onEvent: observer?.event,
343
345
  });
@@ -653,6 +655,7 @@ class RunExecution implements RunLifecycleEffects<RunResult> {
653
655
  ...(this.fixturesHash ? { fixturesHash: this.fixturesHash } : {}),
654
656
  ...(request.subjectHash ? { subjectHash: request.subjectHash } : {}),
655
657
  ...(request.profileId ? { profileId: request.profileId } : {}),
658
+ ...(this.args.permutationId ? { permutationId: this.args.permutationId } : {}),
656
659
  ...(request.experimentId ? { experimentId: request.experimentId } : {}),
657
660
  ...(request.variantId ? { variantId: request.variantId } : {}),
658
661
  ...(request.candidateId ? { candidateId: request.candidateId } : {}),
@@ -5,6 +5,7 @@ import {
5
5
  MetricSummarySchema,
6
6
  type SuiteSample,
7
7
  type SuiteSummary,
8
+ suiteGroupKey,
8
9
  summarizeNumbers,
9
10
  } from "./suite-summary.js";
10
11
 
@@ -18,6 +19,7 @@ const ComparedOutcomeSchema = z
18
19
  export const SuiteCaseComparisonSchema = z
19
20
  .object({
20
21
  canonicalCaseId: z.string(),
22
+ permutationId: z.exactOptional(z.string()),
21
23
  before: ComparedOutcomeSchema.nullable(),
22
24
  after: ComparedOutcomeSchema.nullable(),
23
25
  passRateDelta: z.number().nullable(),
@@ -40,6 +42,7 @@ export const SuiteComparisonSchema = z
40
42
  z
41
43
  .object({
42
44
  canonicalCaseId: z.string(),
45
+ permutationId: z.exactOptional(z.string()),
43
46
  repetition: z.number().int().positive(),
44
47
  before: z.string().nullable(),
45
48
  after: z.string().nullable(),
@@ -54,9 +57,10 @@ export type SuiteComparison = z.infer<typeof SuiteComparisonSchema>;
54
57
  const samplesByCase = (summary: SuiteSummary): Map<string, SuiteSample[]> => {
55
58
  const out = new Map<string, SuiteSample[]>();
56
59
  for (const sample of summary.samples) {
57
- const entries = out.get(sample.canonicalCaseId) ?? [];
60
+ const key = suiteGroupKey(sample);
61
+ const entries = out.get(key) ?? [];
58
62
  entries.push(sample);
59
- out.set(sample.canonicalCaseId, entries);
63
+ out.set(key, entries);
60
64
  }
61
65
  return out;
62
66
  };
@@ -95,14 +99,23 @@ export const compareSuiteSummaries = (
95
99
  options: { passRateTolerance?: number } = {},
96
100
  ): SuiteComparison => {
97
101
  const passRateTolerance = options.passRateTolerance ?? 0;
98
- const aCases = new Map(a.cases.map((entry) => [entry.canonicalCaseId, entry]));
99
- const bCases = new Map(b.cases.map((entry) => [entry.canonicalCaseId, entry]));
102
+ const aCases = new Map(a.cases.map((entry) => [suiteGroupKey(entry), entry]));
103
+ const bCases = new Map(b.cases.map((entry) => [suiteGroupKey(entry), entry]));
100
104
  const aSamples = samplesByCase(a);
101
105
  const bSamples = samplesByCase(b);
102
- const ids = new Set([...aCases.keys(), ...bCases.keys()]);
103
- const identityMismatches = [...ids].sort().flatMap((canonicalCaseId) => {
104
- const before = aSamples.get(canonicalCaseId) ?? [];
105
- const after = bSamples.get(canonicalCaseId) ?? [];
106
+ const groups = new Map(
107
+ [...a.cases, ...b.cases].map((entry) => [
108
+ suiteGroupKey(entry),
109
+ {
110
+ canonicalCaseId: entry.canonicalCaseId,
111
+ ...(entry.permutationId ? { permutationId: entry.permutationId } : {}),
112
+ },
113
+ ]),
114
+ );
115
+ const keys = [...groups.keys()].sort();
116
+ const identityMismatches = keys.flatMap((key) => {
117
+ const before = aSamples.get(key) ?? [];
118
+ const after = bSamples.get(key) ?? [];
106
119
  return Array.from({ length: Math.max(before.length, after.length) }, (_, index) => {
107
120
  const beforeHash = before[index]?.identityHash ?? null;
108
121
  const afterHash = after[index]?.identityHash ?? null;
@@ -110,7 +123,7 @@ export const compareSuiteSummaries = (
110
123
  ? []
111
124
  : [
112
125
  {
113
- canonicalCaseId,
126
+ ...groups.get(key),
114
127
  repetition: index + 1,
115
128
  before: beforeHash,
116
129
  after: afterHash,
@@ -118,9 +131,9 @@ export const compareSuiteSummaries = (
118
131
  ];
119
132
  }).flat();
120
133
  });
121
- const cases = [...ids].sort().map((canonicalCaseId) => {
122
- const before = aCases.get(canonicalCaseId);
123
- const after = bCases.get(canonicalCaseId);
134
+ const cases = keys.map((key) => {
135
+ const before = aCases.get(key);
136
+ const after = bCases.get(key);
124
137
  let passRateDelta: number | null = null;
125
138
  if (before && after) {
126
139
  passRateDelta = after.passRate - before.passRate;
@@ -128,16 +141,13 @@ export const compareSuiteSummaries = (
128
141
  passRateDelta = -before.passRate;
129
142
  }
130
143
  return {
131
- canonicalCaseId,
144
+ ...groups.get(key),
132
145
  before: before ? { attempts: before.attempts, passRate: before.passRate } : null,
133
146
  after: after ? { attempts: after.attempts, passRate: after.passRate } : null,
134
147
  passRateDelta,
135
148
  regressed:
136
149
  Boolean(before) && (!after || after.passRate + passRateTolerance < (before?.passRate ?? 0)),
137
- pairedMetricDeltas: pairedMetricDeltas(
138
- aSamples.get(canonicalCaseId) ?? [],
139
- bSamples.get(canonicalCaseId) ?? [],
140
- ),
150
+ pairedMetricDeltas: pairedMetricDeltas(aSamples.get(key) ?? [], bSamples.get(key) ?? []),
141
151
  };
142
152
  });
143
153
  return SuiteComparisonSchema.parse({
@@ -182,13 +192,13 @@ export const formatSuiteComparisonText = (comparison: SuiteComparison): string =
182
192
  if (comparison.identityMismatches.length > 0) {
183
193
  lines.push(` identity mismatches: ${comparison.identityMismatches.length}`);
184
194
  for (const mismatch of comparison.identityMismatches) {
185
- lines.push(` ! ${mismatch.canonicalCaseId} repetition ${mismatch.repetition}`);
195
+ lines.push(` ! ${suiteGroupKey(mismatch)} repetition ${mismatch.repetition}`);
186
196
  }
187
197
  }
188
198
  for (const entry of comparison.cases) {
189
199
  if (!entry.regressed) continue;
190
200
  lines.push(
191
- ` ↓ ${entry.canonicalCaseId}: ${entry.before ? percent(entry.before.passRate) : "—"} → ${entry.after ? percent(entry.after.passRate) : "missing"}`,
201
+ ` ↓ ${suiteGroupKey(entry)}: ${entry.before ? percent(entry.before.passRate) : "—"} → ${entry.after ? percent(entry.after.passRate) : "missing"}`,
192
202
  );
193
203
  }
194
204
  return lines.join("\n");
@@ -10,6 +10,7 @@ const SUITE_FILE = "suite.json";
10
10
  const SuiteItemSchema = z.object({
11
11
  caseId: z.string(),
12
12
  canonicalCaseId: z.string(),
13
+ permutationId: z.exactOptional(z.string()),
13
14
  status: z.enum(["pending", "running", "completed"]),
14
15
  runDir: z.string().nullable(),
15
16
  exitReason: z.union([z.literal("done"), z.string()]).nullable(),
@@ -64,7 +65,7 @@ export type OpenedSuiteRun = {
64
65
  export const openSuiteRun = async (options: {
65
66
  runsRoot: string;
66
67
  concurrency: number;
67
- items: { id: string; caseId?: string | undefined }[];
68
+ items: { id: string; caseId?: string | undefined; permutationId?: string | undefined }[];
68
69
  startedAt?: Date | undefined;
69
70
  profileId?: string | undefined;
70
71
  experimentId?: string | undefined;
@@ -110,6 +111,7 @@ export const openSuiteRun = async (options: {
110
111
  items: options.items.map((item) => ({
111
112
  caseId: item.id,
112
113
  canonicalCaseId: item.caseId ?? item.id,
114
+ ...(item.permutationId ? { permutationId: item.permutationId } : {}),
113
115
  status: "pending",
114
116
  runDir: null,
115
117
  exitReason: null,
@@ -42,14 +42,25 @@ export type OutcomeSummary = z.infer<typeof OutcomeSummarySchema>;
42
42
 
43
43
  const CaseSummarySchema = OutcomeSummarySchema.extend({
44
44
  canonicalCaseId: z.string(),
45
+ permutationId: z.exactOptional(z.string()),
45
46
  metrics: z.record(z.string(), MetricSummarySchema),
46
47
  });
48
+
49
+ /** Repetitions pool per case and harness permutation, never across permutations. */
50
+ export const suiteGroupKey = (entry: {
51
+ canonicalCaseId: string;
52
+ permutationId?: string | undefined;
53
+ }): string =>
54
+ entry.permutationId === undefined
55
+ ? entry.canonicalCaseId
56
+ : `${entry.canonicalCaseId} [${entry.permutationId}]`;
47
57
  export type CaseSummary = z.infer<typeof CaseSummarySchema>;
48
58
 
49
59
  export const SuiteSampleSchema = z.object({
50
60
  index: z.number().int().nonnegative(),
51
61
  caseId: z.string(),
52
62
  canonicalCaseId: z.string(),
63
+ permutationId: z.exactOptional(z.string()),
53
64
  exitReason: z.string().nullable(),
54
65
  passed: z.boolean().nullable(),
55
66
  identityHash: z.string().nullable(),
@@ -308,14 +319,15 @@ export const buildSuiteSummary = (
308
319
 
309
320
  const byCase = new Map<string, typeof entries>();
310
321
  for (const entry of entries) {
311
- const group = byCase.get(entry.item.canonicalCaseId) ?? [];
322
+ const key = suiteGroupKey(entry.item);
323
+ const group = byCase.get(key) ?? [];
312
324
  group.push(entry);
313
- byCase.set(entry.item.canonicalCaseId, group);
325
+ byCase.set(key, group);
314
326
  }
315
327
 
316
328
  const cases = [...byCase.entries()]
317
329
  .sort(([a], [b]) => a.localeCompare(b))
318
- .map(([canonicalCaseId, caseEntries]) => {
330
+ .map(([, caseEntries]) => {
319
331
  const metrics: MetricSamples = new Map();
320
332
  for (const entry of caseEntries) {
321
333
  const result = entry.result?.result;
@@ -323,8 +335,10 @@ export const buildSuiteSummary = (
323
335
  add(metrics, "score", result.grading.caseScore ?? undefined);
324
336
  collectMetadata(metrics, result.metadata);
325
337
  }
338
+ const first = caseEntries[0]?.item;
326
339
  return {
327
- canonicalCaseId,
340
+ canonicalCaseId: first?.canonicalCaseId ?? "",
341
+ ...(first?.permutationId ? { permutationId: first.permutationId } : {}),
328
342
  ...summarizeOutcomes(caseEntries),
329
343
  metrics: summarizeMetrics(metrics),
330
344
  };
@@ -345,6 +359,7 @@ export const buildSuiteSummary = (
345
359
  index,
346
360
  caseId: entry.item.caseId,
347
361
  canonicalCaseId: entry.item.canonicalCaseId,
362
+ ...(entry.item.permutationId ? { permutationId: entry.item.permutationId } : {}),
348
363
  exitReason: entry.result?.exitReason ?? null,
349
364
  passed: entry.result?.casePassed ?? null,
350
365
  identityHash: result ? runComparisonIdentity(result.metadata) : null,
@@ -1 +0,0 @@
1
- {"version":3,"file":"acp-transport.d.ts","sourceRoot":"","sources":["../../../src/drivers/cursor/acp-transport.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAChD,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AACpC,eAAO,MAAM,QAAQ,UAAW,OAAO,KAAG,SAAS,GAAG,SAGvC,CAAC;AAEhB,KAAK,gBAAgB,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,CAAC,OAAO,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAClC,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAEF,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAOpB;IACJ,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAM;IAExB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAE3C,YAAY,OAAO,EAAE,gBAAgB,EAoBpC;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAE7B;IAED,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAiBjF;IAED,KAAK,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI,CAM9B;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAE7B;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAK3B;IAED,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,IAAI;IAmBZ,OAAO,CAAC,IAAI;CAyCb"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"acp-transport.js","sourceRoot":"","sources":["../../../src/drivers/cursor/acp-transport.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/drivers/cursor/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAsB,MAAM,qBAAqB,CAAC;AACxE,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAK9D,qBAAa,YAAY;IACvB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IACtD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAE/C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAElC,YAAY,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAGjD;IAED,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,EAAE,CA6DpC;CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/drivers/cursor/events.ts"],"names":[],"mappings":"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"}
@@ -1,89 +0,0 @@
1
- ---
2
- name: lux
3
- description: Author, validate, run, inspect, compare, and improve coding-agent evaluations with the Lux CLI. Use when creating or reviewing Lux cases, custom assertions, lifecycle fixtures, driver or harness configuration, campaigns, grader annotations, diagnosing eval failures, comparing runs, or running and promoting Lux experiments.
4
- ---
5
-
6
- # Lux
7
-
8
- Use Lux as an eval test runner and evidence system for coding agents. Prefer
9
- small, discriminating cases with deterministic assertions; add an LLM rubric
10
- only for qualities that artifacts and commands cannot establish.
11
-
12
- ## Start here
13
-
14
- 1. Inspect the repository and its existing `lux.config.ts`, cases, fixtures,
15
- prompts, and experiments before adding files.
16
- 2. If Lux is not initialized, run `npm exec -- lux init` for ordinary evals or
17
- `npm exec -- lux init --experiment` for an improvement campaign.
18
- 3. Read [references/eval-authoring.md](references/eval-authoring.md) before
19
- authoring or reviewing a case, assertion plugin, or lifecycle fixture.
20
- 4. Read [references/cli.md](references/cli.md) before running, diagnosing,
21
- comparing, or promoting results.
22
- 5. Run `npm exec -- lux doctor` before model calls. Treat its errors as
23
- authoring problems, not as permission to bypass validation.
24
-
25
- ## Workflow
26
-
27
- ### Author an eval
28
-
29
- - Define the behavior and likely failure mode first.
30
- - Make the prompt realistic and self-contained.
31
- - Give the persona only facts and preferences the simulated user should know.
32
- - Assert observable outcomes, not implementation details.
33
- - Use stable assertion IDs so grading evidence remains intelligible.
34
- - Use the cheapest deterministic assertion that proves each requirement.
35
- - Include a rubric assertion only when semantic judgment is unavoidable, and
36
- write one narrow, falsifiable criterion per assertion.
37
- - Pin the subject driver model explicitly when comparability matters.
38
-
39
- ### Run and diagnose
40
-
41
- ```bash
42
- npm exec -- lux doctor
43
- npm exec -- lux run <case-or-filter> --list
44
- npm exec -- lux run <case-or-filter> --loop 3
45
- npm exec -- lux view <run-or-suite>
46
- ```
47
-
48
- Inspect `case.json`, `run.json`, `events.jsonl`, `grading.json`, and `artifacts/`
49
- before changing the case. Separate subject failure from harness failure:
50
-
51
- - Subject failure: the agent misunderstood, asked poorly, used the wrong tools,
52
- or left incorrect artifacts.
53
- - Harness failure: the prompt was underspecified, the persona lacked a needed
54
- fact, a fixture or driver failed, an assertion measured a proxy, or the
55
- judge criterion was ambiguous.
56
-
57
- Do not weaken a valid assertion merely to make a run pass.
58
-
59
- ### Improve with evidence
60
-
61
- Use repeated runs and held-out splits for noisy agent behavior. For skill,
62
- prompt, or agent-source changes, use `subjectPath()` in cases and an experiment
63
- campaign with immutable candidates. Plan first, run the experiment, inspect the
64
- report, and apply a promoted candidate as a separate action:
65
-
66
- ```bash
67
- npm exec -- lux experiment experiments/example.experiment.ts --plan
68
- npm exec -- lux experiment experiments/example.experiment.ts
69
- npm exec -- lux report <experiment-dir>
70
- npm exec -- lux apply <experiment-dir>
71
- ```
72
-
73
- Never edit a materialized candidate or managed experiment record by hand.
74
-
75
- ## Guardrails
76
-
77
- - Lux eval projects execute project-authored commands and agent-generated work.
78
- Run untrusted evals only in a disposable environment.
79
- - Do not infer success from agent prose. Grade the final artifacts and recorded
80
- behavior.
81
- - Do not use only `run-succeeded` for a case that claims to verify a concrete
82
- result.
83
- - Do not invoke bare `lux`; it displays help. Use the explicit `lux run` verb
84
- and narrow by case, path, or tag before any model call.
85
- - Do not let train examples leak into validation or test splits.
86
- - Do not combine evidence across changed models, harnesses, cases, or subjects;
87
- Lux identity checks exist to prevent that.
88
- - Prefer `--plan`, `doctor`, `view`, and `report` before expensive or mutating
89
- commands.
@@ -1,128 +0,0 @@
1
- # Lux CLI runbook
2
-
3
- Invoke the project-local CLI with `npm exec -- lux ...` unless the repository
4
- uses another package-manager convention.
5
-
6
- Bare `lux` prints command and agent-skill help. Running cases always requires
7
- the explicit `run` verb; do not assume an unfiltered run is harmless.
8
- Use `lux <command> --help` before composing an unfamiliar or automation-facing
9
- invocation; it is the authoritative option list for the installed version.
10
- Use `lux --llms` for the compact command manifest and
11
- `lux <command> --schema --json` for exact argument, option, and output schemas.
12
- All commands support Incur's `--format`, `--filter-output`, and token-pagination
13
- flags; prefer the default TOON output unless strict JSON is required.
14
-
15
- ## Author and preflight
16
-
17
- ```bash
18
- lux init
19
- lux init --experiment
20
- lux skills list
21
- lux skills add --no-global
22
- lux doctor
23
- lux doctor experiments/campaign.experiment.ts --json
24
- lux run --list
25
- lux run --list-tags
26
- ```
27
-
28
- `init` is conservative around existing files. `doctor` validates configuration,
29
- case discovery, driver executables, campaign splits, confidence feasibility,
30
- and projected budgets without model calls.
31
-
32
- ## Run
33
-
34
- ```bash
35
- lux run
36
- lux run retry-flag
37
- lux run cases/retry-flag.ts
38
- lux run --tag smoke
39
- lux run retry --loop 5 --concurrency 2
40
- lux run one-case --interactive
41
- lux run one-case --claude-answerer
42
- lux run one-case --profile small-low --subject-root . --verbose
43
- lux run one-case --skip-judge
44
- ```
45
-
46
- Filters match case IDs and paths. Tags come from `meta.tags`. A run invocation
47
- also creates a suite record, which is the right unit for repeated or multi-case
48
- comparison.
49
-
50
- `--skip-judge` leaves subject execution unchanged but does not call rubric LLM
51
- judges. Deterministic assertions still determine the verdict; judge-only cases
52
- remain ungraded, and persisted grading records identify the skipped rubrics.
53
-
54
- ## Inspect and compare
55
-
56
- ```bash
57
- lux view
58
- lux view <run-or-suite>
59
- lux view --suites --json
60
- lux view --experiments
61
- lux compare <run-or-suite-a> <run-or-suite-b> --pass-rate-tolerance 0.05
62
- ```
63
-
64
- Use `view` before opening raw files. When diagnosing, inspect:
65
-
66
- - `case.json`: frozen authored inputs;
67
- - `run.json`: exit reason, timing, usage, source identity;
68
- - `events.jsonl`: trajectory, tools, and interrupts;
69
- - `grading.json`: assertion evidence;
70
- - `artifacts/`: the subject workspace output.
71
-
72
- `compare` exits nonzero on a gated regression, making it suitable for CI.
73
-
74
- ## Regrade and annotate
75
-
76
- ```bash
77
- lux grade <run>
78
- lux grade <run> --case cases/changed-grader.ts
79
- lux annotate <run> \
80
- --out evals/annotations.json \
81
- --rubric evals/rubrics/case.json \
82
- --label pass
83
- ```
84
-
85
- Regrading preserves subject evidence and changes only grading. Human annotations
86
- support grader-alignment experiments. `annotate` can record overall label or
87
- score, repeatable assertion outcomes, split/tag selection, feedback, annotator,
88
- reviewer, and human/synthetic provenance. Keep assertion IDs aligned with the
89
- rubric and record reviewer context where available.
90
-
91
- ## Experiment lifecycle
92
-
93
- ```bash
94
- lux experiment <campaign> --plan
95
- lux experiment <campaign>
96
- lux experiment <campaign> --resume <experiment-dir>
97
- lux optimize <campaign> --plan
98
- lux optimize <campaign>
99
- lux optimize <campaign> --resume <experiment-dir>
100
- lux view <experiment-dir>
101
- lux report <experiment-dir> --out .lux-runs/reports/decision.md
102
- lux report <experiment-dir> --json
103
- lux apply <experiment-dir>
104
- ```
105
-
106
- `experiment` compares authored variants. `optimize` searches proposed changes.
107
- Both create durable, resumable, integrity-checked records. `report` re-verifies
108
- the ledger and promotion decision. `apply` is deliberately separate and
109
- hash-guards the source it changes.
110
-
111
- Use the exact resume, report, and apply commands printed by Lux. Do not edit
112
- `.lux-runs/.experiments/` manually.
113
-
114
- ## Failure triage
115
-
116
- - Discovery/config error: run `doctor`, verify paths and exported definitions.
117
- - Driver unavailable: verify the selected CLI is installed and the model is
118
- explicitly configured where required.
119
- - Agent exit/error: inspect `events.jsonl` and the driver section of `run.json`.
120
- - Assertion failure: inspect the assertion evidence and final artifact; decide
121
- whether the subject or measurement is wrong.
122
- - Tool evidence mismatch: compare paired call/result IDs and inspect unresolved,
123
- unmatched, malformed, and failed tool outcomes; never infer success from a
124
- call event alone.
125
- - Judge disagreement: narrow the rubric, regrade stored evidence, and collect
126
- human annotations before changing the subject.
127
- - Interrupted experiment: resume the printed experiment directory; do not start
128
- a nominally identical campaign and combine results yourself.