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