@tangle-network/agent-eval 0.126.6 → 0.126.7

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/CHANGELOG.md CHANGED
@@ -4,6 +4,13 @@ All notable changes to `@tangle-network/agent-eval` and its sibling `agent-eval-
4
4
 
5
5
  ---
6
6
 
7
+ ## [0.126.7] - 2026-07-24 - dependency security refresh
8
+
9
+ ### Changed
10
+
11
+ - Updated Ax, Hono, Zod, OpenAPI, Biome, Node types, lint-staged, and Vitest to their current compatible releases.
12
+ - Pinned patched Vite, esbuild, PostCSS, and WebSocket transitive versions; the npm dependency audit now reports zero known vulnerabilities.
13
+
7
14
  ## [0.126.6] - 2026-07-24 - optimizer model provenance
8
15
 
9
16
  ### Added
@@ -2123,7 +2123,7 @@ type RawAnalystFinding = z.infer<typeof RawAnalystFindingSchema>;
2123
2123
  * item so persisted rows and older model fixtures remain readable. New output
2124
2124
  * always receives the plural shape.
2125
2125
  */
2126
- declare const CanonicalRawAnalystFindingSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
2126
+ declare const CanonicalRawAnalystFindingSchema: z.ZodPreprocess<z.ZodObject<{
2127
2127
  evidence: z.ZodArray<z.ZodObject<{
2128
2128
  uri: z.ZodString;
2129
2129
  excerpt: z.ZodOptional<z.ZodString>;
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { AgentCandidateExperiment, AgentCandidateBundle, AgentCandidateBenchmarkTask, AgentCandidateBenchmarkCellRef, AgentCandidateExperimentMeasurement, AgentImprovementMeasuredComparison, CandidateExecutionEvidence, AgentCandidateBenchmarkSuiteInputs, AgentCandidateBenchmarkTaskMaterial, AgentCandidateExperimentMaterial } from '@tangle-network/agent-interface';
2
+ import { AgentCandidateExperiment, AgentCandidateBundle, AgentCandidateBenchmarkTask, AgentCandidateBenchmarkCellRef, AgentCandidateExperimentMeasurement, AgentImprovementMeasuredComparison, AgentCandidateEvaluationPolicy, CandidateExecutionEvidence, AgentCandidateBenchmarkSuiteInputs, AgentCandidateBenchmarkTaskMaterial, AgentCandidateExperimentMaterial } from '@tangle-network/agent-interface';
3
3
  import { AxFunction, AxAIService } from '@ax-llm/ax';
4
4
 
5
5
  type CostChannel = 'agent' | 'judge' | 'verifier' | 'analyst' | 'driver' | (string & {});
@@ -3968,6 +3968,39 @@ interface CompareCandidateExperimentOptions {
3968
3968
  searchCostUsd?: number;
3969
3969
  metadata?: AgentImprovementMeasuredComparison['metadata'];
3970
3970
  }
3971
+ /** One exact baseline/candidate observation of the same held-out cell. */
3972
+ interface PairedMeasurement<TRun> {
3973
+ cellId: string;
3974
+ baseline: TRun;
3975
+ candidate: TRun;
3976
+ }
3977
+ /** Maps a product-owned run receipt into the measurements required for a fair paired decision. */
3978
+ interface PairedMeasurementAdapter<TRun> {
3979
+ score(run: TRun): number;
3980
+ dimensions(run: TRun): readonly {
3981
+ name: string;
3982
+ score: number;
3983
+ }[];
3984
+ costUsd(run: TRun): number;
3985
+ latencyMs(run: TRun): number;
3986
+ completed(run: TRun): boolean;
3987
+ passed(run: TRun): boolean;
3988
+ }
3989
+ interface EvaluatePairedMeasurementsOptions<TRun> {
3990
+ measurements: readonly PairedMeasurement<TRun>[];
3991
+ policy: AgentCandidateEvaluationPolicy;
3992
+ adapter: PairedMeasurementAdapter<TRun>;
3993
+ /** Whether both arms use the same scorer family as the promotion decision. */
3994
+ sharedScorerChannel: boolean;
3995
+ /** Search or preparation spend that belongs to the same frozen budget. */
3996
+ additionalCostUsd?: number;
3997
+ }
3998
+ /** Statistical and operational result derived from complete paired receipts. */
3999
+ type PairedMeasurementEvaluation = Pick<AgentImprovementMeasuredComparison, 'overall' | 'objectives' | 'decision' | 'power'> & {
4000
+ executionCostUsd: number;
4001
+ totalCostUsd: number;
4002
+ executionDurationMs: number;
4003
+ };
3971
4004
  /** Content-address one task before any measured execution can see it. */
3972
4005
  declare function sealCandidateBenchmarkTask(material: AgentCandidateBenchmarkTaskMaterial): AgentCandidateBenchmarkTask;
3973
4006
  /** Freeze task order, repetitions, and every seed before either arm runs. */
@@ -3977,6 +4010,14 @@ declare function sealCandidateExperiment(material: AgentCandidateExperimentMater
3977
4010
  declare function verifyCandidateExperiment(input: unknown): AgentCandidateExperiment;
3978
4011
  /** Execute each signed cell for both arms. The callback is Runtime's one executor. */
3979
4012
  declare function runCandidateExperiment(options: RunCandidateExperimentOptions): Promise<AgentCandidateExperimentMeasurement[]>;
4013
+ /**
4014
+ * Calculate the shared paired decision from any complete receipt shape.
4015
+ *
4016
+ * Callers still own sealing their tasks, verifying each receipt against its
4017
+ * expected arm and state, and proving every expected cell exists. This function
4018
+ * only validates the projected measurements and derives their shared decision.
4019
+ */
4020
+ declare function evaluatePairedMeasurements<TRun>(options: EvaluatePairedMeasurementsOptions<TRun>): PairedMeasurementEvaluation;
3980
4021
  /** Build the only publishable comparison: paired statistics over Runtime receipts. */
3981
4022
  declare function measuredComparisonFromCandidateExperiment(options: CompareCandidateExperimentOptions): AgentImprovementMeasuredComparison;
3982
4023
  /** Recompute every statistic and decision from the signed experiment receipts. */
@@ -4522,7 +4563,7 @@ type RawAnalystFinding = z.infer<typeof RawAnalystFindingSchema>;
4522
4563
  * item so persisted rows and older model fixtures remain readable. New output
4523
4564
  * always receives the plural shape.
4524
4565
  */
4525
- declare const CanonicalRawAnalystFindingSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
4566
+ declare const CanonicalRawAnalystFindingSchema: z.ZodPreprocess<z.ZodObject<{
4526
4567
  evidence: z.ZodArray<z.ZodObject<{
4527
4568
  uri: z.ZodString;
4528
4569
  excerpt: z.ZodOptional<z.ZodString>;
@@ -5465,4 +5506,4 @@ interface FromOtelSpansOptions {
5465
5506
  }
5466
5507
  declare function fromOtelSpans(opts: FromOtelSpansOptions): RunRecord[];
5467
5508
 
5468
- export { type AgentEvalAgent, type AgentEvalEvaluateOptions, type AgentEvalImproveOptions, type AgentTraceContributor, type AgentTraceContributorType, type AgentTraceConversation, type AgentTraceFile, type AgentTraceIndex, type AgentTraceRange, type AgentTraceRecord, type AnalystFinding, type AnalyzeRunsOptions, type AuthoringProvenance, type AxisEvidence, type AxisVerdict, type BuildEvidenceVectorOptions, type CampaignAggregates, type CampaignArtifactWriter, type CampaignCellFailureReceipt, type CampaignCellResult, type CampaignCostMeter, type CampaignResult, type CampaignStorage, type CampaignTraceWriter, type CandidateExperimentExecutionInput, type ChatClient, type CodeAgentSessionAction, type CodeAgentSessionActionKind, type CodeAgentSessionActionStatus, type CodeAgentSessionActionSurface, type CodeAgentSessionDiagnostic, type CodeAgentSessionExecutionReceipt, type CodeAgentSessionIntakeOptions, type CodeAgentSessionIntakeResult, type CodeAgentSessionMetrics, type CodeAgentSessionObservation, type CodeAgentSessionSource, type CodeAgentSessionTerminalStatus, type CodeSurface, type CompareCandidateExperimentOptions, type CompareOptimizationMethodsOptions, type ComparisonCost, type CostLedgerHandle, type CostProvenanceSummary, type CreateChatClientOpts, type DefaultAnalystRegistryOptions, type DefaultProductionGateOptions, type DefineAgentEvalOptions, type DefinedAgentEval, type DeploymentOutcome, type DispatchFn as Dispatch, type DispatchContext, type EvalCellScoreDelta, type EvalDimensionDelta, type EvalGenerationDiff, type EvalReportingSuiteInput, type EvalReportingSuiteOptions, type EvalReportingSuiteResult, type EvalRunDiff, type EvidenceVector, type ExecutionInsight, type ExecutionReport, type ExternalOptimizationExample, type ExternalTextEvaluationResponse, type ExternalTextOptimizationMethodConfig, type ExternalTextOptimizerContext, type ExternalTextOptimizerResult, type FailureClusterInsight, type FeedbackTableMeta, type FeedbackTableRow, FileSystemOutcomeStore, type FileSystemOutcomeStoreOptions, type FromFeedbackTableOptions, type FromFeedbackTableResult, type FromOtelSpansOptions, type FromRunRecordDirOptions, type FromRunRecordDirResult, type Gate, type GateContext, type GateDecision, type GateResult, type GenerationCandidate, type GenerationRecord, type GepaAdaptiveEngineRun, type GepaEngineOptions, type GepaEngineRun, type GepaOptimizationMethodConfig, type GepaOptimizationRecipe, type GepaRunnerCommand, type HeldOutGateOptions, type HostedTenant, InMemoryOutcomeStore, type InsightReport, type InterRaterInsight, type JudgeConfig, type JudgeDimension, type JudgeInsight, type JudgeScore, type LiftInsight, type LlmJudgeDimension, type LlmJudgeOptions, type MutableSurface, type ObjectiveSource, type OpenAICompatibleOptimizerModel, type OptimizationMethod, type OptimizationMethodComparison, type OptimizationMethodInput, type OptimizationMethodProvenance, type OptimizationMethodResult, type OptimizationPackageSource, type OptimizationProposer, type OptimizationTokenUsage, type OptimizerConfig, type OptimizerModelBudget, type OutcomeCorrelationInsight, type OutcomeStore, type ParetoSignificanceGateOptions, type ParsedCodeAgentJsonl, type PartitionByAuthoringModelResult, type PromotionObjective, type PromotionPolicy, REFERENCE_EQUIVALENCE_INPUT_LIMITS, REFERENCE_EQUIVALENCE_JUDGE_VERSION, type Recommendation, type ReferenceEquivalenceJudgeInput, type ReferenceEquivalenceJudgeOptions, type ReferenceEquivalenceJudgeResult, type ReferenceEquivalenceScenario, type ReleaseSummary, type RunCampaignOptions, type RunCandidateExperimentOptions, type RunEvalOptions, type RunImprovementLoopOptions, type RunImprovementLoopResult, type RunRecordRejection, type ScalarDistribution, type Scenario$1 as Scenario, type SealCandidateBenchmarkSuiteOptions, type SelfImproveBudget, type SelfImproveOptions, type SelfImproveProgressEvent, type SelfImproveResult, SelfImproveRunError, type SessionScript, type SkillOptOptimizationMethodConfig, type SkillOptRunnerCommand, type SkillOptTrainerConfig, type SummarizeExecutionOptions, type SurfaceProposer, type TokenUsageInsight, analyzeRuns, buildDefaultAnalystRegistry, buildEvidenceVector, campaignSplitDigest, compareOptimizationMethods, composeGate, createChatClient, createReferenceEquivalenceJudge, defaultProductionGate, defineAgentEval, diffGenerations, diffRunBaselineToWinner, diffRuns, evalReportingSuite, externalTextOptimizationMethod, fromClaudeCodeSession, fromCodexSession, fromFeedbackTable, fromKimiCodeSession, fromOpenCodeSession, fromOtelSpans, fromPiSession, fromPigraphSession, fromRunRecordDir, fsCampaignStorage, gepaOptimizationMethod, heldOutGate, inMemoryCampaignStorage, llmJudge, measuredComparisonFromCandidateExperiment, observeCodeAgentSession, paretoPolicy, paretoSignificanceGate, parseAgentTrace, parseCodeAgentJsonl, partitionRunsByAuthoringModel, runCampaign, runCandidateExperiment, runEval, runImprovementLoop, runReferenceEquivalenceJudge, sealCandidateBenchmarkSuite, sealCandidateBenchmarkTask, sealCandidateExperiment, selfImprove, skillOptOptimizationMethod, summarizeExecution, verifyCandidateBenchmarkSuite, verifyCandidateBenchmarkSuiteInputs, verifyCandidateBenchmarkTask, verifyCandidateExperiment, verifyCandidateExperimentComparison };
5509
+ export { type AgentEvalAgent, type AgentEvalEvaluateOptions, type AgentEvalImproveOptions, type AgentTraceContributor, type AgentTraceContributorType, type AgentTraceConversation, type AgentTraceFile, type AgentTraceIndex, type AgentTraceRange, type AgentTraceRecord, type AnalystFinding, type AnalyzeRunsOptions, type AuthoringProvenance, type AxisEvidence, type AxisVerdict, type BuildEvidenceVectorOptions, type CampaignAggregates, type CampaignArtifactWriter, type CampaignCellFailureReceipt, type CampaignCellResult, type CampaignCostMeter, type CampaignResult, type CampaignStorage, type CampaignTraceWriter, type CandidateExperimentExecutionInput, type ChatClient, type CodeAgentSessionAction, type CodeAgentSessionActionKind, type CodeAgentSessionActionStatus, type CodeAgentSessionActionSurface, type CodeAgentSessionDiagnostic, type CodeAgentSessionExecutionReceipt, type CodeAgentSessionIntakeOptions, type CodeAgentSessionIntakeResult, type CodeAgentSessionMetrics, type CodeAgentSessionObservation, type CodeAgentSessionSource, type CodeAgentSessionTerminalStatus, type CodeSurface, type CompareCandidateExperimentOptions, type CompareOptimizationMethodsOptions, type ComparisonCost, type CostLedgerHandle, type CostProvenanceSummary, type CreateChatClientOpts, type DefaultAnalystRegistryOptions, type DefaultProductionGateOptions, type DefineAgentEvalOptions, type DefinedAgentEval, type DeploymentOutcome, type DispatchFn as Dispatch, type DispatchContext, type EvalCellScoreDelta, type EvalDimensionDelta, type EvalGenerationDiff, type EvalReportingSuiteInput, type EvalReportingSuiteOptions, type EvalReportingSuiteResult, type EvalRunDiff, type EvaluatePairedMeasurementsOptions, type EvidenceVector, type ExecutionInsight, type ExecutionReport, type ExternalOptimizationExample, type ExternalTextEvaluationResponse, type ExternalTextOptimizationMethodConfig, type ExternalTextOptimizerContext, type ExternalTextOptimizerResult, type FailureClusterInsight, type FeedbackTableMeta, type FeedbackTableRow, FileSystemOutcomeStore, type FileSystemOutcomeStoreOptions, type FromFeedbackTableOptions, type FromFeedbackTableResult, type FromOtelSpansOptions, type FromRunRecordDirOptions, type FromRunRecordDirResult, type Gate, type GateContext, type GateDecision, type GateResult, type GenerationCandidate, type GenerationRecord, type GepaAdaptiveEngineRun, type GepaEngineOptions, type GepaEngineRun, type GepaOptimizationMethodConfig, type GepaOptimizationRecipe, type GepaRunnerCommand, type HeldOutGateOptions, type HostedTenant, InMemoryOutcomeStore, type InsightReport, type InterRaterInsight, type JudgeConfig, type JudgeDimension, type JudgeInsight, type JudgeScore, type LiftInsight, type LlmJudgeDimension, type LlmJudgeOptions, type MutableSurface, type ObjectiveSource, type OpenAICompatibleOptimizerModel, type OptimizationMethod, type OptimizationMethodComparison, type OptimizationMethodInput, type OptimizationMethodProvenance, type OptimizationMethodResult, type OptimizationPackageSource, type OptimizationProposer, type OptimizationTokenUsage, type OptimizerConfig, type OptimizerModelBudget, type OutcomeCorrelationInsight, type OutcomeStore, type PairedMeasurement, type PairedMeasurementAdapter, type PairedMeasurementEvaluation, type ParetoSignificanceGateOptions, type ParsedCodeAgentJsonl, type PartitionByAuthoringModelResult, type PromotionObjective, type PromotionPolicy, REFERENCE_EQUIVALENCE_INPUT_LIMITS, REFERENCE_EQUIVALENCE_JUDGE_VERSION, type Recommendation, type ReferenceEquivalenceJudgeInput, type ReferenceEquivalenceJudgeOptions, type ReferenceEquivalenceJudgeResult, type ReferenceEquivalenceScenario, type ReleaseSummary, type RunCampaignOptions, type RunCandidateExperimentOptions, type RunEvalOptions, type RunImprovementLoopOptions, type RunImprovementLoopResult, type RunRecordRejection, type ScalarDistribution, type Scenario$1 as Scenario, type SealCandidateBenchmarkSuiteOptions, type SelfImproveBudget, type SelfImproveOptions, type SelfImproveProgressEvent, type SelfImproveResult, SelfImproveRunError, type SessionScript, type SkillOptOptimizationMethodConfig, type SkillOptRunnerCommand, type SkillOptTrainerConfig, type SummarizeExecutionOptions, type SurfaceProposer, type TokenUsageInsight, analyzeRuns, buildDefaultAnalystRegistry, buildEvidenceVector, campaignSplitDigest, compareOptimizationMethods, composeGate, createChatClient, createReferenceEquivalenceJudge, defaultProductionGate, defineAgentEval, diffGenerations, diffRunBaselineToWinner, diffRuns, evalReportingSuite, evaluatePairedMeasurements, externalTextOptimizationMethod, fromClaudeCodeSession, fromCodexSession, fromFeedbackTable, fromKimiCodeSession, fromOpenCodeSession, fromOtelSpans, fromPiSession, fromPigraphSession, fromRunRecordDir, fsCampaignStorage, gepaOptimizationMethod, heldOutGate, inMemoryCampaignStorage, llmJudge, measuredComparisonFromCandidateExperiment, observeCodeAgentSession, paretoPolicy, paretoSignificanceGate, parseAgentTrace, parseCodeAgentJsonl, partitionRunsByAuthoringModel, runCampaign, runCandidateExperiment, runEval, runImprovementLoop, runReferenceEquivalenceJudge, sealCandidateBenchmarkSuite, sealCandidateBenchmarkTask, sealCandidateExperiment, selfImprove, skillOptOptimizationMethod, summarizeExecution, verifyCandidateBenchmarkSuite, verifyCandidateBenchmarkSuiteInputs, verifyCandidateBenchmarkTask, verifyCandidateExperiment, verifyCandidateExperimentComparison };
@@ -698,6 +698,7 @@ import {
698
698
  agentCandidateBenchmarkSuiteSchema,
699
699
  agentCandidateBenchmarkTaskSchema,
700
700
  agentCandidateBundleSchema,
701
+ agentCandidateEvaluationPolicySchema,
701
702
  agentCandidateExperimentSchema,
702
703
  agentImprovementMeasuredComparisonSchema,
703
704
  candidateExecutionEvidenceSchema,
@@ -800,19 +801,28 @@ async function runCandidateExperiment(options) {
800
801
  await Promise.all(lanes);
801
802
  return measurements;
802
803
  }
803
- function measuredComparisonFromCandidateExperiment(options) {
804
- const experiment = verifyCandidateExperiment(options.experiment);
804
+ function evaluatePairedMeasurements(options) {
805
+ if (options.measurements.length === 0) {
806
+ throw new Error("paired measurement evaluation requires at least one paired cell");
807
+ }
808
+ const additionalCostUsd = options.additionalCostUsd ?? 0;
809
+ if (!Number.isFinite(additionalCostUsd) || additionalCostUsd < 0) {
810
+ throw new Error("paired measurement evaluation additionalCostUsd must be a non-negative number");
811
+ }
812
+ if (typeof options.sharedScorerChannel !== "boolean") {
813
+ throw new Error("paired measurement evaluation sharedScorerChannel must be a boolean");
814
+ }
815
+ const policy = agentCandidateEvaluationPolicySchema.parse(options.policy);
805
816
  const measurements = options.measurements.map(
806
- (measurement, index) => verifyMeasurement(experiment, measurement, index)
817
+ (measurement, index) => projectPairedMeasurement(measurement, index, options.adapter)
807
818
  );
808
- const expectedN = experiment.benchmark.suite.taskDigests.length * experiment.benchmark.suite.reps;
809
- if (measurements.length !== expectedN) {
810
- throw new Error(
811
- `candidate experiment is incomplete (${measurements.length}/${expectedN} paired cells)`
812
- );
819
+ const cellIds2 = measurements.map((measurement) => measurement.cellId);
820
+ if (new Set(cellIds2).size !== cellIds2.length) {
821
+ throw new Error("paired measurement evaluation cell ids must be unique");
813
822
  }
814
- verifyStableProfileMaterialization(measurements);
815
- if (!options.runId.trim()) throw new Error("candidate experiment runId is required");
823
+ const dimensions = sharedProjectedDimensions(measurements);
824
+ const baselineScores = measurements.map((measurement) => measurement.baseline.score);
825
+ const candidateScores = measurements.map((measurement) => measurement.candidate.score);
816
826
  const {
817
827
  confidenceLevel: confidence,
818
828
  resamples,
@@ -822,15 +832,23 @@ function measuredComparisonFromCandidateExperiment(options) {
822
832
  budgetUsd,
823
833
  criticalDimensions,
824
834
  regressionTolerance
825
- } = experiment.policy;
826
- const baselineScores = measurements.map(scoreOf("baseline"));
827
- const candidateScores = measurements.map(scoreOf("candidate"));
835
+ } = policy;
836
+ const significance = heldoutSignificance(
837
+ { before: baselineScores, after: candidateScores, cellIds: cellIds2 },
838
+ {
839
+ confidence,
840
+ resamples,
841
+ seed: bootstrapSeed,
842
+ statistic: "mean",
843
+ deltaThreshold,
844
+ minProductiveRuns
845
+ }
846
+ );
828
847
  const overall = measuredEstimate(baselineScores, candidateScores, {
829
848
  confidence,
830
849
  resamples,
831
850
  seed: bootstrapSeed
832
851
  });
833
- const dimensions = sharedDimensions(measurements);
834
852
  const objectives = [
835
853
  {
836
854
  kind: "objective",
@@ -848,21 +866,33 @@ function measuredComparisonFromCandidateExperiment(options) {
848
866
  unit: "score",
849
867
  availability: "measured",
850
868
  ...measuredEstimate(
851
- measurements.map(dimensionOf("baseline", name)),
852
- measurements.map(dimensionOf("candidate", name)),
853
- { confidence, resamples, seed: bootstrapSeed + index + 1 }
869
+ measurements.map((measurement) => dimensionScore(measurement.baseline, name)),
870
+ measurements.map((measurement) => dimensionScore(measurement.candidate, name)),
871
+ {
872
+ confidence,
873
+ resamples,
874
+ seed: bootstrapSeed + index + 1
875
+ }
854
876
  )
855
877
  }))
856
878
  ];
857
879
  const cost = measuredEstimate(
858
- measurements.map(costOf("baseline")),
859
- measurements.map(costOf("candidate")),
860
- { confidence, resamples, seed: bootstrapSeed + dimensions.length + 1 }
880
+ measurements.map((measurement) => measurement.baseline.costUsd),
881
+ measurements.map((measurement) => measurement.candidate.costUsd),
882
+ {
883
+ confidence,
884
+ resamples,
885
+ seed: bootstrapSeed + dimensions.length + 1
886
+ }
861
887
  );
862
888
  const latency = measuredEstimate(
863
- measurements.map(latencyOf("baseline")),
864
- measurements.map(latencyOf("candidate")),
865
- { confidence, resamples, seed: bootstrapSeed + dimensions.length + 2 }
889
+ measurements.map((measurement) => measurement.baseline.latencyMs),
890
+ measurements.map((measurement) => measurement.candidate.latencyMs),
891
+ {
892
+ confidence,
893
+ resamples,
894
+ seed: bootstrapSeed + dimensions.length + 2
895
+ }
866
896
  );
867
897
  objectives.push(
868
898
  {
@@ -882,23 +912,12 @@ function measuredComparisonFromCandidateExperiment(options) {
882
912
  ...latency
883
913
  }
884
914
  );
885
- const significance = heldoutSignificance(
886
- { before: baselineScores, after: candidateScores, cellIds: cellIds(experiment) },
887
- {
888
- confidence,
889
- resamples,
890
- seed: bootstrapSeed,
891
- statistic: "mean",
892
- deltaThreshold,
893
- minProductiveRuns
894
- }
895
- );
896
915
  const power = baselineScores.length >= 3 ? powerPreflight({
897
916
  baselineComposites: baselineScores,
898
917
  pairedN: baselineScores.length,
899
918
  deltaThreshold,
900
919
  confidence,
901
- sharedScorerChannel: true
920
+ sharedScorerChannel: options.sharedScorerChannel
902
921
  }) : void 0;
903
922
  const powerSufficient = baselineScores.length >= minProductiveRuns && power !== void 0 && !power.underpowered;
904
923
  const guardedDimensions = new Set(criticalDimensions);
@@ -909,20 +928,21 @@ function measuredComparisonFromCandidateExperiment(options) {
909
928
  (objective) => objective.kind === "dimension" && guardedDimensions.has(objective.name) && objective.availability === "measured" && objective.confidenceInterval.lower < -regressionTolerance
910
929
  );
911
930
  const executionCostUsd = measurements.reduce(
912
- (sum, measurement) => sum + costFromEvidence(measurement.baseline) + costFromEvidence(measurement.candidate),
931
+ (sum, measurement) => sum + measurement.baseline.costUsd + measurement.candidate.costUsd,
932
+ 0
933
+ );
934
+ const executionDurationMs = measurements.reduce(
935
+ (sum, measurement) => sum + measurement.baseline.latencyMs + measurement.candidate.latencyMs,
913
936
  0
914
937
  );
915
- const searchCostUsd = options.searchCostUsd ?? 0;
916
- const totalCostUsd = executionCostUsd + searchCostUsd;
917
- const budgetPassed = budgetUsd === void 0 || totalCostUsd <= budgetUsd;
918
938
  const completedRuns = measurements.flatMap((measurement) => [
919
939
  measurement.baseline,
920
940
  measurement.candidate
921
941
  ]);
922
- const incompleteRuns = completedRuns.filter((evidence) => !completedSuccessfully(evidence));
923
- const failedCandidateResults = measurements.filter(
924
- (measurement) => !measurement.candidate.receipt.benchmarkResult.material.passed
925
- );
942
+ const incompleteRuns = completedRuns.filter((run) => !run.completed);
943
+ const failedCandidateResults = measurements.filter((measurement) => !measurement.candidate.passed);
944
+ const totalCostUsd = executionCostUsd + additionalCostUsd;
945
+ const budgetPassed = budgetUsd === void 0 || totalCostUsd <= budgetUsd;
926
946
  const checks = [
927
947
  { name: "paired-significance", passed: significance.significant },
928
948
  { name: "statistical-power", passed: powerSufficient },
@@ -946,17 +966,7 @@ function measuredComparisonFromCandidateExperiment(options) {
946
966
  ...failedCandidateResults.length === 0 ? [] : [`candidate failed ${failedCandidateResults.length} benchmark tasks`],
947
967
  ...budgetPassed ? [] : [`total cost ${totalCostUsd} exceeded budget ${budgetUsd}`]
948
968
  ];
949
- const diff = deriveCandidateBundleDiff(experiment);
950
- const executionDurationMs = measurements.reduce(
951
- (sum, measurement) => sum + latencyFromEvidence(measurement.baseline) + latencyFromEvidence(measurement.candidate),
952
- 0
953
- );
954
- const searchDurationMs = options.searchDurationMs ?? 0;
955
- const durationMs = executionDurationMs + searchDurationMs;
956
- const provisional = agentImprovementMeasuredComparisonSchema.parse({
957
- kind: "agent-improvement-measured-comparison",
958
- experiment,
959
- measurements,
969
+ return {
960
970
  overall: {
961
971
  name: "composite",
962
972
  direction: "higher-is-better",
@@ -964,7 +974,6 @@ function measuredComparisonFromCandidateExperiment(options) {
964
974
  ...overall
965
975
  },
966
976
  objectives,
967
- ...options.candidate ? { candidate: options.candidate } : {},
968
977
  decision: {
969
978
  outcome: shipped ? "ship" : significance.fewRuns || !powerSufficient ? "need_more_work" : "hold",
970
979
  reasons: reasons.length > 0 ? reasons : ["all measured checks passed"],
@@ -976,9 +985,51 @@ function measuredComparisonFromCandidateExperiment(options) {
976
985
  minimumDetectableDelta: power?.mde ?? 1,
977
986
  confidenceLevel: confidence,
978
987
  scaleAssumed: power?.scaleAssumed ?? true,
979
- sharedScorerChannel: true,
988
+ sharedScorerChannel: options.sharedScorerChannel,
980
989
  reason: power?.recommendation ?? `need at least ${Math.max(3, minProductiveRuns)} paired runs`
981
990
  },
991
+ executionCostUsd,
992
+ totalCostUsd,
993
+ executionDurationMs
994
+ };
995
+ }
996
+ function measuredComparisonFromCandidateExperiment(options) {
997
+ const experiment = verifyCandidateExperiment(options.experiment);
998
+ const measurements = options.measurements.map(
999
+ (measurement, index) => verifyMeasurement(experiment, measurement, index)
1000
+ );
1001
+ const expectedN = experiment.benchmark.suite.taskDigests.length * experiment.benchmark.suite.reps;
1002
+ if (measurements.length !== expectedN) {
1003
+ throw new Error(
1004
+ `candidate experiment is incomplete (${measurements.length}/${expectedN} paired cells)`
1005
+ );
1006
+ }
1007
+ verifyStableProfileMaterialization(measurements);
1008
+ if (!options.runId.trim()) throw new Error("candidate experiment runId is required");
1009
+ const searchCostUsd = options.searchCostUsd ?? 0;
1010
+ const evaluation = evaluatePairedMeasurements({
1011
+ measurements: measurements.map((measurement, index) => ({
1012
+ cellId: cellIds(experiment)[index],
1013
+ ...measurement
1014
+ })),
1015
+ policy: experiment.policy,
1016
+ adapter: candidateExecutionEvidenceAdapter,
1017
+ sharedScorerChannel: true,
1018
+ additionalCostUsd: searchCostUsd
1019
+ });
1020
+ const diff = deriveCandidateBundleDiff(experiment);
1021
+ const searchDurationMs = options.searchDurationMs ?? 0;
1022
+ const totalCostUsd = evaluation.totalCostUsd;
1023
+ const durationMs = evaluation.executionDurationMs + searchDurationMs;
1024
+ const provisional = agentImprovementMeasuredComparisonSchema.parse({
1025
+ kind: "agent-improvement-measured-comparison",
1026
+ experiment,
1027
+ measurements,
1028
+ overall: evaluation.overall,
1029
+ objectives: evaluation.objectives,
1030
+ ...options.candidate ? { candidate: options.candidate } : {},
1031
+ decision: evaluation.decision,
1032
+ power: evaluation.power,
982
1033
  provenance: {
983
1034
  kind: "agent-eval-loop",
984
1035
  schema: "agent-candidate-experiment",
@@ -991,10 +1042,10 @@ function measuredComparisonFromCandidateExperiment(options) {
991
1042
  evaluation: {
992
1043
  generationsExplored: options.generationsExplored ?? 0,
993
1044
  searchDurationMs,
994
- executionDurationMs,
1045
+ executionDurationMs: evaluation.executionDurationMs,
995
1046
  durationMs,
996
1047
  searchCostUsd,
997
- executionCostUsd,
1048
+ executionCostUsd: evaluation.executionCostUsd,
998
1049
  totalCostUsd
999
1050
  },
1000
1051
  ...options.metadata ? { metadata: options.metadata } : {}
@@ -1197,6 +1248,65 @@ function verifyMaterialAddressed(evidence, label) {
1197
1248
  throw new Error(`${label} digest is invalid`);
1198
1249
  }
1199
1250
  }
1251
+ function projectPairedMeasurement(measurement, index, adapter) {
1252
+ if (typeof measurement.cellId !== "string" || !measurement.cellId.trim()) {
1253
+ throw new Error(`paired measurement ${index} requires a cell id`);
1254
+ }
1255
+ return {
1256
+ cellId: measurement.cellId,
1257
+ baseline: projectRun(measurement.baseline, adapter, `paired measurement ${index} baseline`),
1258
+ candidate: projectRun(measurement.candidate, adapter, `paired measurement ${index} candidate`)
1259
+ };
1260
+ }
1261
+ function projectRun(run, adapter, label) {
1262
+ const suppliedDimensions = adapter.dimensions(run);
1263
+ if (!Array.isArray(suppliedDimensions)) {
1264
+ throw new Error(`${label} dimensions must be an array`);
1265
+ }
1266
+ const dimensions = /* @__PURE__ */ new Map();
1267
+ for (const dimension of suppliedDimensions) {
1268
+ if (typeof dimension.name !== "string" || !dimension.name.trim()) {
1269
+ throw new Error(`${label} contains an unnamed dimension`);
1270
+ }
1271
+ if (dimensions.has(dimension.name)) {
1272
+ throw new Error(`${label} repeats dimension '${dimension.name}'`);
1273
+ }
1274
+ dimensions.set(dimension.name, finiteMeasurement(dimension.score, `${label} ${dimension.name}`));
1275
+ }
1276
+ const completed = adapter.completed(run);
1277
+ const passed = adapter.passed(run);
1278
+ if (typeof completed !== "boolean" || typeof passed !== "boolean") {
1279
+ throw new Error(`${label} completion and pass values must be booleans`);
1280
+ }
1281
+ return {
1282
+ score: finiteMeasurement(adapter.score(run), `${label} score`),
1283
+ dimensions,
1284
+ costUsd: nonNegativeMeasurement(adapter.costUsd(run), `${label} cost`),
1285
+ latencyMs: nonNegativeMeasurement(adapter.latencyMs(run), `${label} latency`),
1286
+ completed,
1287
+ passed
1288
+ };
1289
+ }
1290
+ function sharedProjectedDimensions(measurements) {
1291
+ const expected = [...measurements[0].baseline.dimensions.keys()];
1292
+ for (const [index, measurement] of measurements.entries()) {
1293
+ for (const [arm, run] of [
1294
+ ["baseline", measurement.baseline],
1295
+ ["candidate", measurement.candidate]
1296
+ ]) {
1297
+ const actual = [...run.dimensions.keys()];
1298
+ if (JSON.stringify(actual) !== JSON.stringify(expected)) {
1299
+ throw new Error(`paired measurement ${index} ${arm} dimensions do not match the suite`);
1300
+ }
1301
+ }
1302
+ }
1303
+ return expected;
1304
+ }
1305
+ function dimensionScore(run, name) {
1306
+ const value = run.dimensions.get(name);
1307
+ if (value === void 0) throw new Error(`paired measurement is missing dimension '${name}'`);
1308
+ return value;
1309
+ }
1200
1310
  function measuredEstimate(baseline, candidate, options) {
1201
1311
  const bootstrap = pairedBootstrap(baseline, candidate, {
1202
1312
  confidence: options.confidence,
@@ -1222,46 +1332,22 @@ function measuredEstimate(baseline, candidate, options) {
1222
1332
  n: bootstrap.n
1223
1333
  };
1224
1334
  }
1225
- function sharedDimensions(measurements) {
1226
- const expected = dimensionNames(measurements[0]?.baseline);
1227
- for (const [index, measurement] of measurements.entries()) {
1228
- for (const [arm, evidence] of [
1229
- ["baseline", measurement.baseline],
1230
- ["candidate", measurement.candidate]
1231
- ]) {
1232
- const actual = dimensionNames(evidence);
1233
- if (JSON.stringify(actual) !== JSON.stringify(expected)) {
1234
- throw new Error(
1235
- `candidate experiment measurement ${index} ${arm} dimensions do not match the suite`
1236
- );
1237
- }
1238
- }
1239
- }
1240
- return expected;
1241
- }
1242
- function dimensionNames(evidence) {
1243
- return (evidence?.receipt.benchmarkResult.material.dimensions ?? []).map(
1244
- (dimension) => dimension.name
1245
- );
1246
- }
1247
- function scoreOf(arm) {
1248
- return (measurement) => measurement[arm].receipt.benchmarkResult.material.score;
1249
- }
1250
- function dimensionOf(arm, name) {
1251
- return (measurement) => {
1252
- const dimension = measurement[arm].receipt.benchmarkResult.material.dimensions.find(
1253
- (entry) => entry.name === name
1254
- );
1255
- if (!dimension) throw new Error(`candidate experiment is missing dimension '${name}'`);
1256
- return dimension.score;
1257
- };
1258
- }
1259
- function costOf(arm) {
1260
- return (measurement) => costFromEvidence(measurement[arm]);
1335
+ function finiteMeasurement(value, label) {
1336
+ if (!Number.isFinite(value)) throw new Error(`${label} must be finite`);
1337
+ return value;
1261
1338
  }
1262
- function latencyOf(arm) {
1263
- return (measurement) => latencyFromEvidence(measurement[arm]);
1339
+ function nonNegativeMeasurement(value, label) {
1340
+ if (!Number.isFinite(value) || value < 0) throw new Error(`${label} must be non-negative`);
1341
+ return value;
1264
1342
  }
1343
+ var candidateExecutionEvidenceAdapter = {
1344
+ score: (evidence) => evidence.receipt.benchmarkResult.material.score,
1345
+ dimensions: (evidence) => evidence.receipt.benchmarkResult.material.dimensions,
1346
+ costUsd: costFromEvidence,
1347
+ latencyMs: latencyFromEvidence,
1348
+ completed: completedSuccessfully,
1349
+ passed: (evidence) => evidence.receipt.benchmarkResult.material.passed
1350
+ };
1265
1351
  function costFromEvidence(evidence) {
1266
1352
  return combinedUsage(evidence).costUsdNanos / 1e9;
1267
1353
  }
@@ -1822,6 +1908,7 @@ export {
1822
1908
  diffRunBaselineToWinner,
1823
1909
  diffRuns,
1824
1910
  evalReportingSuite,
1911
+ evaluatePairedMeasurements,
1825
1912
  externalTextOptimizationMethod,
1826
1913
  fromClaudeCodeSession,
1827
1914
  fromCodexSession,