@prismatic-io/lux 0.0.1
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/LICENSE +21 -0
- package/lib/answerers/claude-code/index.d.ts +17 -0
- package/lib/answerers/claude-code/index.d.ts.map +1 -0
- package/lib/answerers/claude-code/index.js +280 -0
- package/lib/answerers/claude-code/index.js.map +1 -0
- package/lib/answerers/persona/index.d.ts +40 -0
- package/lib/answerers/persona/index.d.ts.map +1 -0
- package/lib/answerers/persona/index.js +265 -0
- package/lib/answerers/persona/index.js.map +1 -0
- package/lib/answerers/scripted/index.d.ts +8 -0
- package/lib/answerers/scripted/index.d.ts.map +1 -0
- package/lib/answerers/scripted/index.js +163 -0
- package/lib/answerers/scripted/index.js.map +1 -0
- package/lib/answerers/shared.d.ts +13 -0
- package/lib/answerers/shared.d.ts.map +1 -0
- package/lib/answerers/shared.js +17 -0
- package/lib/answerers/shared.js.map +1 -0
- package/lib/answerers/terminal/index.d.ts +9 -0
- package/lib/answerers/terminal/index.d.ts.map +1 -0
- package/lib/answerers/terminal/index.js +97 -0
- package/lib/answerers/terminal/index.js.map +1 -0
- package/lib/assertions/core/command-exits-zero.d.ts +21 -0
- package/lib/assertions/core/command-exits-zero.d.ts.map +1 -0
- package/lib/assertions/core/command-exits-zero.js +87 -0
- package/lib/assertions/core/command-exits-zero.js.map +1 -0
- package/lib/assertions/core/event-checks.d.ts +57 -0
- package/lib/assertions/core/event-checks.d.ts.map +1 -0
- package/lib/assertions/core/event-checks.js +123 -0
- package/lib/assertions/core/event-checks.js.map +1 -0
- package/lib/assertions/core/file-checks.d.ts +103 -0
- package/lib/assertions/core/file-checks.d.ts.map +1 -0
- package/lib/assertions/core/file-checks.js +288 -0
- package/lib/assertions/core/file-checks.js.map +1 -0
- package/lib/assertions/core/helpers.d.ts +66 -0
- package/lib/assertions/core/helpers.d.ts.map +1 -0
- package/lib/assertions/core/helpers.js +170 -0
- package/lib/assertions/core/helpers.js.map +1 -0
- package/lib/assertions/core/index.d.ts +15 -0
- package/lib/assertions/core/index.d.ts.map +1 -0
- package/lib/assertions/core/index.js +56 -0
- package/lib/assertions/core/index.js.map +1 -0
- package/lib/assertions/core/json-pointer-equals.d.ts +19 -0
- package/lib/assertions/core/json-pointer-equals.d.ts.map +1 -0
- package/lib/assertions/core/json-pointer-equals.js +71 -0
- package/lib/assertions/core/json-pointer-equals.js.map +1 -0
- package/lib/assertions/core/output-checks.d.ts +46 -0
- package/lib/assertions/core/output-checks.d.ts.map +1 -0
- package/lib/assertions/core/output-checks.js +121 -0
- package/lib/assertions/core/output-checks.js.map +1 -0
- package/lib/assertions/core/predicate.d.ts +14 -0
- package/lib/assertions/core/predicate.d.ts.map +1 -0
- package/lib/assertions/core/predicate.js +55 -0
- package/lib/assertions/core/predicate.js.map +1 -0
- package/lib/assertions/core/resource-checks.d.ts +71 -0
- package/lib/assertions/core/resource-checks.d.ts.map +1 -0
- package/lib/assertions/core/resource-checks.js +159 -0
- package/lib/assertions/core/resource-checks.js.map +1 -0
- package/lib/assertions/core/safe-regex.d.ts +23 -0
- package/lib/assertions/core/safe-regex.d.ts.map +1 -0
- package/lib/assertions/core/safe-regex.js +102 -0
- package/lib/assertions/core/safe-regex.js.map +1 -0
- package/lib/assertions/core/tool-called-with.d.ts +21 -0
- package/lib/assertions/core/tool-called-with.d.ts.map +1 -0
- package/lib/assertions/core/tool-called-with.js +69 -0
- package/lib/assertions/core/tool-called-with.js.map +1 -0
- package/lib/assertions/core/tool-calls.d.ts +22 -0
- package/lib/assertions/core/tool-calls.d.ts.map +1 -0
- package/lib/assertions/core/tool-calls.js +17 -0
- package/lib/assertions/core/tool-calls.js.map +1 -0
- package/lib/assertions/core/tool-invocation.d.ts +36 -0
- package/lib/assertions/core/tool-invocation.d.ts.map +1 -0
- package/lib/assertions/core/tool-invocation.js +170 -0
- package/lib/assertions/core/tool-invocation.js.map +1 -0
- package/lib/assertions/core/tool-result-checks.d.ts +59 -0
- package/lib/assertions/core/tool-result-checks.d.ts.map +1 -0
- package/lib/assertions/core/tool-result-checks.js +193 -0
- package/lib/assertions/core/tool-result-checks.js.map +1 -0
- package/lib/assertions/mcp/discovery-checks.d.ts +36 -0
- package/lib/assertions/mcp/discovery-checks.d.ts.map +1 -0
- package/lib/assertions/mcp/discovery-checks.js +122 -0
- package/lib/assertions/mcp/discovery-checks.js.map +1 -0
- package/lib/assertions/mcp/index.d.ts +10 -0
- package/lib/assertions/mcp/index.d.ts.map +1 -0
- package/lib/assertions/mcp/index.js +25 -0
- package/lib/assertions/mcp/index.js.map +1 -0
- package/lib/assertions/rubric/index.d.ts +104 -0
- package/lib/assertions/rubric/index.d.ts.map +1 -0
- package/lib/assertions/rubric/index.js +191 -0
- package/lib/assertions/rubric/index.js.map +1 -0
- package/lib/assertions/rubric/internal.d.ts +14 -0
- package/lib/assertions/rubric/internal.d.ts.map +1 -0
- package/lib/assertions/rubric/internal.js +335 -0
- package/lib/assertions/rubric/internal.js.map +1 -0
- package/lib/authoring.d.ts +3 -0
- package/lib/authoring.d.ts.map +1 -0
- package/lib/authoring.js +3 -0
- package/lib/authoring.js.map +1 -0
- package/lib/cli/bin.d.ts +3 -0
- package/lib/cli/bin.d.ts.map +1 -0
- package/lib/cli/bin.js +15 -0
- package/lib/cli/bin.js.map +1 -0
- package/lib/cli/command-runtime.d.ts +5 -0
- package/lib/cli/command-runtime.d.ts.map +1 -0
- package/lib/cli/command-runtime.js +30 -0
- package/lib/cli/command-runtime.js.map +1 -0
- package/lib/cli/init.d.ts +21 -0
- package/lib/cli/init.d.ts.map +1 -0
- package/lib/cli/init.js +340 -0
- package/lib/cli/init.js.map +1 -0
- package/lib/cli/program.d.ts +22 -0
- package/lib/cli/program.d.ts.map +1 -0
- package/lib/cli/program.js +757 -0
- package/lib/cli/program.js.map +1 -0
- package/lib/cli/render/format.d.ts +14 -0
- package/lib/cli/render/format.d.ts.map +1 -0
- package/lib/cli/render/format.js +71 -0
- package/lib/cli/render/format.js.map +1 -0
- package/lib/cli/render/reporter.d.ts +73 -0
- package/lib/cli/render/reporter.d.ts.map +1 -0
- package/lib/cli/render/reporter.js +519 -0
- package/lib/cli/render/reporter.js.map +1 -0
- package/lib/cli/render/tty.d.ts +77 -0
- package/lib/cli/render/tty.d.ts.map +1 -0
- package/lib/cli/render/tty.js +283 -0
- package/lib/cli/render/tty.js.map +1 -0
- package/lib/cli/run-options.d.ts +27 -0
- package/lib/cli/run-options.d.ts.map +1 -0
- package/lib/cli/run-options.js +58 -0
- package/lib/cli/run-options.js.map +1 -0
- package/lib/cli/skills.d.ts +38 -0
- package/lib/cli/skills.d.ts.map +1 -0
- package/lib/cli/skills.js +84 -0
- package/lib/cli/skills.js.map +1 -0
- package/lib/core/annotation.d.ts +56 -0
- package/lib/core/annotation.d.ts.map +1 -0
- package/lib/core/annotation.js +92 -0
- package/lib/core/annotation.js.map +1 -0
- package/lib/core/answerer.d.ts +68 -0
- package/lib/core/answerer.d.ts.map +1 -0
- package/lib/core/answerer.js +17 -0
- package/lib/core/answerer.js.map +1 -0
- package/lib/core/artifact-evidence.d.ts +50 -0
- package/lib/core/artifact-evidence.d.ts.map +1 -0
- package/lib/core/artifact-evidence.js +185 -0
- package/lib/core/artifact-evidence.js.map +1 -0
- package/lib/core/artifact-snapshot.d.ts +37 -0
- package/lib/core/artifact-snapshot.d.ts.map +1 -0
- package/lib/core/artifact-snapshot.js +339 -0
- package/lib/core/artifact-snapshot.js.map +1 -0
- package/lib/core/assertion.d.ts +129 -0
- package/lib/core/assertion.d.ts.map +1 -0
- package/lib/core/assertion.js +75 -0
- package/lib/core/assertion.js.map +1 -0
- package/lib/core/case.d.ts +79 -0
- package/lib/core/case.d.ts.map +1 -0
- package/lib/core/case.js +90 -0
- package/lib/core/case.js.map +1 -0
- package/lib/core/conversation-turn.d.ts +23 -0
- package/lib/core/conversation-turn.d.ts.map +1 -0
- package/lib/core/conversation-turn.js +31 -0
- package/lib/core/conversation-turn.js.map +1 -0
- package/lib/core/driver.d.ts +64 -0
- package/lib/core/driver.d.ts.map +1 -0
- package/lib/core/driver.js +18 -0
- package/lib/core/driver.js.map +1 -0
- package/lib/core/emitter.d.ts +20 -0
- package/lib/core/emitter.d.ts.map +1 -0
- package/lib/core/emitter.js +34 -0
- package/lib/core/emitter.js.map +1 -0
- package/lib/core/events.d.ts +202 -0
- package/lib/core/events.d.ts.map +1 -0
- package/lib/core/events.js +107 -0
- package/lib/core/events.js.map +1 -0
- package/lib/core/exec.d.ts +82 -0
- package/lib/core/exec.d.ts.map +1 -0
- package/lib/core/exec.js +168 -0
- package/lib/core/exec.js.map +1 -0
- package/lib/core/experiment.d.ts +285 -0
- package/lib/core/experiment.d.ts.map +1 -0
- package/lib/core/experiment.js +389 -0
- package/lib/core/experiment.js.map +1 -0
- package/lib/core/glob.d.ts +3 -0
- package/lib/core/glob.d.ts.map +1 -0
- package/lib/core/glob.js +32 -0
- package/lib/core/glob.js.map +1 -0
- package/lib/core/hash.d.ts +8 -0
- package/lib/core/hash.d.ts.map +1 -0
- package/lib/core/hash.js +214 -0
- package/lib/core/hash.js.map +1 -0
- package/lib/core/index.d.ts +29 -0
- package/lib/core/index.d.ts.map +1 -0
- package/lib/core/index.js +29 -0
- package/lib/core/index.js.map +1 -0
- package/lib/core/lifecycle-fixtures.d.ts +20 -0
- package/lib/core/lifecycle-fixtures.d.ts.map +1 -0
- package/lib/core/lifecycle-fixtures.js +109 -0
- package/lib/core/lifecycle-fixtures.js.map +1 -0
- package/lib/core/lifecycle-hooks.d.ts +52 -0
- package/lib/core/lifecycle-hooks.d.ts.map +1 -0
- package/lib/core/lifecycle-hooks.js +42 -0
- package/lib/core/lifecycle-hooks.js.map +1 -0
- package/lib/core/mcp-events.d.ts +44 -0
- package/lib/core/mcp-events.d.ts.map +1 -0
- package/lib/core/mcp-events.js +23 -0
- package/lib/core/mcp-events.js.map +1 -0
- package/lib/core/model-cli.d.ts +57 -0
- package/lib/core/model-cli.d.ts.map +1 -0
- package/lib/core/model-cli.js +237 -0
- package/lib/core/model-cli.js.map +1 -0
- package/lib/core/observer.d.ts +31 -0
- package/lib/core/observer.d.ts.map +1 -0
- package/lib/core/observer.js +25 -0
- package/lib/core/observer.js.map +1 -0
- package/lib/core/platform-process.d.ts +33 -0
- package/lib/core/platform-process.d.ts.map +1 -0
- package/lib/core/platform-process.js +214 -0
- package/lib/core/platform-process.js.map +1 -0
- package/lib/core/registry.d.ts +22 -0
- package/lib/core/registry.d.ts.map +1 -0
- package/lib/core/registry.js +45 -0
- package/lib/core/registry.js.map +1 -0
- package/lib/core/rubric.d.ts +18 -0
- package/lib/core/rubric.d.ts.map +1 -0
- package/lib/core/rubric.js +49 -0
- package/lib/core/rubric.js.map +1 -0
- package/lib/core/run.d.ts +419 -0
- package/lib/core/run.d.ts.map +1 -0
- package/lib/core/run.js +126 -0
- package/lib/core/run.js.map +1 -0
- package/lib/core/statistics.d.ts +39 -0
- package/lib/core/statistics.d.ts.map +1 -0
- package/lib/core/statistics.js +163 -0
- package/lib/core/statistics.js.map +1 -0
- package/lib/core/subject.d.ts +4 -0
- package/lib/core/subject.d.ts.map +1 -0
- package/lib/core/subject.js +46 -0
- package/lib/core/subject.js.map +1 -0
- package/lib/core/tool-events.d.ts +69 -0
- package/lib/core/tool-events.d.ts.map +1 -0
- package/lib/core/tool-events.js +242 -0
- package/lib/core/tool-events.js.map +1 -0
- package/lib/core/usage.d.ts +78 -0
- package/lib/core/usage.d.ts.map +1 -0
- package/lib/core/usage.js +104 -0
- package/lib/core/usage.js.map +1 -0
- package/lib/core/wire.d.ts +83 -0
- package/lib/core/wire.d.ts.map +1 -0
- package/lib/core/wire.js +101 -0
- package/lib/core/wire.js.map +1 -0
- package/lib/core/zod.d.ts +10 -0
- package/lib/core/zod.d.ts.map +1 -0
- package/lib/core/zod.js +18 -0
- package/lib/core/zod.js.map +1 -0
- package/lib/drivers/claude-code/index.d.ts +55 -0
- package/lib/drivers/claude-code/index.d.ts.map +1 -0
- package/lib/drivers/claude-code/index.js +779 -0
- package/lib/drivers/claude-code/index.js.map +1 -0
- package/lib/drivers/claude-code/parse-events.d.ts +46 -0
- package/lib/drivers/claude-code/parse-events.d.ts.map +1 -0
- package/lib/drivers/claude-code/parse-events.js +387 -0
- package/lib/drivers/claude-code/parse-events.js.map +1 -0
- package/lib/drivers/codex/app-events.d.ts +16 -0
- package/lib/drivers/codex/app-events.d.ts.map +1 -0
- package/lib/drivers/codex/app-events.js +184 -0
- package/lib/drivers/codex/app-events.js.map +1 -0
- package/lib/drivers/codex/config.d.ts +55 -0
- package/lib/drivers/codex/config.d.ts.map +1 -0
- package/lib/drivers/codex/config.js +125 -0
- package/lib/drivers/codex/config.js.map +1 -0
- package/lib/drivers/codex/index.d.ts +8 -0
- package/lib/drivers/codex/index.d.ts.map +1 -0
- package/lib/drivers/codex/index.js +904 -0
- package/lib/drivers/codex/index.js.map +1 -0
- package/lib/drivers/mcp/index.d.ts +52 -0
- package/lib/drivers/mcp/index.d.ts.map +1 -0
- package/lib/drivers/mcp/index.js +282 -0
- package/lib/drivers/mcp/index.js.map +1 -0
- package/lib/drivers/mcp/transport.d.ts +50 -0
- package/lib/drivers/mcp/transport.d.ts.map +1 -0
- package/lib/drivers/mcp/transport.js +190 -0
- package/lib/drivers/mcp/transport.js.map +1 -0
- package/lib/drivers/shared/artifacts.d.ts +4 -0
- package/lib/drivers/shared/artifacts.d.ts.map +1 -0
- package/lib/drivers/shared/artifacts.js +81 -0
- package/lib/drivers/shared/artifacts.js.map +1 -0
- package/lib/drivers/shared/secure-copy.d.ts +2 -0
- package/lib/drivers/shared/secure-copy.d.ts.map +1 -0
- package/lib/drivers/shared/secure-copy.js +35 -0
- package/lib/drivers/shared/secure-copy.js.map +1 -0
- package/lib/drivers/subprocess/index.d.ts +24 -0
- package/lib/drivers/subprocess/index.d.ts.map +1 -0
- package/lib/drivers/subprocess/index.js +451 -0
- package/lib/drivers/subprocess/index.js.map +1 -0
- package/lib/index.d.ts +40 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +48 -0
- package/lib/index.js.map +1 -0
- package/lib/optimization/reflective.d.ts +27 -0
- package/lib/optimization/reflective.d.ts.map +1 -0
- package/lib/optimization/reflective.js +257 -0
- package/lib/optimization/reflective.js.map +1 -0
- package/lib/orchestrator/annotation-loader.d.ts +65 -0
- package/lib/orchestrator/annotation-loader.d.ts.map +1 -0
- package/lib/orchestrator/annotation-loader.js +73 -0
- package/lib/orchestrator/annotation-loader.js.map +1 -0
- package/lib/orchestrator/annotation-store.d.ts +3 -0
- package/lib/orchestrator/annotation-store.d.ts.map +1 -0
- package/lib/orchestrator/annotation-store.js +100 -0
- package/lib/orchestrator/annotation-store.js.map +1 -0
- package/lib/orchestrator/authored-dependencies.d.ts +3 -0
- package/lib/orchestrator/authored-dependencies.d.ts.map +1 -0
- package/lib/orchestrator/authored-dependencies.js +146 -0
- package/lib/orchestrator/authored-dependencies.js.map +1 -0
- package/lib/orchestrator/campaign-lifecycle.d.ts +105 -0
- package/lib/orchestrator/campaign-lifecycle.d.ts.map +1 -0
- package/lib/orchestrator/campaign-lifecycle.js +141 -0
- package/lib/orchestrator/campaign-lifecycle.js.map +1 -0
- package/lib/orchestrator/candidate-integrity.d.ts +4 -0
- package/lib/orchestrator/candidate-integrity.d.ts.map +1 -0
- package/lib/orchestrator/candidate-integrity.js +14 -0
- package/lib/orchestrator/candidate-integrity.js.map +1 -0
- package/lib/orchestrator/candidates.d.ts +13 -0
- package/lib/orchestrator/candidates.d.ts.map +1 -0
- package/lib/orchestrator/candidates.js +577 -0
- package/lib/orchestrator/candidates.js.map +1 -0
- package/lib/orchestrator/compare.d.ts +80 -0
- package/lib/orchestrator/compare.d.ts.map +1 -0
- package/lib/orchestrator/compare.js +270 -0
- package/lib/orchestrator/compare.js.map +1 -0
- package/lib/orchestrator/comparison-identity.d.ts +10 -0
- package/lib/orchestrator/comparison-identity.d.ts.map +1 -0
- package/lib/orchestrator/comparison-identity.js +39 -0
- package/lib/orchestrator/comparison-identity.js.map +1 -0
- package/lib/orchestrator/config.d.ts +121 -0
- package/lib/orchestrator/config.d.ts.map +1 -0
- package/lib/orchestrator/config.js +176 -0
- package/lib/orchestrator/config.js.map +1 -0
- package/lib/orchestrator/content-bound-json.d.ts +5 -0
- package/lib/orchestrator/content-bound-json.d.ts.map +1 -0
- package/lib/orchestrator/content-bound-json.js +59 -0
- package/lib/orchestrator/content-bound-json.js.map +1 -0
- package/lib/orchestrator/discover.d.ts +45 -0
- package/lib/orchestrator/discover.d.ts.map +1 -0
- package/lib/orchestrator/discover.js +98 -0
- package/lib/orchestrator/discover.js.map +1 -0
- package/lib/orchestrator/doctor.d.ts +141 -0
- package/lib/orchestrator/doctor.d.ts.map +1 -0
- package/lib/orchestrator/doctor.js +525 -0
- package/lib/orchestrator/doctor.js.map +1 -0
- package/lib/orchestrator/driver-session.d.ts +177 -0
- package/lib/orchestrator/driver-session.d.ts.map +1 -0
- package/lib/orchestrator/driver-session.js +396 -0
- package/lib/orchestrator/driver-session.js.map +1 -0
- package/lib/orchestrator/evaluator-identity.d.ts +7 -0
- package/lib/orchestrator/evaluator-identity.d.ts.map +1 -0
- package/lib/orchestrator/evaluator-identity.js +42 -0
- package/lib/orchestrator/evaluator-identity.js.map +1 -0
- package/lib/orchestrator/experiment-budget.d.ts +11 -0
- package/lib/orchestrator/experiment-budget.d.ts.map +1 -0
- package/lib/orchestrator/experiment-budget.js +51 -0
- package/lib/orchestrator/experiment-budget.js.map +1 -0
- package/lib/orchestrator/experiment-context.d.ts +43 -0
- package/lib/orchestrator/experiment-context.d.ts.map +1 -0
- package/lib/orchestrator/experiment-context.js +9 -0
- package/lib/orchestrator/experiment-context.js.map +1 -0
- package/lib/orchestrator/experiment-contracts.d.ts +290 -0
- package/lib/orchestrator/experiment-contracts.d.ts.map +1 -0
- package/lib/orchestrator/experiment-contracts.js +38 -0
- package/lib/orchestrator/experiment-contracts.js.map +1 -0
- package/lib/orchestrator/experiment-corpus.d.ts +21 -0
- package/lib/orchestrator/experiment-corpus.d.ts.map +1 -0
- package/lib/orchestrator/experiment-corpus.js +276 -0
- package/lib/orchestrator/experiment-corpus.js.map +1 -0
- package/lib/orchestrator/experiment-evaluation.d.ts +44 -0
- package/lib/orchestrator/experiment-evaluation.d.ts.map +1 -0
- package/lib/orchestrator/experiment-evaluation.js +542 -0
- package/lib/orchestrator/experiment-evaluation.js.map +1 -0
- package/lib/orchestrator/experiment-finish.d.ts +6 -0
- package/lib/orchestrator/experiment-finish.d.ts.map +1 -0
- package/lib/orchestrator/experiment-finish.js +19 -0
- package/lib/orchestrator/experiment-finish.js.map +1 -0
- package/lib/orchestrator/experiment-identity.d.ts +6 -0
- package/lib/orchestrator/experiment-identity.d.ts.map +1 -0
- package/lib/orchestrator/experiment-identity.js +257 -0
- package/lib/orchestrator/experiment-identity.js.map +1 -0
- package/lib/orchestrator/experiment-loader.d.ts +175 -0
- package/lib/orchestrator/experiment-loader.d.ts.map +1 -0
- package/lib/orchestrator/experiment-loader.js +77 -0
- package/lib/orchestrator/experiment-loader.js.map +1 -0
- package/lib/orchestrator/experiment-report.d.ts +450 -0
- package/lib/orchestrator/experiment-report.d.ts.map +1 -0
- package/lib/orchestrator/experiment-report.js +570 -0
- package/lib/orchestrator/experiment-report.js.map +1 -0
- package/lib/orchestrator/experiment-runs.d.ts +379 -0
- package/lib/orchestrator/experiment-runs.d.ts.map +1 -0
- package/lib/orchestrator/experiment-runs.js +796 -0
- package/lib/orchestrator/experiment-runs.js.map +1 -0
- package/lib/orchestrator/experiment-runtime-identity.d.ts +41 -0
- package/lib/orchestrator/experiment-runtime-identity.d.ts.map +1 -0
- package/lib/orchestrator/experiment-runtime-identity.js +411 -0
- package/lib/orchestrator/experiment-runtime-identity.js.map +1 -0
- package/lib/orchestrator/experiment-selection.d.ts +25 -0
- package/lib/orchestrator/experiment-selection.d.ts.map +1 -0
- package/lib/orchestrator/experiment-selection.js +286 -0
- package/lib/orchestrator/experiment-selection.js.map +1 -0
- package/lib/orchestrator/experiment.d.ts +11 -0
- package/lib/orchestrator/experiment.d.ts.map +1 -0
- package/lib/orchestrator/experiment.js +639 -0
- package/lib/orchestrator/experiment.js.map +1 -0
- package/lib/orchestrator/fixture-identity.d.ts +7 -0
- package/lib/orchestrator/fixture-identity.d.ts.map +1 -0
- package/lib/orchestrator/fixture-identity.js +55 -0
- package/lib/orchestrator/fixture-identity.js.map +1 -0
- package/lib/orchestrator/fs-read.d.ts +19 -0
- package/lib/orchestrator/fs-read.d.ts.map +1 -0
- package/lib/orchestrator/fs-read.js +113 -0
- package/lib/orchestrator/fs-read.js.map +1 -0
- package/lib/orchestrator/grader-experiment.d.ts +190 -0
- package/lib/orchestrator/grader-experiment.d.ts.map +1 -0
- package/lib/orchestrator/grader-experiment.js +579 -0
- package/lib/orchestrator/grader-experiment.js.map +1 -0
- package/lib/orchestrator/grading.d.ts +31 -0
- package/lib/orchestrator/grading.d.ts.map +1 -0
- package/lib/orchestrator/grading.js +186 -0
- package/lib/orchestrator/grading.js.map +1 -0
- package/lib/orchestrator/index.d.ts +22 -0
- package/lib/orchestrator/index.d.ts.map +1 -0
- package/lib/orchestrator/index.js +30 -0
- package/lib/orchestrator/index.js.map +1 -0
- package/lib/orchestrator/lifecycle-hook-execution.d.ts +4 -0
- package/lib/orchestrator/lifecycle-hook-execution.d.ts.map +1 -0
- package/lib/orchestrator/lifecycle-hook-execution.js +67 -0
- package/lib/orchestrator/lifecycle-hook-execution.js.map +1 -0
- package/lib/orchestrator/list-runs.d.ts +33 -0
- package/lib/orchestrator/list-runs.d.ts.map +1 -0
- package/lib/orchestrator/list-runs.js +308 -0
- package/lib/orchestrator/list-runs.js.map +1 -0
- package/lib/orchestrator/loader.d.ts +3 -0
- package/lib/orchestrator/loader.d.ts.map +1 -0
- package/lib/orchestrator/loader.js +17 -0
- package/lib/orchestrator/loader.js.map +1 -0
- package/lib/orchestrator/optimization-lifecycle.d.ts +12 -0
- package/lib/orchestrator/optimization-lifecycle.d.ts.map +1 -0
- package/lib/orchestrator/optimization-lifecycle.js +92 -0
- package/lib/orchestrator/optimization-lifecycle.js.map +1 -0
- package/lib/orchestrator/orchestrator.d.ts +144 -0
- package/lib/orchestrator/orchestrator.d.ts.map +1 -0
- package/lib/orchestrator/orchestrator.js +632 -0
- package/lib/orchestrator/orchestrator.js.map +1 -0
- package/lib/orchestrator/owned-lock.d.ts +17 -0
- package/lib/orchestrator/owned-lock.d.ts.map +1 -0
- package/lib/orchestrator/owned-lock.js +149 -0
- package/lib/orchestrator/owned-lock.js.map +1 -0
- package/lib/orchestrator/package-version.d.ts +2 -0
- package/lib/orchestrator/package-version.d.ts.map +1 -0
- package/lib/orchestrator/package-version.js +4 -0
- package/lib/orchestrator/package-version.js.map +1 -0
- package/lib/orchestrator/provenance.d.ts +5 -0
- package/lib/orchestrator/provenance.d.ts.map +1 -0
- package/lib/orchestrator/provenance.js +137 -0
- package/lib/orchestrator/provenance.js.map +1 -0
- package/lib/orchestrator/regrade.d.ts +80 -0
- package/lib/orchestrator/regrade.d.ts.map +1 -0
- package/lib/orchestrator/regrade.js +433 -0
- package/lib/orchestrator/regrade.js.map +1 -0
- package/lib/orchestrator/rubric-loader.d.ts +7 -0
- package/lib/orchestrator/rubric-loader.d.ts.map +1 -0
- package/lib/orchestrator/rubric-loader.js +65 -0
- package/lib/orchestrator/rubric-loader.js.map +1 -0
- package/lib/orchestrator/run-dir.d.ts +40 -0
- package/lib/orchestrator/run-dir.d.ts.map +1 -0
- package/lib/orchestrator/run-dir.js +161 -0
- package/lib/orchestrator/run-dir.js.map +1 -0
- package/lib/orchestrator/run-execution.d.ts +30 -0
- package/lib/orchestrator/run-execution.d.ts.map +1 -0
- package/lib/orchestrator/run-execution.js +531 -0
- package/lib/orchestrator/run-execution.js.map +1 -0
- package/lib/orchestrator/run-lifecycle.d.ts +115 -0
- package/lib/orchestrator/run-lifecycle.d.ts.map +1 -0
- package/lib/orchestrator/run-lifecycle.js +136 -0
- package/lib/orchestrator/run-lifecycle.js.map +1 -0
- package/lib/orchestrator/suite-compare.d.ts +76 -0
- package/lib/orchestrator/suite-compare.d.ts.map +1 -0
- package/lib/orchestrator/suite-compare.js +159 -0
- package/lib/orchestrator/suite-compare.js.map +1 -0
- package/lib/orchestrator/suite-lifecycle.d.ts +157 -0
- package/lib/orchestrator/suite-lifecycle.d.ts.map +1 -0
- package/lib/orchestrator/suite-lifecycle.js +253 -0
- package/lib/orchestrator/suite-lifecycle.js.map +1 -0
- package/lib/orchestrator/suite-runs.d.ts +91 -0
- package/lib/orchestrator/suite-runs.d.ts.map +1 -0
- package/lib/orchestrator/suite-runs.js +157 -0
- package/lib/orchestrator/suite-runs.js.map +1 -0
- package/lib/orchestrator/suite-summary.d.ts +109 -0
- package/lib/orchestrator/suite-summary.d.ts.map +1 -0
- package/lib/orchestrator/suite-summary.js +213 -0
- package/lib/orchestrator/suite-summary.js.map +1 -0
- package/lib/orchestrator/trace-limits.d.ts +20 -0
- package/lib/orchestrator/trace-limits.d.ts.map +1 -0
- package/lib/orchestrator/trace-limits.js +28 -0
- package/lib/orchestrator/trace-limits.js.map +1 -0
- package/lib/orchestrator/validate-plugin-config.d.ts +10 -0
- package/lib/orchestrator/validate-plugin-config.d.ts.map +1 -0
- package/lib/orchestrator/validate-plugin-config.js +26 -0
- package/lib/orchestrator/validate-plugin-config.js.map +1 -0
- package/package.json +84 -0
- package/skills/lux/SKILL.md +85 -0
- package/skills/lux/references/cli.md +102 -0
- package/skills/lux/references/eval-authoring.md +105 -0
- package/skills/lux-answerer/SKILL.md +169 -0
- package/src/answerers/claude-code/index.ts +342 -0
- package/src/answerers/persona/index.ts +327 -0
- package/src/answerers/scripted/index.ts +186 -0
- package/src/answerers/shared.ts +23 -0
- package/src/answerers/terminal/index.ts +117 -0
- package/src/assertions/core/command-exits-zero.ts +94 -0
- package/src/assertions/core/event-checks.ts +138 -0
- package/src/assertions/core/file-checks.ts +336 -0
- package/src/assertions/core/helpers.ts +203 -0
- package/src/assertions/core/index.ts +80 -0
- package/src/assertions/core/json-pointer-equals.ts +84 -0
- package/src/assertions/core/output-checks.ts +134 -0
- package/src/assertions/core/predicate.ts +67 -0
- package/src/assertions/core/resource-checks.ts +180 -0
- package/src/assertions/core/safe-regex.ts +196 -0
- package/src/assertions/core/tool-called-with.ts +68 -0
- package/src/assertions/core/tool-calls.ts +28 -0
- package/src/assertions/core/tool-invocation.ts +198 -0
- package/src/assertions/core/tool-result-checks.ts +211 -0
- package/src/assertions/mcp/discovery-checks.ts +139 -0
- package/src/assertions/mcp/index.ts +37 -0
- package/src/assertions/rubric/index.ts +258 -0
- package/src/assertions/rubric/internal.ts +367 -0
- package/src/authoring.ts +2 -0
- package/src/cli/bin.ts +14 -0
- package/src/cli/command-runtime.ts +34 -0
- package/src/cli/init.ts +410 -0
- package/src/cli/program.ts +992 -0
- package/src/cli/render/format.ts +69 -0
- package/src/cli/render/reporter.ts +643 -0
- package/src/cli/render/tty.ts +314 -0
- package/src/cli/run-options.ts +82 -0
- package/src/cli/skills.ts +129 -0
- package/src/core/annotation.ts +104 -0
- package/src/core/answerer.ts +75 -0
- package/src/core/artifact-evidence.ts +249 -0
- package/src/core/artifact-snapshot.ts +429 -0
- package/src/core/assertion.ts +156 -0
- package/src/core/case.ts +103 -0
- package/src/core/conversation-turn.ts +47 -0
- package/src/core/driver.ts +75 -0
- package/src/core/emitter.ts +38 -0
- package/src/core/events.ts +135 -0
- package/src/core/exec.ts +263 -0
- package/src/core/experiment.ts +467 -0
- package/src/core/glob.ts +31 -0
- package/src/core/hash.ts +237 -0
- package/src/core/index.ts +28 -0
- package/src/core/lifecycle-fixtures.ts +145 -0
- package/src/core/lifecycle-hooks.ts +101 -0
- package/src/core/mcp-events.ts +57 -0
- package/src/core/model-cli.ts +271 -0
- package/src/core/observer.ts +50 -0
- package/src/core/platform-process.ts +284 -0
- package/src/core/registry.ts +57 -0
- package/src/core/rubric.ts +52 -0
- package/src/core/run.ts +144 -0
- package/src/core/statistics.ts +194 -0
- package/src/core/subject.ts +50 -0
- package/src/core/tool-events.ts +292 -0
- package/src/core/usage.ts +123 -0
- package/src/core/wire.ts +135 -0
- package/src/core/zod.ts +20 -0
- package/src/drivers/claude-code/index.ts +866 -0
- package/src/drivers/claude-code/parse-events.ts +464 -0
- package/src/drivers/codex/app-events.ts +218 -0
- package/src/drivers/codex/config.ts +128 -0
- package/src/drivers/codex/index.ts +995 -0
- package/src/drivers/mcp/index.ts +351 -0
- package/src/drivers/mcp/transport.ts +222 -0
- package/src/drivers/shared/artifacts.ts +86 -0
- package/src/drivers/shared/secure-copy.ts +40 -0
- package/src/drivers/subprocess/index.ts +490 -0
- package/src/index.ts +594 -0
- package/src/optimization/reflective.ts +319 -0
- package/src/orchestrator/annotation-loader.ts +97 -0
- package/src/orchestrator/annotation-store.ts +112 -0
- package/src/orchestrator/authored-dependencies.ts +193 -0
- package/src/orchestrator/campaign-lifecycle.ts +181 -0
- package/src/orchestrator/candidate-integrity.ts +18 -0
- package/src/orchestrator/candidates.ts +683 -0
- package/src/orchestrator/compare.ts +358 -0
- package/src/orchestrator/comparison-identity.ts +45 -0
- package/src/orchestrator/config.ts +205 -0
- package/src/orchestrator/content-bound-json.ts +71 -0
- package/src/orchestrator/discover.ts +132 -0
- package/src/orchestrator/doctor.ts +781 -0
- package/src/orchestrator/driver-session.ts +507 -0
- package/src/orchestrator/evaluator-identity.ts +45 -0
- package/src/orchestrator/experiment-budget.ts +61 -0
- package/src/orchestrator/experiment-context.ts +41 -0
- package/src/orchestrator/experiment-contracts.ts +43 -0
- package/src/orchestrator/experiment-corpus.ts +416 -0
- package/src/orchestrator/experiment-evaluation.ts +749 -0
- package/src/orchestrator/experiment-finish.ts +33 -0
- package/src/orchestrator/experiment-identity.ts +356 -0
- package/src/orchestrator/experiment-loader.ts +105 -0
- package/src/orchestrator/experiment-report.ts +788 -0
- package/src/orchestrator/experiment-runs.ts +960 -0
- package/src/orchestrator/experiment-runtime-identity.ts +465 -0
- package/src/orchestrator/experiment-selection.ts +467 -0
- package/src/orchestrator/experiment.ts +991 -0
- package/src/orchestrator/fixture-identity.ts +67 -0
- package/src/orchestrator/fs-read.ts +126 -0
- package/src/orchestrator/grader-experiment.ts +856 -0
- package/src/orchestrator/grading.ts +260 -0
- package/src/orchestrator/index.ts +186 -0
- package/src/orchestrator/lifecycle-hook-execution.ts +90 -0
- package/src/orchestrator/list-runs.ts +384 -0
- package/src/orchestrator/loader.ts +19 -0
- package/src/orchestrator/optimization-lifecycle.ts +126 -0
- package/src/orchestrator/orchestrator.ts +919 -0
- package/src/orchestrator/owned-lock.ts +147 -0
- package/src/orchestrator/package-version.ts +5 -0
- package/src/orchestrator/provenance.ts +140 -0
- package/src/orchestrator/regrade.ts +580 -0
- package/src/orchestrator/rubric-loader.ts +74 -0
- package/src/orchestrator/run-dir.ts +209 -0
- package/src/orchestrator/run-execution.ts +694 -0
- package/src/orchestrator/run-lifecycle.ts +174 -0
- package/src/orchestrator/suite-compare.ts +195 -0
- package/src/orchestrator/suite-lifecycle.ts +335 -0
- package/src/orchestrator/suite-runs.ts +202 -0
- package/src/orchestrator/suite-summary.ts +276 -0
- package/src/orchestrator/trace-limits.ts +65 -0
- package/src/orchestrator/validate-plugin-config.ts +34 -0
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
chmod,
|
|
4
|
+
constants,
|
|
5
|
+
link,
|
|
6
|
+
lstat,
|
|
7
|
+
mkdir,
|
|
8
|
+
open,
|
|
9
|
+
readdir,
|
|
10
|
+
realpath,
|
|
11
|
+
rm,
|
|
12
|
+
stat,
|
|
13
|
+
unlink,
|
|
14
|
+
writeFile,
|
|
15
|
+
} from "node:fs/promises";
|
|
16
|
+
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
17
|
+
import { temporaryDirectory } from "tempy";
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
import {
|
|
20
|
+
ArtifactSchema,
|
|
21
|
+
bindRunArtifactEvidence,
|
|
22
|
+
contentHash,
|
|
23
|
+
type EvalCase,
|
|
24
|
+
EvalCaseSchema,
|
|
25
|
+
type GradingReport,
|
|
26
|
+
GradingReportSchema,
|
|
27
|
+
inspectRunArtifact,
|
|
28
|
+
PersistedCaseSchema,
|
|
29
|
+
type Registry,
|
|
30
|
+
type Run,
|
|
31
|
+
RunMetadataSchema,
|
|
32
|
+
readInspectedFileBytes,
|
|
33
|
+
readRunArtifactBytes,
|
|
34
|
+
valueHash,
|
|
35
|
+
} from "../core/index.js";
|
|
36
|
+
import { evaluatorImplementationHash } from "./evaluator-identity.js";
|
|
37
|
+
import { parsePersistedJson, readBoundedHandle, safeReadJson } from "./fs-read.js";
|
|
38
|
+
import {
|
|
39
|
+
assertionEvaluatorIdentities,
|
|
40
|
+
assertionPluginIdentities,
|
|
41
|
+
gradeRun,
|
|
42
|
+
graderConfigHash,
|
|
43
|
+
validateAssertionPlan,
|
|
44
|
+
} from "./grading.js";
|
|
45
|
+
import { loadRunDetail } from "./list-runs.js";
|
|
46
|
+
import { LUX_VERSION } from "./package-version.js";
|
|
47
|
+
|
|
48
|
+
export const GRADING_SNAPSHOT_SCHEMA_VERSION = 2 as const;
|
|
49
|
+
|
|
50
|
+
export const GradingSnapshotSchema = z.object({
|
|
51
|
+
schemaVersion: z.literal(GRADING_SNAPSHOT_SCHEMA_VERSION),
|
|
52
|
+
gradingId: z.string(),
|
|
53
|
+
gradedAt: z.string(),
|
|
54
|
+
runDir: z.string(),
|
|
55
|
+
caseHash: z.string(),
|
|
56
|
+
assertionsHash: z.string(),
|
|
57
|
+
validatedAssertionsHash: z.string(),
|
|
58
|
+
graderConfigHash: z.string(),
|
|
59
|
+
evidenceHash: z.string(),
|
|
60
|
+
assertionPlugins: z.array(
|
|
61
|
+
z
|
|
62
|
+
.object({
|
|
63
|
+
type: z.string(),
|
|
64
|
+
pluginVersion: z.string().nullable(),
|
|
65
|
+
})
|
|
66
|
+
.strict(),
|
|
67
|
+
),
|
|
68
|
+
sourceGraderConfigHash: z.string().optional(),
|
|
69
|
+
sourceValidatedAssertionsHash: z.string().optional(),
|
|
70
|
+
report: GradingReportSchema,
|
|
71
|
+
});
|
|
72
|
+
export type GradingSnapshot = z.infer<typeof GradingSnapshotSchema>;
|
|
73
|
+
|
|
74
|
+
const timestampId = (date: Date): string => date.toISOString().replace(/[:.]/g, "-");
|
|
75
|
+
const frozenRunStates = new WeakMap<
|
|
76
|
+
Run,
|
|
77
|
+
{
|
|
78
|
+
snapshotRunDir: string;
|
|
79
|
+
sourceRunDir: string;
|
|
80
|
+
}
|
|
81
|
+
>();
|
|
82
|
+
let currentEvaluatorHash: Promise<string> | undefined;
|
|
83
|
+
const MAX_FROZEN_ARTIFACTS = 10_000;
|
|
84
|
+
const MAX_FROZEN_ARTIFACT_BYTES = 10 * 1024 * 1024;
|
|
85
|
+
const MAX_FROZEN_ARTIFACT_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
86
|
+
const MAX_FROZEN_ARTIFACT_INDEX_BYTES = 2 * 1024 * 1024;
|
|
87
|
+
const MAX_FROZEN_RUN_JSON_BYTES = 2 * 1024 * 1024;
|
|
88
|
+
|
|
89
|
+
const currentEvaluatorImplementationHash = (): Promise<string> =>
|
|
90
|
+
(currentEvaluatorHash ??= evaluatorImplementationHash());
|
|
91
|
+
|
|
92
|
+
const readFrozenJson = async <S extends z.ZodType>(
|
|
93
|
+
path: string,
|
|
94
|
+
schema: S,
|
|
95
|
+
): Promise<z.infer<S> | null> => {
|
|
96
|
+
try {
|
|
97
|
+
if ((await lstat(path)).isSymbolicLink()) {
|
|
98
|
+
throw new Error(`frozen run JSON cannot be a symlink: ${path}`);
|
|
99
|
+
}
|
|
100
|
+
const handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
101
|
+
try {
|
|
102
|
+
const metadata = await handle.stat();
|
|
103
|
+
if (!metadata.isFile() || metadata.size > MAX_FROZEN_RUN_JSON_BYTES) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
`frozen run JSON must be a regular file no larger than ${MAX_FROZEN_RUN_JSON_BYTES} bytes: ${path}`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
const contents = await readBoundedHandle(handle, MAX_FROZEN_RUN_JSON_BYTES, path);
|
|
109
|
+
return parsePersistedJson(path, contents.toString("utf8"), schema);
|
|
110
|
+
} finally {
|
|
111
|
+
await handle.close();
|
|
112
|
+
}
|
|
113
|
+
} catch (error) {
|
|
114
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
|
|
115
|
+
if ((error as NodeJS.ErrnoException).code === "ELOOP") {
|
|
116
|
+
throw new Error(`frozen run JSON cannot be a symlink: ${path}`);
|
|
117
|
+
}
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const loadArtifacts = async (
|
|
123
|
+
runDir: string,
|
|
124
|
+
fallbackPaths: string[],
|
|
125
|
+
frozenLimits: boolean,
|
|
126
|
+
): Promise<Run["artifacts"]> => {
|
|
127
|
+
const artifactsPath = join(runDir, "artifacts.json");
|
|
128
|
+
let persisted: Run["artifacts"] | null = null;
|
|
129
|
+
if (frozenLimits) {
|
|
130
|
+
try {
|
|
131
|
+
if ((await lstat(artifactsPath)).isSymbolicLink()) {
|
|
132
|
+
throw new Error(`frozen artifact index cannot be a symlink: ${artifactsPath}`);
|
|
133
|
+
}
|
|
134
|
+
const handle = await open(artifactsPath, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
135
|
+
try {
|
|
136
|
+
const metadata = await handle.stat();
|
|
137
|
+
if (!metadata.isFile() || metadata.size > MAX_FROZEN_ARTIFACT_INDEX_BYTES) {
|
|
138
|
+
throw new Error(`frozen artifact index exceeds ${MAX_FROZEN_ARTIFACT_INDEX_BYTES} bytes`);
|
|
139
|
+
}
|
|
140
|
+
persisted = parsePersistedJson(
|
|
141
|
+
artifactsPath,
|
|
142
|
+
(
|
|
143
|
+
await readBoundedHandle(
|
|
144
|
+
handle,
|
|
145
|
+
MAX_FROZEN_ARTIFACT_INDEX_BYTES,
|
|
146
|
+
"frozen artifact index",
|
|
147
|
+
)
|
|
148
|
+
).toString("utf8"),
|
|
149
|
+
z.array(ArtifactSchema),
|
|
150
|
+
);
|
|
151
|
+
} finally {
|
|
152
|
+
await handle.close();
|
|
153
|
+
}
|
|
154
|
+
} catch (error) {
|
|
155
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
persisted = await safeReadJson(artifactsPath, z.array(ArtifactSchema));
|
|
159
|
+
}
|
|
160
|
+
if (persisted) return persisted;
|
|
161
|
+
return Promise.all(
|
|
162
|
+
fallbackPaths.map(async (path) => ({
|
|
163
|
+
path,
|
|
164
|
+
size: (await stat(join(runDir, "artifacts", path))).size,
|
|
165
|
+
})),
|
|
166
|
+
);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const authoredCaseFromPersisted = (persisted: z.infer<typeof PersistedCaseSchema>): unknown => ({
|
|
170
|
+
...(persisted.id !== undefined ? { id: persisted.id } : {}),
|
|
171
|
+
...(persisted.prompt !== undefined ? { prompt: persisted.prompt } : {}),
|
|
172
|
+
...(persisted.persona !== undefined ? { persona: persisted.persona } : {}),
|
|
173
|
+
...(persisted.driver !== undefined
|
|
174
|
+
? {
|
|
175
|
+
driver:
|
|
176
|
+
typeof persisted.driver === "string"
|
|
177
|
+
? persisted.driver
|
|
178
|
+
: {
|
|
179
|
+
name: persisted.driver.name,
|
|
180
|
+
...(persisted.driver.config !== undefined
|
|
181
|
+
? { config: persisted.driver.config }
|
|
182
|
+
: {}),
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
: {}),
|
|
186
|
+
...(persisted.answerer !== undefined
|
|
187
|
+
? {
|
|
188
|
+
answerer:
|
|
189
|
+
typeof persisted.answerer === "string"
|
|
190
|
+
? persisted.answerer
|
|
191
|
+
: {
|
|
192
|
+
name: persisted.answerer.name,
|
|
193
|
+
...(persisted.answerer.config !== undefined
|
|
194
|
+
? { config: persisted.answerer.config }
|
|
195
|
+
: {}),
|
|
196
|
+
},
|
|
197
|
+
}
|
|
198
|
+
: {}),
|
|
199
|
+
...(persisted.fixtures !== undefined
|
|
200
|
+
? {
|
|
201
|
+
fixtures:
|
|
202
|
+
typeof persisted.fixtures === "string"
|
|
203
|
+
? persisted.fixtures
|
|
204
|
+
: { kind: persisted.fixtures.kind, path: persisted.fixtures.path },
|
|
205
|
+
}
|
|
206
|
+
: {}),
|
|
207
|
+
...(persisted.assertions !== undefined ? { assertions: persisted.assertions } : {}),
|
|
208
|
+
...(persisted.meta !== undefined ? { meta: persisted.meta } : {}),
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
export const loadRegradableRun = async (
|
|
212
|
+
runDir: string,
|
|
213
|
+
caseOverride?: EvalCase,
|
|
214
|
+
options: { frozenLimits?: boolean } = {},
|
|
215
|
+
): Promise<Run> => {
|
|
216
|
+
const absolute = resolve(runDir);
|
|
217
|
+
const detail = await loadRunDetail(
|
|
218
|
+
absolute,
|
|
219
|
+
options.frozenLimits
|
|
220
|
+
? { maxArtifacts: MAX_FROZEN_ARTIFACTS, skipArtifactsWalk: true, skipJson: true }
|
|
221
|
+
: {},
|
|
222
|
+
);
|
|
223
|
+
const persistedCase = options.frozenLimits
|
|
224
|
+
? await readFrozenJson(join(absolute, "case.json"), PersistedCaseSchema)
|
|
225
|
+
: detail.case;
|
|
226
|
+
const metadata = options.frozenLimits
|
|
227
|
+
? await readFrozenJson(join(absolute, "run.json"), RunMetadataSchema)
|
|
228
|
+
: detail.metadata;
|
|
229
|
+
if (!persistedCase) throw new Error(`case.json is missing or invalid at ${absolute}`);
|
|
230
|
+
if (!metadata) throw new Error(`run.json is missing or invalid at ${absolute}`);
|
|
231
|
+
const parsedCase = EvalCaseSchema.safeParse(
|
|
232
|
+
caseOverride ?? authoredCaseFromPersisted(persistedCase),
|
|
233
|
+
);
|
|
234
|
+
if (!parsedCase.success) {
|
|
235
|
+
throw new Error(
|
|
236
|
+
`persisted case cannot be regraded: ${parsedCase.error.issues[0]?.message ?? "invalid case"}`,
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
case: parsedCase.data,
|
|
241
|
+
metadata,
|
|
242
|
+
events: detail.events,
|
|
243
|
+
artifacts: await loadArtifacts(absolute, detail.artifacts, options.frozenLimits === true),
|
|
244
|
+
runDir: absolute,
|
|
245
|
+
};
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Load evidence for an offline grader experiment. Frozen evidence must be
|
|
250
|
+
* self-contained so authored artifact metadata cannot disclose unrelated
|
|
251
|
+
* local files to a model judge.
|
|
252
|
+
*/
|
|
253
|
+
export const loadFrozenRegradableRun = async (
|
|
254
|
+
runDir: string,
|
|
255
|
+
caseOverride?: EvalCase,
|
|
256
|
+
): Promise<Run> => {
|
|
257
|
+
const run = await loadRegradableRun(runDir, caseOverride, { frozenLimits: true });
|
|
258
|
+
if (run.artifacts.length > MAX_FROZEN_ARTIFACTS) {
|
|
259
|
+
throw new Error(`frozen grader evidence exceeds ${MAX_FROZEN_ARTIFACTS} artifacts`);
|
|
260
|
+
}
|
|
261
|
+
const artifactsRoot = resolve(run.runDir, "artifacts");
|
|
262
|
+
const sourceRunDir = run.runDir;
|
|
263
|
+
const snapshotRunDir = temporaryDirectory({ prefix: "lux-frozen-evidence-" });
|
|
264
|
+
const snapshotArtifactsRoot = join(snapshotRunDir, "artifacts");
|
|
265
|
+
try {
|
|
266
|
+
await mkdir(snapshotArtifactsRoot);
|
|
267
|
+
if (run.artifacts.length > 0) {
|
|
268
|
+
const rootMetadata = await lstat(artifactsRoot);
|
|
269
|
+
if (!rootMetadata.isDirectory() || rootMetadata.isSymbolicLink()) {
|
|
270
|
+
throw new Error("frozen grader artifacts root must be a real directory");
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
const artifacts: Run["artifacts"] = [];
|
|
274
|
+
let totalBytes = 0;
|
|
275
|
+
for (const artifact of run.artifacts) {
|
|
276
|
+
if (artifact.root !== undefined) {
|
|
277
|
+
throw new Error(
|
|
278
|
+
`frozen grader artifact '${artifact.path}' cannot declare an external root`,
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
if (
|
|
282
|
+
isAbsolute(artifact.path) ||
|
|
283
|
+
artifact.path.split(/[\\/]/).includes("..") ||
|
|
284
|
+
artifact.path.includes("\0")
|
|
285
|
+
) {
|
|
286
|
+
throw new Error(`frozen grader artifact path escapes its run: ${artifact.path}`);
|
|
287
|
+
}
|
|
288
|
+
const path = resolve(artifactsRoot, artifact.path);
|
|
289
|
+
if (path === artifactsRoot || !path.startsWith(`${artifactsRoot}${sep}`)) {
|
|
290
|
+
throw new Error(`frozen grader artifact path escapes its run: ${artifact.path}`);
|
|
291
|
+
}
|
|
292
|
+
const inspected = await inspectRunArtifact(run, artifact.path);
|
|
293
|
+
if (!inspected.stats?.isFile()) {
|
|
294
|
+
throw new Error(
|
|
295
|
+
inspected.issue ?? `frozen grader artifact must be a regular file: ${artifact.path}`,
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
const bytes = await readInspectedFileBytes(
|
|
299
|
+
inspected.target,
|
|
300
|
+
inspected.stats,
|
|
301
|
+
MAX_FROZEN_ARTIFACT_BYTES,
|
|
302
|
+
`frozen grader artifact '${artifact.path}'`,
|
|
303
|
+
);
|
|
304
|
+
totalBytes += bytes.length;
|
|
305
|
+
if (totalBytes > MAX_FROZEN_ARTIFACT_TOTAL_BYTES) {
|
|
306
|
+
throw new Error(
|
|
307
|
+
`frozen grader artifacts exceed ${MAX_FROZEN_ARTIFACT_TOTAL_BYTES} total bytes`,
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
const destination = resolve(snapshotArtifactsRoot, artifact.path);
|
|
311
|
+
if (!destination.startsWith(`${resolve(snapshotArtifactsRoot)}${sep}`)) {
|
|
312
|
+
throw new Error(`frozen grader artifact path escapes its snapshot: ${artifact.path}`);
|
|
313
|
+
}
|
|
314
|
+
await mkdir(resolve(destination, ".."), { recursive: true });
|
|
315
|
+
await writeFile(destination, bytes, { flag: "wx" });
|
|
316
|
+
await chmod(destination, inspected.stats.mode & 0o777);
|
|
317
|
+
artifacts.push({ ...artifact, root: snapshotArtifactsRoot, size: bytes.length });
|
|
318
|
+
}
|
|
319
|
+
const frozen = { ...run, runDir: snapshotRunDir, artifacts };
|
|
320
|
+
bindRunArtifactEvidence(frozen, { root: snapshotArtifactsRoot, indexedOnly: true });
|
|
321
|
+
frozenRunStates.set(frozen, { snapshotRunDir, sourceRunDir });
|
|
322
|
+
return frozen;
|
|
323
|
+
} catch (error) {
|
|
324
|
+
await rm(snapshotRunDir, { recursive: true, force: true });
|
|
325
|
+
throw error;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
export const releaseFrozenRegradableRun = async (run: Run): Promise<void> => {
|
|
330
|
+
const state = frozenRunStates.get(run);
|
|
331
|
+
if (!state) return;
|
|
332
|
+
frozenRunStates.delete(run);
|
|
333
|
+
await rm(state.snapshotRunDir, { recursive: true, force: true });
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const writeGradingSnapshot = async (
|
|
337
|
+
run: Run,
|
|
338
|
+
report: GradingReport,
|
|
339
|
+
identity: {
|
|
340
|
+
validatedAssertionsHash: string;
|
|
341
|
+
graderConfigHash: string;
|
|
342
|
+
evidenceHash: string;
|
|
343
|
+
assertionPlugins: GradingSnapshot["assertionPlugins"];
|
|
344
|
+
},
|
|
345
|
+
now: Date,
|
|
346
|
+
): Promise<{ path: string; snapshot: GradingSnapshot }> => {
|
|
347
|
+
const gradingPrefix = timestampId(now);
|
|
348
|
+
const persistedRunDir = frozenRunStates.get(run)?.sourceRunDir ?? run.runDir;
|
|
349
|
+
const directory = join(persistedRunDir, "gradings");
|
|
350
|
+
try {
|
|
351
|
+
await mkdir(directory);
|
|
352
|
+
} catch (error) {
|
|
353
|
+
if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
|
|
354
|
+
}
|
|
355
|
+
const directoryMetadata = await lstat(directory);
|
|
356
|
+
if (!directoryMetadata.isDirectory() || directoryMetadata.isSymbolicLink()) {
|
|
357
|
+
throw new Error("run gradings path must be a real directory");
|
|
358
|
+
}
|
|
359
|
+
const [canonicalRunRoot, canonicalDirectory] = await Promise.all([
|
|
360
|
+
realpath(persistedRunDir),
|
|
361
|
+
realpath(directory),
|
|
362
|
+
]);
|
|
363
|
+
if (canonicalDirectory !== join(canonicalRunRoot, "gradings")) {
|
|
364
|
+
throw new Error("run gradings directory resolves outside its run");
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
for (let suffix = 1; ; suffix++) {
|
|
368
|
+
const gradingId = suffix === 1 ? gradingPrefix : `${gradingPrefix}-${suffix}`;
|
|
369
|
+
const path = join(directory, `${gradingId}.json`);
|
|
370
|
+
const snapshot: GradingSnapshot = {
|
|
371
|
+
schemaVersion: GRADING_SNAPSHOT_SCHEMA_VERSION,
|
|
372
|
+
gradingId,
|
|
373
|
+
gradedAt: now.toISOString(),
|
|
374
|
+
runDir: persistedRunDir,
|
|
375
|
+
caseHash: valueHash(run.case),
|
|
376
|
+
assertionsHash: valueHash(run.case.assertions ?? []),
|
|
377
|
+
validatedAssertionsHash: identity.validatedAssertionsHash,
|
|
378
|
+
graderConfigHash: identity.graderConfigHash,
|
|
379
|
+
evidenceHash: identity.evidenceHash,
|
|
380
|
+
assertionPlugins: identity.assertionPlugins,
|
|
381
|
+
...(run.metadata.provenance?.graderConfigHash
|
|
382
|
+
? { sourceGraderConfigHash: run.metadata.provenance.graderConfigHash }
|
|
383
|
+
: {}),
|
|
384
|
+
...(run.metadata.provenance?.validatedAssertionsHash
|
|
385
|
+
? {
|
|
386
|
+
sourceValidatedAssertionsHash: run.metadata.provenance.validatedAssertionsHash,
|
|
387
|
+
}
|
|
388
|
+
: {}),
|
|
389
|
+
report,
|
|
390
|
+
};
|
|
391
|
+
const temporary = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
392
|
+
await writeFile(temporary, `${JSON.stringify(snapshot, null, 2)}\n`, { flag: "wx" });
|
|
393
|
+
try {
|
|
394
|
+
await link(temporary, path);
|
|
395
|
+
return { path, snapshot };
|
|
396
|
+
} catch (error) {
|
|
397
|
+
if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
|
|
398
|
+
} finally {
|
|
399
|
+
await unlink(temporary).catch(() => undefined);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
type FrozenCwdEntry = {
|
|
405
|
+
path: string;
|
|
406
|
+
kind: "directory" | "file";
|
|
407
|
+
mode: number;
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
const frozenCwdManifest = async (run: Run): Promise<FrozenCwdEntry[]> => {
|
|
411
|
+
if (!frozenRunStates.has(run)) {
|
|
412
|
+
throw new Error("grading evidence is not bound to a frozen run");
|
|
413
|
+
}
|
|
414
|
+
const expected = new Map<string, Map<string, FrozenCwdEntry["kind"]>>();
|
|
415
|
+
const addExpected = (directory: string, name: string, kind: FrozenCwdEntry["kind"]): void => {
|
|
416
|
+
const children = expected.get(directory) ?? new Map();
|
|
417
|
+
const existing = children.get(name);
|
|
418
|
+
if (existing && existing !== kind) {
|
|
419
|
+
throw new Error("frozen grading evidence has conflicting artifact paths");
|
|
420
|
+
}
|
|
421
|
+
children.set(name, kind);
|
|
422
|
+
expected.set(directory, children);
|
|
423
|
+
};
|
|
424
|
+
expected.set("", new Map([["artifacts", "directory"]]));
|
|
425
|
+
expected.set("artifacts", new Map());
|
|
426
|
+
for (const artifact of run.artifacts) {
|
|
427
|
+
const target = resolve(artifact.root ?? join(run.runDir, "artifacts"), artifact.path);
|
|
428
|
+
const authored = relative(run.runDir, target);
|
|
429
|
+
if (authored === ".." || authored.startsWith(`..${sep}`) || isAbsolute(authored)) {
|
|
430
|
+
throw new Error("frozen grading evidence contains an artifact outside its snapshot");
|
|
431
|
+
}
|
|
432
|
+
const parts = authored.split(sep).filter(Boolean);
|
|
433
|
+
for (let index = 0; index < parts.length; index++) {
|
|
434
|
+
const parent = parts.slice(0, index).join(sep);
|
|
435
|
+
const name = parts[index];
|
|
436
|
+
if (!name) continue;
|
|
437
|
+
const kind = index === parts.length - 1 ? "file" : "directory";
|
|
438
|
+
addExpected(parent, name, kind);
|
|
439
|
+
if (kind === "directory" && !expected.has(join(parent, name))) {
|
|
440
|
+
expected.set(join(parent, name), new Map());
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const manifest: FrozenCwdEntry[] = [];
|
|
446
|
+
for (const directory of [...expected.keys()].sort()) {
|
|
447
|
+
const absolute = resolve(run.runDir, directory);
|
|
448
|
+
const metadata = await lstat(absolute);
|
|
449
|
+
if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
|
|
450
|
+
throw new Error("frozen grading cwd changed during evaluation");
|
|
451
|
+
}
|
|
452
|
+
manifest.push({
|
|
453
|
+
path: directory || ".",
|
|
454
|
+
kind: "directory",
|
|
455
|
+
mode: metadata.mode & 0o777,
|
|
456
|
+
});
|
|
457
|
+
const actual = await readdir(absolute, { withFileTypes: true });
|
|
458
|
+
const expectedChildren = expected.get(directory) ?? new Map();
|
|
459
|
+
if (
|
|
460
|
+
actual.length !== expectedChildren.size ||
|
|
461
|
+
actual.some((entry) => {
|
|
462
|
+
const kind = expectedChildren.get(entry.name);
|
|
463
|
+
return (
|
|
464
|
+
kind === undefined ||
|
|
465
|
+
(kind === "directory" && !entry.isDirectory()) ||
|
|
466
|
+
(kind === "file" && !entry.isFile())
|
|
467
|
+
);
|
|
468
|
+
})
|
|
469
|
+
) {
|
|
470
|
+
throw new Error("frozen grading cwd changed during evaluation");
|
|
471
|
+
}
|
|
472
|
+
for (const entry of actual.filter((candidate) => candidate.isFile())) {
|
|
473
|
+
const path = join(directory, entry.name);
|
|
474
|
+
const file = await lstat(resolve(run.runDir, path));
|
|
475
|
+
if (!file.isFile() || file.isSymbolicLink()) {
|
|
476
|
+
throw new Error("frozen grading cwd changed during evaluation");
|
|
477
|
+
}
|
|
478
|
+
manifest.push({ path, kind: "file", mode: file.mode & 0o777 });
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return manifest.sort((left, right) => left.path.localeCompare(right.path));
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
const gradingEvidenceHash = async (run: Run): Promise<string> => {
|
|
485
|
+
const artifacts: Array<{
|
|
486
|
+
path: string;
|
|
487
|
+
contentType: string | null;
|
|
488
|
+
declaredSize: number | null;
|
|
489
|
+
size: number;
|
|
490
|
+
meta: Record<string, unknown> | null;
|
|
491
|
+
contentHash: string;
|
|
492
|
+
}> = [];
|
|
493
|
+
// Frozen runs may contain up to 200 artifacts. Hash in order so tiny files
|
|
494
|
+
// never reserve every per-file ceiling at once.
|
|
495
|
+
for (const artifact of [...run.artifacts].sort((left, right) =>
|
|
496
|
+
left.path.localeCompare(right.path),
|
|
497
|
+
)) {
|
|
498
|
+
const bytes = await readRunArtifactBytes(run, artifact.path, {
|
|
499
|
+
maxBytes: MAX_FROZEN_ARTIFACT_BYTES,
|
|
500
|
+
});
|
|
501
|
+
artifacts.push({
|
|
502
|
+
path: artifact.path,
|
|
503
|
+
contentType: artifact.contentType ?? null,
|
|
504
|
+
declaredSize: artifact.size ?? null,
|
|
505
|
+
size: bytes.length,
|
|
506
|
+
meta: artifact.meta ?? null,
|
|
507
|
+
contentHash: contentHash(bytes),
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
return valueHash({
|
|
511
|
+
case: run.case,
|
|
512
|
+
metadata: run.metadata,
|
|
513
|
+
events: run.events,
|
|
514
|
+
artifacts,
|
|
515
|
+
cwd: await frozenCwdManifest(run),
|
|
516
|
+
});
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
export const regradeRun = async (options: {
|
|
520
|
+
runDir: string;
|
|
521
|
+
registry: Registry;
|
|
522
|
+
case?: EvalCase;
|
|
523
|
+
/** Explicit grader state captured by closures, such as the configured harness model. */
|
|
524
|
+
graderContext?: unknown;
|
|
525
|
+
abortSignal?: AbortSignal;
|
|
526
|
+
now?: Date;
|
|
527
|
+
}): Promise<{ path: string; snapshot: GradingSnapshot }> => {
|
|
528
|
+
const run = await loadFrozenRegradableRun(options.runDir, options.case);
|
|
529
|
+
try {
|
|
530
|
+
const evidenceHash = await gradingEvidenceHash(run);
|
|
531
|
+
const validatedAssertionConfigs = await validateAssertionPlan(
|
|
532
|
+
run.case.assertions ?? [],
|
|
533
|
+
options.registry,
|
|
534
|
+
);
|
|
535
|
+
const validatedAssertionsHash = valueHash(validatedAssertionConfigs);
|
|
536
|
+
const assertionEvaluators = assertionEvaluatorIdentities(
|
|
537
|
+
run.case.assertions ?? [],
|
|
538
|
+
options.registry,
|
|
539
|
+
);
|
|
540
|
+
const assertionPlugins = assertionPluginIdentities(run.case.assertions ?? [], options.registry);
|
|
541
|
+
const graderHash = graderConfigHash({
|
|
542
|
+
luxVersion: LUX_VERSION,
|
|
543
|
+
implementationHash: await currentEvaluatorImplementationHash(),
|
|
544
|
+
assertions: assertionEvaluators,
|
|
545
|
+
validatedAssertionsHash,
|
|
546
|
+
graderContext: options.graderContext,
|
|
547
|
+
});
|
|
548
|
+
const report: GradingReport = await gradeRun(
|
|
549
|
+
run,
|
|
550
|
+
options.registry,
|
|
551
|
+
undefined,
|
|
552
|
+
options.abortSignal,
|
|
553
|
+
undefined,
|
|
554
|
+
undefined,
|
|
555
|
+
validatedAssertionConfigs,
|
|
556
|
+
);
|
|
557
|
+
let postEvaluationEvidenceHash: string;
|
|
558
|
+
try {
|
|
559
|
+
postEvaluationEvidenceHash = await gradingEvidenceHash(run);
|
|
560
|
+
} catch (error) {
|
|
561
|
+
throw new Error("frozen grading evidence changed during evaluation", { cause: error });
|
|
562
|
+
}
|
|
563
|
+
if (postEvaluationEvidenceHash !== evidenceHash) {
|
|
564
|
+
throw new Error("frozen grading evidence changed during evaluation");
|
|
565
|
+
}
|
|
566
|
+
return await writeGradingSnapshot(
|
|
567
|
+
run,
|
|
568
|
+
report,
|
|
569
|
+
{
|
|
570
|
+
validatedAssertionsHash,
|
|
571
|
+
graderConfigHash: graderHash,
|
|
572
|
+
evidenceHash,
|
|
573
|
+
assertionPlugins,
|
|
574
|
+
},
|
|
575
|
+
options.now ?? new Date(),
|
|
576
|
+
);
|
|
577
|
+
} finally {
|
|
578
|
+
await releaseFrozenRegradableRun(run);
|
|
579
|
+
}
|
|
580
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { readFile, stat } from "node:fs/promises";
|
|
2
|
+
import { extname, resolve } from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { RubricConfigSchema } from "../assertions/rubric/index.js";
|
|
5
|
+
import { formatZodIssues, type RubricDefinition, RubricDefinitionSchema } from "../core/index.js";
|
|
6
|
+
|
|
7
|
+
const CANDIDATE_FORBIDDEN_FIELDS = [
|
|
8
|
+
"command",
|
|
9
|
+
"provider",
|
|
10
|
+
"model",
|
|
11
|
+
"reasoningEffort",
|
|
12
|
+
"timeoutMs",
|
|
13
|
+
"promptOverride",
|
|
14
|
+
] as const;
|
|
15
|
+
const RawRubricDefinitionSchema = z.looseObject({
|
|
16
|
+
assertions: z.array(z.unknown()),
|
|
17
|
+
});
|
|
18
|
+
const RawRubricAssertionSchema = z.looseObject({});
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Candidate rubrics are deliberately declarative JSON. Reflective optimization
|
|
22
|
+
* must never gain code execution by emitting a TypeScript grader module.
|
|
23
|
+
*/
|
|
24
|
+
export const loadRubricDefinition = async (filePath: string): Promise<RubricDefinition> => {
|
|
25
|
+
const path = resolve(filePath);
|
|
26
|
+
if (extname(path).toLowerCase() !== ".json") {
|
|
27
|
+
throw new Error(`Lux grader experiments require a declarative .json rubric: ${path}`);
|
|
28
|
+
}
|
|
29
|
+
if ((await stat(path)).size > 256_000) {
|
|
30
|
+
throw new Error(`Invalid Lux rubric at ${path}: candidate rubric exceeds 256000 bytes`);
|
|
31
|
+
}
|
|
32
|
+
const raw: unknown = JSON.parse(await readFile(path, "utf8"));
|
|
33
|
+
const parsed = RubricDefinitionSchema.safeParse(raw);
|
|
34
|
+
if (!parsed.success) {
|
|
35
|
+
throw new Error(`Invalid Lux rubric at ${path}: ${formatZodIssues(parsed.error)}`);
|
|
36
|
+
}
|
|
37
|
+
if (parsed.data.assertions.length > 20) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
`Invalid Lux rubric at ${path}: candidate rubrics are limited to 20 assertions`,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
const rawAssertions = RawRubricDefinitionSchema.parse(raw).assertions;
|
|
43
|
+
for (const [index, assertion] of parsed.data.assertions.entries()) {
|
|
44
|
+
if (assertion.type !== "rubric") {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`Invalid Lux rubric at ${path}: grader experiment assertions must use type 'rubric', got '${assertion.type}'`,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
const rawAssertion = RawRubricAssertionSchema.safeParse(rawAssertions[index]).data;
|
|
50
|
+
const field = rawAssertion
|
|
51
|
+
? CANDIDATE_FORBIDDEN_FIELDS.find((key) => key in rawAssertion)
|
|
52
|
+
: undefined;
|
|
53
|
+
if (field) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Invalid Lux rubric at ${path}: candidate assertions cannot override '${field}'`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
const config = RubricConfigSchema.safeParse(rawAssertion);
|
|
59
|
+
if (!config.success) {
|
|
60
|
+
throw new Error(`Invalid Lux rubric at ${path}: ${formatZodIssues(config.error)}`);
|
|
61
|
+
}
|
|
62
|
+
if (
|
|
63
|
+
config.data.criteria.length > 20_000 ||
|
|
64
|
+
config.data.evidence.maxEvents > 100 ||
|
|
65
|
+
config.data.evidence.maxAgentChars > 100_000 ||
|
|
66
|
+
config.data.evidence.maxToolChars > 100_000 ||
|
|
67
|
+
config.data.evidence.maxArtifactChars > 200_000 ||
|
|
68
|
+
config.data.maxArtifactExcerpt > 20_000
|
|
69
|
+
) {
|
|
70
|
+
throw new Error(`Invalid Lux rubric at ${path}: candidate prompt bounds exceed safe caps`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return parsed.data;
|
|
74
|
+
};
|