@tangle-network/agent-eval 0.121.0 → 0.122.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/dist/analyst/index.d.ts +1 -0
- package/dist/analyst/index.js +1 -1
- package/dist/belief-state/index.d.ts +43 -0
- package/dist/belief-state/index.js +48 -326
- package/dist/belief-state/index.js.map +1 -1
- package/dist/benchmarks/index.d.ts +5 -1
- package/dist/benchmarks/index.js +2 -2
- package/dist/campaign/index.d.ts +16 -3
- package/dist/campaign/index.js +4 -2
- package/dist/chunk-7VYEGHWF.js +1425 -0
- package/dist/chunk-7VYEGHWF.js.map +1 -0
- package/dist/{chunk-JM2SKQMS.js → chunk-P62I523A.js} +3 -1
- package/dist/{chunk-JM2SKQMS.js.map → chunk-P62I523A.js.map} +1 -1
- package/dist/{chunk-JN2FCO5W.js → chunk-TDHX3BVA.js} +157 -4
- package/dist/chunk-TDHX3BVA.js.map +1 -0
- package/dist/{chunk-32BZXMSO.js → chunk-VZ6VKOJT.js} +23 -160
- package/dist/chunk-VZ6VKOJT.js.map +1 -0
- package/dist/contract/index.d.ts +118 -14
- package/dist/contract/index.js +548 -497
- package/dist/contract/index.js.map +1 -1
- package/dist/index.d.ts +7 -19
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/openapi.json +1 -1
- package/dist/rl.d.ts +5 -1
- package/package.json +2 -2
- package/dist/chunk-32BZXMSO.js.map +0 -1
- package/dist/chunk-HKUCJ437.js +0 -787
- package/dist/chunk-HKUCJ437.js.map +0 -1
- package/dist/chunk-JN2FCO5W.js.map +0 -1
package/dist/contract/index.js
CHANGED
|
@@ -5,8 +5,9 @@ import {
|
|
|
5
5
|
fromOpenCodeSession,
|
|
6
6
|
fromPiSession,
|
|
7
7
|
fromPigraphSession,
|
|
8
|
+
observeCodeAgentSession,
|
|
8
9
|
parseCodeAgentJsonl
|
|
9
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-7VYEGHWF.js";
|
|
10
11
|
import {
|
|
11
12
|
createHostedClient
|
|
12
13
|
} from "../chunk-ZZUXHH3R.js";
|
|
@@ -18,10 +19,6 @@ import {
|
|
|
18
19
|
REFERENCE_EQUIVALENCE_INPUT_LIMITS,
|
|
19
20
|
REFERENCE_EQUIVALENCE_JUDGE_VERSION,
|
|
20
21
|
buildEvidenceVector,
|
|
21
|
-
buildLoopProvenanceRecord,
|
|
22
|
-
campaignBreakdown,
|
|
23
|
-
campaignMeanComposite,
|
|
24
|
-
canonicalDigest,
|
|
25
22
|
composeGate,
|
|
26
23
|
createReferenceEquivalenceJudge,
|
|
27
24
|
defaultProductionGate,
|
|
@@ -29,23 +26,18 @@ import {
|
|
|
29
26
|
evolutionaryProposer,
|
|
30
27
|
gepaProposer,
|
|
31
28
|
heldOutGate,
|
|
29
|
+
heldoutSignificance,
|
|
32
30
|
loopProvenanceArgsFromResult,
|
|
33
|
-
pairArms,
|
|
34
31
|
paretoPolicy,
|
|
35
32
|
paretoSignificanceGate,
|
|
36
33
|
powerPreflight,
|
|
37
|
-
renderSurfaceDiff,
|
|
38
34
|
runEval,
|
|
39
35
|
runImprovementLoop,
|
|
40
36
|
runReferenceEquivalenceJudge,
|
|
41
37
|
surfaceContentHash,
|
|
42
|
-
surfaceHash
|
|
43
|
-
|
|
44
|
-
} from "../chunk-32BZXMSO.js";
|
|
38
|
+
surfaceHash
|
|
39
|
+
} from "../chunk-VZ6VKOJT.js";
|
|
45
40
|
import {
|
|
46
|
-
assertCampaignSplitIdentity,
|
|
47
|
-
assertRealAgentReceipts,
|
|
48
|
-
campaignCoverage,
|
|
49
41
|
campaignSplitDigest,
|
|
50
42
|
createRunCostLedger,
|
|
51
43
|
fsCampaignStorage,
|
|
@@ -69,9 +61,7 @@ import "../chunk-DPZAEKA6.js";
|
|
|
69
61
|
import {
|
|
70
62
|
pairedBootstrap
|
|
71
63
|
} from "../chunk-PJQFMIOX.js";
|
|
72
|
-
import
|
|
73
|
-
CostLedger
|
|
74
|
-
} from "../chunk-JHOJHHU7.js";
|
|
64
|
+
import "../chunk-JHOJHHU7.js";
|
|
75
65
|
import "../chunk-VI2UW6B6.js";
|
|
76
66
|
import {
|
|
77
67
|
recordAggregateMeasurements,
|
|
@@ -548,554 +538,605 @@ function requirePositiveInteger(value, field) {
|
|
|
548
538
|
|
|
549
539
|
// src/contract/measured-comparison.ts
|
|
550
540
|
import {
|
|
551
|
-
|
|
541
|
+
agentCandidateBenchmarkSuiteSchema,
|
|
542
|
+
agentCandidateBenchmarkTaskSchema,
|
|
543
|
+
agentCandidateBundleSchema,
|
|
544
|
+
agentCandidateExperimentSchema,
|
|
545
|
+
agentImprovementMeasuredComparisonSchema,
|
|
546
|
+
candidateExecutionEvidenceSchema,
|
|
547
|
+
canonicalCandidateDigest,
|
|
548
|
+
omitTopLevelDigest
|
|
552
549
|
} from "@tangle-network/agent-interface";
|
|
553
|
-
function
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
const
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
550
|
+
function sealCandidateBenchmarkTask(material) {
|
|
551
|
+
return agentCandidateBenchmarkTaskSchema.parse({
|
|
552
|
+
...material,
|
|
553
|
+
digest: canonicalCandidateDigest(material)
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
function sealCandidateBenchmarkSuite(options) {
|
|
557
|
+
for (const task of options.tasks) verifyCandidateBenchmarkTask(task);
|
|
558
|
+
const material = {
|
|
559
|
+
kind: "agent-candidate-benchmark-suite",
|
|
560
|
+
digestAlgorithm: "rfc8785-sha256",
|
|
561
|
+
taskDigests: options.tasks.map((task) => task.digest),
|
|
562
|
+
reps: options.reps,
|
|
563
|
+
seeds: options.seeds
|
|
564
|
+
};
|
|
565
|
+
const suite = agentCandidateBenchmarkSuiteSchema.parse({
|
|
566
|
+
...material,
|
|
567
|
+
digest: canonicalCandidateDigest(material)
|
|
568
|
+
});
|
|
569
|
+
return { suite, tasks: options.tasks };
|
|
570
|
+
}
|
|
571
|
+
function sealCandidateExperiment(material) {
|
|
572
|
+
const parsed = agentCandidateExperimentSchema.parse({
|
|
573
|
+
...material,
|
|
574
|
+
digest: canonicalCandidateDigest(material)
|
|
575
|
+
});
|
|
576
|
+
return verifyCandidateExperiment(parsed);
|
|
577
|
+
}
|
|
578
|
+
function verifyCandidateExperiment(input) {
|
|
579
|
+
const experiment = agentCandidateExperimentSchema.parse(input);
|
|
580
|
+
verifySelfAddressed(experiment, "candidate experiment");
|
|
581
|
+
verifyBundle(experiment.baseline, "baseline bundle");
|
|
582
|
+
verifyBundle(experiment.candidate, "candidate bundle");
|
|
583
|
+
if (experiment.baseline.digest === experiment.candidate.digest) {
|
|
584
|
+
throw new Error("candidate experiment baseline and candidate bundles are identical");
|
|
585
|
+
}
|
|
586
|
+
verifyCandidateBenchmarkSuiteInputs(experiment.benchmark);
|
|
587
|
+
return experiment;
|
|
588
|
+
}
|
|
589
|
+
async function runCandidateExperiment(options) {
|
|
590
|
+
const experiment = verifyCandidateExperiment(options.experiment);
|
|
591
|
+
const { suite, tasks } = experiment.benchmark;
|
|
592
|
+
const maxConcurrency = options.maxConcurrency ?? 2;
|
|
593
|
+
if (!Number.isSafeInteger(maxConcurrency) || maxConcurrency < 1) {
|
|
594
|
+
throw new Error("candidate experiment maxConcurrency must be a positive integer");
|
|
595
|
+
}
|
|
596
|
+
const measurements = new Array(
|
|
597
|
+
suite.taskDigests.length * suite.reps
|
|
578
598
|
);
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
599
|
+
let nextIndex = 0;
|
|
600
|
+
const lanes = Array.from({ length: Math.min(maxConcurrency, measurements.length) }, async () => {
|
|
601
|
+
while (true) {
|
|
602
|
+
if (options.signal?.aborted) throw abortError(options.signal);
|
|
603
|
+
const index = nextIndex;
|
|
604
|
+
nextIndex += 1;
|
|
605
|
+
if (index >= measurements.length) return;
|
|
606
|
+
const taskIndex = Math.floor(index / suite.reps);
|
|
607
|
+
const repetition = index % suite.reps;
|
|
608
|
+
const task = tasks[taskIndex];
|
|
609
|
+
const seed = suite.seeds[index];
|
|
610
|
+
if (!task || seed === void 0) {
|
|
611
|
+
throw new Error(`candidate experiment cell ${index} has no signed task or seed`);
|
|
612
|
+
}
|
|
613
|
+
const benchmarkCell = {
|
|
614
|
+
suiteDigest: suite.digest,
|
|
615
|
+
taskIndex,
|
|
616
|
+
repetition
|
|
617
|
+
};
|
|
618
|
+
const [baseline, candidate] = await Promise.all([
|
|
619
|
+
options.execute({
|
|
620
|
+
experiment,
|
|
621
|
+
arm: "baseline",
|
|
622
|
+
bundle: experiment.baseline,
|
|
623
|
+
task,
|
|
624
|
+
benchmarkCell,
|
|
625
|
+
seed,
|
|
626
|
+
...options.signal ? { signal: options.signal } : {}
|
|
627
|
+
}),
|
|
628
|
+
options.execute({
|
|
629
|
+
experiment,
|
|
630
|
+
arm: "candidate",
|
|
631
|
+
bundle: experiment.candidate,
|
|
632
|
+
task,
|
|
633
|
+
benchmarkCell,
|
|
634
|
+
seed,
|
|
635
|
+
...options.signal ? { signal: options.signal } : {}
|
|
636
|
+
})
|
|
637
|
+
]);
|
|
638
|
+
const measurement = { baseline, candidate };
|
|
639
|
+
verifyMeasurement(experiment, measurement, index);
|
|
640
|
+
measurements[index] = measurement;
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
await Promise.all(lanes);
|
|
644
|
+
return measurements;
|
|
645
|
+
}
|
|
646
|
+
function measuredComparisonFromCandidateExperiment(options) {
|
|
647
|
+
const experiment = verifyCandidateExperiment(options.experiment);
|
|
648
|
+
const measurements = options.measurements.map(
|
|
649
|
+
(measurement, index) => verifyMeasurement(experiment, measurement, index)
|
|
582
650
|
);
|
|
583
|
-
const
|
|
651
|
+
const expectedN = experiment.benchmark.suite.taskDigests.length * experiment.benchmark.suite.reps;
|
|
652
|
+
if (measurements.length !== expectedN) {
|
|
653
|
+
throw new Error(
|
|
654
|
+
`candidate experiment is incomplete (${measurements.length}/${expectedN} paired cells)`
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
verifyStableProfileMaterialization(measurements);
|
|
658
|
+
if (!options.runId.trim()) throw new Error("candidate experiment runId is required");
|
|
659
|
+
const {
|
|
660
|
+
confidenceLevel: confidence,
|
|
661
|
+
resamples,
|
|
662
|
+
bootstrapSeed,
|
|
663
|
+
deltaThreshold,
|
|
664
|
+
minProductiveRuns,
|
|
665
|
+
budgetUsd,
|
|
666
|
+
criticalDimensions,
|
|
667
|
+
regressionTolerance
|
|
668
|
+
} = experiment.policy;
|
|
669
|
+
const baselineScores = measurements.map(scoreOf("baseline"));
|
|
670
|
+
const candidateScores = measurements.map(scoreOf("candidate"));
|
|
671
|
+
const overall = measuredEstimate(baselineScores, candidateScores, {
|
|
672
|
+
confidence,
|
|
673
|
+
resamples,
|
|
674
|
+
seed: bootstrapSeed
|
|
675
|
+
});
|
|
676
|
+
const dimensions = sharedDimensions(measurements);
|
|
677
|
+
const objectives = [
|
|
584
678
|
{
|
|
585
679
|
kind: "objective",
|
|
586
|
-
name: "
|
|
680
|
+
name: "benchmark-score",
|
|
587
681
|
direction: "higher-is-better",
|
|
588
|
-
unit: "score"
|
|
682
|
+
unit: "score",
|
|
683
|
+
availability: "measured",
|
|
684
|
+
...overall
|
|
589
685
|
},
|
|
590
|
-
|
|
591
|
-
|
|
686
|
+
...dimensions.map((name, index) => ({
|
|
687
|
+
kind: "dimension",
|
|
688
|
+
objective: "benchmark-score",
|
|
689
|
+
name,
|
|
690
|
+
direction: "higher-is-better",
|
|
691
|
+
unit: "score",
|
|
692
|
+
availability: "measured",
|
|
693
|
+
...measuredEstimate(
|
|
694
|
+
measurements.map(dimensionOf("baseline", name)),
|
|
695
|
+
measurements.map(dimensionOf("candidate", name)),
|
|
696
|
+
{ confidence, resamples, seed: bootstrapSeed + index + 1 }
|
|
697
|
+
)
|
|
698
|
+
}))
|
|
699
|
+
];
|
|
700
|
+
const cost = measuredEstimate(
|
|
701
|
+
measurements.map(costOf("baseline")),
|
|
702
|
+
measurements.map(costOf("candidate")),
|
|
703
|
+
{ confidence, resamples, seed: bootstrapSeed + dimensions.length + 1 }
|
|
592
704
|
);
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
const candidateContentHash = surfaceContentHash(result.winner.surface);
|
|
598
|
-
const canonicalDiff = baselineContentHash === candidateContentHash ? "" : renderSurfaceDiff(result.raw.winnerSurface, options.baselineSurface);
|
|
599
|
-
assertMeasuredIdentity(result.gateDecision, result.raw.gateResult.decision, "raw decision");
|
|
600
|
-
assertMeasuredIdentity(
|
|
601
|
-
candidateContentHash,
|
|
602
|
-
surfaceContentHash(result.raw.winnerSurface),
|
|
603
|
-
"raw winner surface"
|
|
705
|
+
const latency = measuredEstimate(
|
|
706
|
+
measurements.map(latencyOf("baseline")),
|
|
707
|
+
measurements.map(latencyOf("candidate")),
|
|
708
|
+
{ confidence, resamples, seed: bootstrapSeed + dimensions.length + 2 }
|
|
604
709
|
);
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
assertCompleteMeasuredCampaign(
|
|
623
|
-
result.raw.baselineCampaign,
|
|
624
|
-
"search baseline",
|
|
625
|
-
receiptsById,
|
|
626
|
-
receiptIdsByCell
|
|
710
|
+
objectives.push(
|
|
711
|
+
{
|
|
712
|
+
kind: "cost",
|
|
713
|
+
name: "cost",
|
|
714
|
+
direction: "lower-is-better",
|
|
715
|
+
unit: "usd",
|
|
716
|
+
availability: "measured",
|
|
717
|
+
...cost
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
kind: "latency",
|
|
721
|
+
name: "latency",
|
|
722
|
+
direction: "lower-is-better",
|
|
723
|
+
unit: "milliseconds",
|
|
724
|
+
availability: "measured",
|
|
725
|
+
...latency
|
|
726
|
+
}
|
|
627
727
|
);
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
);
|
|
639
|
-
pairMeasuredCells(result.raw.baselineOnHoldout.cells, result.raw.neutralizedOnHoldout.cells);
|
|
640
|
-
}
|
|
641
|
-
const rebuiltProvenance = buildLoopProvenanceRecord(
|
|
642
|
-
loopProvenanceArgsFromResult({
|
|
643
|
-
runId: result.provenance.runId,
|
|
644
|
-
runDir: result.provenance.runDir,
|
|
645
|
-
timestamp: result.provenance.timestamp,
|
|
646
|
-
baselineSurface: options.baselineSurface,
|
|
647
|
-
result: result.raw,
|
|
648
|
-
costReceipts: receipts,
|
|
649
|
-
totalCostUsd: result.totalCostUsd,
|
|
650
|
-
totalDurationMs: result.durationMs
|
|
651
|
-
})
|
|
728
|
+
const significance = heldoutSignificance(
|
|
729
|
+
{ before: baselineScores, after: candidateScores, cellIds: cellIds(experiment) },
|
|
730
|
+
{
|
|
731
|
+
confidence,
|
|
732
|
+
resamples,
|
|
733
|
+
seed: bootstrapSeed,
|
|
734
|
+
statistic: "mean",
|
|
735
|
+
deltaThreshold,
|
|
736
|
+
minProductiveRuns
|
|
737
|
+
}
|
|
652
738
|
);
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
739
|
+
const power = baselineScores.length >= 3 ? powerPreflight({
|
|
740
|
+
baselineComposites: baselineScores,
|
|
741
|
+
pairedN: baselineScores.length,
|
|
742
|
+
deltaThreshold,
|
|
743
|
+
confidence,
|
|
744
|
+
sharedScorerChannel: true
|
|
745
|
+
}) : void 0;
|
|
746
|
+
const powerSufficient = baselineScores.length >= minProductiveRuns && power !== void 0 && !power.underpowered;
|
|
747
|
+
const guardedDimensions = new Set(criticalDimensions);
|
|
748
|
+
const missingCriticalDimensions = criticalDimensions.filter(
|
|
749
|
+
(dimension) => !dimensions.includes(dimension)
|
|
657
750
|
);
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
rebuiltProvenance.evidence.holdout.splitDigest,
|
|
661
|
-
"benchmark heldout split"
|
|
751
|
+
const regressions = objectives.filter(
|
|
752
|
+
(objective) => objective.kind === "dimension" && guardedDimensions.has(objective.name) && objective.availability === "measured" && objective.confidenceInterval.lower < -regressionTolerance
|
|
662
753
|
);
|
|
663
|
-
const
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
assertMeasuredIdentity(
|
|
667
|
-
canonicalDigest(result.cost),
|
|
668
|
-
canonicalDigest(result.raw.cost),
|
|
669
|
-
"raw cost summary"
|
|
754
|
+
const executionCostUsd = measurements.reduce(
|
|
755
|
+
(sum, measurement) => sum + costFromEvidence(measurement.baseline) + costFromEvidence(measurement.candidate),
|
|
756
|
+
0
|
|
670
757
|
);
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
assertMeasuredIdentity(
|
|
682
|
-
canonicalDigest(result.cost),
|
|
683
|
-
canonicalDigest(receiptCost),
|
|
684
|
-
"cost receipt summary"
|
|
758
|
+
const searchCostUsd = options.searchCostUsd ?? 0;
|
|
759
|
+
const totalCostUsd = executionCostUsd + searchCostUsd;
|
|
760
|
+
const budgetPassed = budgetUsd === void 0 || totalCostUsd <= budgetUsd;
|
|
761
|
+
const completedRuns = measurements.flatMap((measurement) => [
|
|
762
|
+
measurement.baseline,
|
|
763
|
+
measurement.candidate
|
|
764
|
+
]);
|
|
765
|
+
const incompleteRuns = completedRuns.filter((evidence) => !completedSuccessfully(evidence));
|
|
766
|
+
const failedCandidateResults = measurements.filter(
|
|
767
|
+
(measurement) => !measurement.candidate.receipt.benchmarkResult.material.passed
|
|
685
768
|
);
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
769
|
+
const checks = [
|
|
770
|
+
{ name: "paired-significance", passed: significance.significant },
|
|
771
|
+
{ name: "statistical-power", passed: powerSufficient },
|
|
772
|
+
{ name: "all-runs-completed", passed: incompleteRuns.length === 0 },
|
|
773
|
+
{ name: "candidate-task-pass", passed: failedCandidateResults.length === 0 },
|
|
774
|
+
{
|
|
775
|
+
name: "critical-dimensions",
|
|
776
|
+
passed: regressions.length === 0 && missingCriticalDimensions.length === 0
|
|
777
|
+
},
|
|
778
|
+
{ name: "budget", passed: budgetPassed }
|
|
779
|
+
];
|
|
780
|
+
const shipped = checks.every((check) => check.passed);
|
|
781
|
+
const reasons = [
|
|
782
|
+
...significance.significant ? [] : [
|
|
783
|
+
significance.fewRuns ? `only ${significance.n} paired runs; ${minProductiveRuns} required` : `paired interval lower bound ${significance.bootstrap.low} did not clear ${deltaThreshold}`
|
|
784
|
+
],
|
|
785
|
+
...powerSufficient ? [] : [power?.recommendation ?? `need at least ${Math.max(3, minProductiveRuns)} paired runs`],
|
|
786
|
+
...regressions.length === 0 ? [] : [`critical dimensions regressed: ${regressions.map((entry) => entry.name).join(", ")}`],
|
|
787
|
+
...missingCriticalDimensions.length === 0 ? [] : [`critical dimensions missing: ${missingCriticalDimensions.join(", ")}`],
|
|
788
|
+
...incompleteRuns.length === 0 ? [] : [`${incompleteRuns.length} benchmark executions did not exit successfully`],
|
|
789
|
+
...failedCandidateResults.length === 0 ? [] : [`candidate failed ${failedCandidateResults.length} benchmark tasks`],
|
|
790
|
+
...budgetPassed ? [] : [`total cost ${totalCostUsd} exceeded budget ${budgetUsd}`]
|
|
791
|
+
];
|
|
792
|
+
const diff = deriveCandidateBundleDiff(experiment);
|
|
793
|
+
const executionDurationMs = measurements.reduce(
|
|
794
|
+
(sum, measurement) => sum + latencyFromEvidence(measurement.baseline) + latencyFromEvidence(measurement.candidate),
|
|
795
|
+
0
|
|
692
796
|
);
|
|
693
|
-
|
|
797
|
+
const searchDurationMs = options.searchDurationMs ?? 0;
|
|
798
|
+
const durationMs = executionDurationMs + searchDurationMs;
|
|
799
|
+
const provisional = agentImprovementMeasuredComparisonSchema.parse({
|
|
694
800
|
kind: "agent-improvement-measured-comparison",
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
candidateBundleDigest: options.candidateBundleDigest,
|
|
801
|
+
experiment,
|
|
802
|
+
measurements,
|
|
698
803
|
overall: {
|
|
699
804
|
name: "composite",
|
|
700
|
-
baseline: composite.baseline,
|
|
701
|
-
candidate: composite.candidate,
|
|
702
|
-
delta: composite.delta,
|
|
703
|
-
confidenceInterval: composite.confidenceInterval,
|
|
704
|
-
n: composite.n,
|
|
705
805
|
direction: "higher-is-better",
|
|
706
|
-
unit: "score"
|
|
806
|
+
unit: "score",
|
|
807
|
+
...overall
|
|
707
808
|
},
|
|
708
|
-
objectives
|
|
709
|
-
...
|
|
710
|
-
candidate: {
|
|
711
|
-
...result.winner.label ? { label: result.winner.label } : {},
|
|
712
|
-
...result.winner.rationale ? { rationale: result.winner.rationale } : {}
|
|
713
|
-
}
|
|
714
|
-
} : {},
|
|
809
|
+
objectives,
|
|
810
|
+
...options.candidate ? { candidate: options.candidate } : {},
|
|
715
811
|
decision: {
|
|
716
|
-
outcome:
|
|
717
|
-
reasons:
|
|
718
|
-
contributingChecks:
|
|
719
|
-
name: check.name,
|
|
720
|
-
passed: check.passed
|
|
721
|
-
}))
|
|
812
|
+
outcome: shipped ? "ship" : significance.fewRuns || !powerSufficient ? "need_more_work" : "hold",
|
|
813
|
+
reasons: reasons.length > 0 ? reasons : ["all measured checks passed"],
|
|
814
|
+
contributingChecks: checks
|
|
722
815
|
},
|
|
723
816
|
power: {
|
|
724
|
-
sufficient:
|
|
725
|
-
n:
|
|
726
|
-
minimumDetectableDelta: power
|
|
727
|
-
confidenceLevel:
|
|
728
|
-
scaleAssumed: power
|
|
729
|
-
sharedScorerChannel:
|
|
730
|
-
reason: power.
|
|
817
|
+
sufficient: powerSufficient,
|
|
818
|
+
n: baselineScores.length,
|
|
819
|
+
minimumDetectableDelta: power?.mde ?? 1,
|
|
820
|
+
confidenceLevel: confidence,
|
|
821
|
+
scaleAssumed: power?.scaleAssumed ?? true,
|
|
822
|
+
sharedScorerChannel: true,
|
|
823
|
+
reason: power?.recommendation ?? `need at least ${Math.max(3, minProductiveRuns)} paired runs`
|
|
731
824
|
},
|
|
732
825
|
provenance: {
|
|
733
826
|
kind: "agent-eval-loop",
|
|
734
|
-
schema:
|
|
735
|
-
runId:
|
|
736
|
-
recordDigest:
|
|
737
|
-
baselineContentHash,
|
|
738
|
-
candidateContentHash
|
|
827
|
+
schema: "agent-candidate-experiment",
|
|
828
|
+
runId: options.runId,
|
|
829
|
+
recordDigest: canonicalCandidateDigest({}),
|
|
830
|
+
baselineContentHash: experiment.baseline.digest,
|
|
831
|
+
candidateContentHash: experiment.candidate.digest
|
|
739
832
|
},
|
|
740
|
-
diff
|
|
833
|
+
diff,
|
|
741
834
|
evaluation: {
|
|
742
|
-
generationsExplored,
|
|
743
|
-
|
|
744
|
-
|
|
835
|
+
generationsExplored: options.generationsExplored ?? 0,
|
|
836
|
+
searchDurationMs,
|
|
837
|
+
executionDurationMs,
|
|
838
|
+
durationMs,
|
|
839
|
+
searchCostUsd,
|
|
840
|
+
executionCostUsd,
|
|
841
|
+
totalCostUsd
|
|
842
|
+
},
|
|
843
|
+
...options.metadata ? { metadata: options.metadata } : {}
|
|
844
|
+
});
|
|
845
|
+
const { recordDigest: _recordDigest, ...provenance } = provisional.provenance;
|
|
846
|
+
return agentImprovementMeasuredComparisonSchema.parse({
|
|
847
|
+
...provisional,
|
|
848
|
+
provenance: {
|
|
849
|
+
...provenance,
|
|
850
|
+
recordDigest: canonicalCandidateDigest({ ...provisional, provenance })
|
|
745
851
|
}
|
|
746
852
|
});
|
|
747
853
|
}
|
|
748
|
-
function
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
canonicalDigest({
|
|
784
|
-
expectedCells: coverage.expectedCellIds.length,
|
|
785
|
-
scorableCells: coverage.scorableCellIds.length,
|
|
786
|
-
unscorableCells: coverage.unscorableCells
|
|
787
|
-
}),
|
|
788
|
-
`candidate ${measured.surfaceHash} coverage`
|
|
789
|
-
);
|
|
790
|
-
assertMeasuredIdentity(
|
|
791
|
-
String(candidate.eligibleForPromotion),
|
|
792
|
-
String(coverage.complete),
|
|
793
|
-
`candidate ${measured.surfaceHash} eligibility`
|
|
794
|
-
);
|
|
795
|
-
assertMeasuredIdentity(
|
|
796
|
-
canonicalDigest(candidate.dimensions),
|
|
797
|
-
canonicalDigest(breakdown.dimensions),
|
|
798
|
-
`candidate ${measured.surfaceHash} dimensions`
|
|
799
|
-
);
|
|
800
|
-
assertMeasuredIdentity(
|
|
801
|
-
canonicalDigest(candidate.scenarios),
|
|
802
|
-
canonicalDigest(breakdown.scenarios),
|
|
803
|
-
`candidate ${measured.surfaceHash} scenarios`
|
|
804
|
-
);
|
|
805
|
-
}
|
|
854
|
+
function verifyCandidateExperimentComparison(input) {
|
|
855
|
+
const comparison = agentImprovementMeasuredComparisonSchema.parse(input);
|
|
856
|
+
const recomputed = measuredComparisonFromCandidateExperiment({
|
|
857
|
+
experiment: comparison.experiment,
|
|
858
|
+
measurements: comparison.measurements,
|
|
859
|
+
runId: comparison.provenance.runId,
|
|
860
|
+
...comparison.candidate ? { candidate: comparison.candidate } : {},
|
|
861
|
+
generationsExplored: comparison.evaluation.generationsExplored,
|
|
862
|
+
searchDurationMs: comparison.evaluation.searchDurationMs,
|
|
863
|
+
searchCostUsd: comparison.evaluation.searchCostUsd,
|
|
864
|
+
...comparison.metadata ? { metadata: comparison.metadata } : {}
|
|
865
|
+
});
|
|
866
|
+
if (canonicalCandidateDigest(recomputed) !== canonicalCandidateDigest(comparison)) {
|
|
867
|
+
throw new Error("candidate experiment comparison does not match its Runtime receipts");
|
|
868
|
+
}
|
|
869
|
+
return comparison;
|
|
870
|
+
}
|
|
871
|
+
function deriveCandidateBundleDiff(experiment) {
|
|
872
|
+
const surfaces = ["profile", "code", "execution", "knowledge", "memory"];
|
|
873
|
+
const changed = surfaces.flatMap((surface) => {
|
|
874
|
+
const baseline = experiment.baseline[surface] ?? null;
|
|
875
|
+
const candidate = experiment.candidate[surface] ?? null;
|
|
876
|
+
const baselineDigest = canonicalCandidateDigest(baseline);
|
|
877
|
+
const candidateDigest = canonicalCandidateDigest(candidate);
|
|
878
|
+
if (baselineDigest === candidateDigest) return [];
|
|
879
|
+
return [
|
|
880
|
+
[
|
|
881
|
+
`--- baseline/${surface} (${baselineDigest})`,
|
|
882
|
+
`+++ candidate/${surface} (${candidateDigest})`,
|
|
883
|
+
JSON.stringify({ baseline, candidate }, null, 2)
|
|
884
|
+
].join("\n")
|
|
885
|
+
];
|
|
886
|
+
});
|
|
887
|
+
if (changed.length === 0) {
|
|
888
|
+
throw new Error("candidate experiment has no changed candidate surface");
|
|
806
889
|
}
|
|
890
|
+
return changed.join("\n\n");
|
|
807
891
|
}
|
|
808
|
-
function
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
892
|
+
function verifyCandidateBenchmarkTask(input) {
|
|
893
|
+
const task = agentCandidateBenchmarkTaskSchema.parse(input);
|
|
894
|
+
verifySelfAddressed(task, "candidate benchmark task");
|
|
895
|
+
return task;
|
|
896
|
+
}
|
|
897
|
+
function verifyCandidateBenchmarkSuiteInputs(input) {
|
|
898
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
899
|
+
throw new Error("candidate benchmark suite inputs must be an object");
|
|
815
900
|
}
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
for (const cellId of scorableCellIds) {
|
|
821
|
-
const cell = cellsById.get(cellId);
|
|
822
|
-
if (!cell) throw new Error(`measured campaign is missing scorable cell ${cellId}`);
|
|
823
|
-
assertMeasuredCell(cell, receiptsById, receiptIdsByCell, campaign.runDir);
|
|
901
|
+
const candidate = input;
|
|
902
|
+
const suite = verifyCandidateBenchmarkSuite(candidate.suite);
|
|
903
|
+
if (!Array.isArray(candidate.tasks) || candidate.tasks.length !== suite.taskDigests.length) {
|
|
904
|
+
throw new Error("candidate benchmark suite task count does not match its signed digests");
|
|
824
905
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
for (const cell of [baseline, candidate]) {
|
|
830
|
-
for (const [objective, score] of Object.entries(cell.judgeScores)) {
|
|
831
|
-
if (score.failed) continue;
|
|
832
|
-
qualityColumns.set(`objective:${objective}`, {
|
|
833
|
-
kind: "objective",
|
|
834
|
-
name: objective,
|
|
835
|
-
direction: "higher-is-better",
|
|
836
|
-
unit: "score"
|
|
837
|
-
});
|
|
838
|
-
for (const name of Object.keys(score.dimensions)) {
|
|
839
|
-
qualityColumns.set(`dimension:${objective}:${name}`, {
|
|
840
|
-
kind: "dimension",
|
|
841
|
-
objective,
|
|
842
|
-
name,
|
|
843
|
-
direction: "higher-is-better",
|
|
844
|
-
unit: "score"
|
|
845
|
-
});
|
|
846
|
-
}
|
|
847
|
-
}
|
|
906
|
+
candidate.tasks.forEach((task, index) => {
|
|
907
|
+
const verified = verifyCandidateBenchmarkTask(task);
|
|
908
|
+
if (verified.digest !== suite.taskDigests[index]) {
|
|
909
|
+
throw new Error(`candidate benchmark task ${index} does not match the signed suite`);
|
|
848
910
|
}
|
|
849
|
-
}
|
|
850
|
-
return
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
911
|
+
});
|
|
912
|
+
return { suite, tasks: candidate.tasks };
|
|
913
|
+
}
|
|
914
|
+
function verifyCandidateBenchmarkSuite(input) {
|
|
915
|
+
const suite = agentCandidateBenchmarkSuiteSchema.parse(input);
|
|
916
|
+
verifySelfAddressed(suite, "candidate benchmark suite");
|
|
917
|
+
return suite;
|
|
918
|
+
}
|
|
919
|
+
function verifyBundle(input, label) {
|
|
920
|
+
const bundle = agentCandidateBundleSchema.parse(input);
|
|
921
|
+
verifySelfAddressed(bundle, label);
|
|
922
|
+
return bundle;
|
|
923
|
+
}
|
|
924
|
+
function verifyMeasurement(experiment, input, index) {
|
|
925
|
+
const suite = experiment.benchmark.suite;
|
|
926
|
+
const taskIndex = Math.floor(index / suite.reps);
|
|
927
|
+
const repetition = index % suite.reps;
|
|
928
|
+
const task = experiment.benchmark.tasks[taskIndex];
|
|
929
|
+
const seed = suite.seeds[index];
|
|
930
|
+
if (!task || seed === void 0) {
|
|
931
|
+
throw new Error(`candidate experiment measurement ${index} is outside the signed suite`);
|
|
932
|
+
}
|
|
933
|
+
const baseline = verifyExecutionEvidence(input.baseline);
|
|
934
|
+
const candidate = verifyExecutionEvidence(input.candidate);
|
|
935
|
+
for (const [arm, evidence] of [
|
|
936
|
+
["baseline", baseline],
|
|
937
|
+
["candidate", candidate]
|
|
938
|
+
]) {
|
|
939
|
+
const bundle = experiment[arm];
|
|
940
|
+
const materialization = evidence.materializationReceipt;
|
|
941
|
+
const plan = materialization.executionPlan.material;
|
|
942
|
+
const runCell = plan.runCell;
|
|
943
|
+
verifySelfAddressed(runCell, "candidate run cell");
|
|
944
|
+
if (runCell.experimentDigest !== experiment.digest || runCell.arm !== arm || runCell.bundleDigest !== bundle.digest || runCell.suiteDigest !== suite.digest || runCell.taskDigest !== task.digest || runCell.taskIndex !== taskIndex || runCell.repetition !== repetition || runCell.seed !== seed || runCell.attempt > task.attempt.maxAttempts || materialization.bundleDigest !== bundle.digest || materialization.benchmark.suite.digest !== suite.digest || materialization.benchmark.task.digest !== task.digest || materialization.codeKind !== bundle.code.kind || materialization.profileActivation.profilePlan.material.sourceProfileDigest !== canonicalCandidateDigest(bundle.profile) || evidence.receipt.runCellDigest !== runCell.digest || JSON.stringify(materialization.resolvedModel) !== JSON.stringify(task.model)) {
|
|
945
|
+
throw new Error(`candidate experiment measurement ${index} substituted its ${arm} arm`);
|
|
946
|
+
}
|
|
947
|
+
verifyTaskOutcome(task, evidence, index, arm);
|
|
948
|
+
}
|
|
949
|
+
const baselinePlan = baseline.materializationReceipt.executionPlan.material;
|
|
950
|
+
const candidatePlan = candidate.materializationReceipt.executionPlan.material;
|
|
951
|
+
if (baselinePlan.executionId === candidatePlan.executionId || baselinePlan.runCell.digest === candidatePlan.runCell.digest || baseline.materializationReceipt.digest === candidate.materializationReceipt.digest || baseline.receipt.digest === candidate.receipt.digest || baseline.digest === candidate.digest) {
|
|
952
|
+
throw new Error(`candidate experiment measurement ${index} reused one execution across arms`);
|
|
953
|
+
}
|
|
954
|
+
return { baseline, candidate };
|
|
955
|
+
}
|
|
956
|
+
function verifyExecutionEvidence(input) {
|
|
957
|
+
const evidence = candidateExecutionEvidenceSchema.parse(input);
|
|
958
|
+
verifySelfAddressed(evidence, "candidate execution evidence");
|
|
959
|
+
verifySelfAddressed(evidence.materializationReceipt, "candidate materialization receipt");
|
|
960
|
+
verifySelfAddressed(
|
|
961
|
+
evidence.materializationReceipt.profileActivation,
|
|
962
|
+
"candidate profile activation"
|
|
879
963
|
);
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
964
|
+
verifyMaterialAddressed(
|
|
965
|
+
evidence.materializationReceipt.profileActivation.profilePlan,
|
|
966
|
+
"candidate profile plan"
|
|
967
|
+
);
|
|
968
|
+
verifyMaterialAddressed(evidence.materializationReceipt.executionPlan, "candidate execution plan");
|
|
969
|
+
verifySelfAddressed(evidence.receipt, "candidate run receipt");
|
|
970
|
+
verifyMaterialAddressed(evidence.receipt.modelSettlement, "candidate model settlement");
|
|
971
|
+
verifyMaterialAddressed(evidence.receipt.taskOutcome, "candidate task outcome");
|
|
972
|
+
verifyMaterialAddressed(evidence.receipt.benchmarkResult, "candidate benchmark result");
|
|
973
|
+
return evidence;
|
|
974
|
+
}
|
|
975
|
+
function verifySelfAddressed(document, label) {
|
|
976
|
+
if (canonicalCandidateDigest(omitTopLevelDigest(document)) !== document.digest) {
|
|
977
|
+
throw new Error(`${label} digest is invalid`);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
function verifyTaskOutcome(task, evidence, index, arm) {
|
|
981
|
+
const outcome = evidence.receipt.taskOutcome.material.outcome;
|
|
982
|
+
const result = evidence.receipt.benchmarkResult.material;
|
|
983
|
+
const prefix = `candidate experiment measurement ${index} ${arm}`;
|
|
984
|
+
if (result.evidence.sha256 === task.grader.artifact.sha256) {
|
|
985
|
+
throw new Error(`${prefix} reused grader bytes as grading evidence`);
|
|
986
|
+
}
|
|
987
|
+
const usage = combinedUsage(evidence);
|
|
988
|
+
const usageChecks = [
|
|
989
|
+
[usage.modelCalls, task.limits.maxModelCalls, "model calls"],
|
|
990
|
+
[usage.inputTokens, task.limits.maxInputTokens, "input tokens"],
|
|
991
|
+
[usage.outputTokens, task.limits.maxOutputTokens, "output tokens"],
|
|
992
|
+
[usage.costUsdNanos, Math.round(task.limits.maxCostUsd * 1e9), "cost"]
|
|
909
993
|
];
|
|
910
|
-
const
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
}
|
|
914
|
-
return paired.pairs.map((pair) => {
|
|
915
|
-
const baseline = pair.baseline.cell;
|
|
916
|
-
const candidate = pair.treatment.cell;
|
|
917
|
-
if (baseline.seed !== candidate.seed) {
|
|
918
|
-
throw new Error(`heldout cell ${baseline.cellId} does not share one paired seed`);
|
|
994
|
+
for (const [actual, maximum, label] of usageChecks) {
|
|
995
|
+
if (actual > maximum) {
|
|
996
|
+
throw new Error(`${prefix} ${label} ${actual} exceeds the signed limit ${maximum}`);
|
|
919
997
|
}
|
|
920
|
-
return [baseline, candidate];
|
|
921
|
-
});
|
|
922
|
-
}
|
|
923
|
-
function assertMeasuredCell(cell, receiptsById, receiptIdsByCell, runDir) {
|
|
924
|
-
if (!cell.scenarioId.trim() || !Number.isSafeInteger(cell.rep) || cell.rep < 0 || !Number.isSafeInteger(cell.seed) || cell.cellId !== measuredCellKey(cell)) {
|
|
925
|
-
throw new Error(`heldout cell '${cell.cellId}' has an invalid scenario/rep identity`);
|
|
926
998
|
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
if (!cell.tokenUsage) {
|
|
930
|
-
throw new Error(`heldout cell ${cell.cellId} does not report token usage`);
|
|
999
|
+
if (outcome.kind !== task.outcome.kind) {
|
|
1000
|
+
throw new Error(`${prefix} returned an outcome outside the signed task contract`);
|
|
931
1001
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
if (!Array.isArray(cell.costCallIds)) {
|
|
938
|
-
throw new Error(`heldout cell ${cell.cellId} does not identify its cost receipts`);
|
|
1002
|
+
if (task.outcome.kind === "output") {
|
|
1003
|
+
if (outcome.kind !== "output" || outcome.spec.mediaType !== task.outcome.mediaType || outcome.spec.maxBytes !== task.outcome.maxBytes) {
|
|
1004
|
+
throw new Error(`${prefix} changed the signed output contract`);
|
|
1005
|
+
}
|
|
1006
|
+
return;
|
|
939
1007
|
}
|
|
940
|
-
|
|
941
|
-
|
|
1008
|
+
const repository = task.repository;
|
|
1009
|
+
if (outcome.kind !== "workspace" || repository === void 0 || outcome.baseRepository.identity !== repository.identity || outcome.baseRepository.rootIdentity !== repository.rootIdentity || outcome.baseRepository.commit !== repository.baseCommit || outcome.baseRepository.tree !== repository.baseTree) {
|
|
1010
|
+
throw new Error(`${prefix} did not start from the signed repository state`);
|
|
942
1011
|
}
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
if (
|
|
948
|
-
|
|
1012
|
+
}
|
|
1013
|
+
function verifyStableProfileMaterialization(measurements) {
|
|
1014
|
+
for (const arm of ["baseline", "candidate"]) {
|
|
1015
|
+
const expected = measurements[0]?.[arm].materializationReceipt.profileActivation;
|
|
1016
|
+
if (!expected) throw new Error("candidate experiment contains no profile materialization");
|
|
1017
|
+
const expectedDigest = canonicalCandidateDigest({
|
|
1018
|
+
profilePlanDigest: expected.profilePlan.digest,
|
|
1019
|
+
files: expected.files
|
|
1020
|
+
});
|
|
1021
|
+
for (const [index, measurement] of measurements.entries()) {
|
|
1022
|
+
const activation = measurement[arm].materializationReceipt.profileActivation;
|
|
1023
|
+
if (canonicalCandidateDigest({
|
|
1024
|
+
profilePlanDigest: activation.profilePlan.digest,
|
|
1025
|
+
files: activation.files
|
|
1026
|
+
}) !== expectedDigest) {
|
|
1027
|
+
throw new Error(
|
|
1028
|
+
`candidate experiment measurement ${index} ${arm} materialized a different profile`
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
949
1031
|
}
|
|
950
|
-
return receipt;
|
|
951
|
-
});
|
|
952
|
-
assertMeasuredIdentity(
|
|
953
|
-
canonicalDigest([...cell.costCallIds].sort()),
|
|
954
|
-
canonicalDigest(
|
|
955
|
-
[
|
|
956
|
-
...receiptIdsByCell.get(receiptCellKey(runDir, cell.cellId, cell.scenarioId, cell.rep)) ?? []
|
|
957
|
-
].sort()
|
|
958
|
-
),
|
|
959
|
-
`heldout cell ${cell.cellId} cost receipt IDs`
|
|
960
|
-
);
|
|
961
|
-
const agentReceipts = linkedReceipts.filter((receipt) => receipt.channel === "agent");
|
|
962
|
-
if (agentReceipts.some((receipt) => receipt.error)) {
|
|
963
|
-
throw new Error(`measured cell ${cell.cellId} links a failed agent receipt`);
|
|
964
1032
|
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
agentReceipts.reduce((total, receipt) => total + receipt.inputTokens, 0),
|
|
974
|
-
`heldout cell ${cell.cellId} input receipts`
|
|
975
|
-
);
|
|
976
|
-
assertMeasuredNumber(
|
|
977
|
-
cell.tokenUsage.output,
|
|
978
|
-
agentReceipts.reduce((total, receipt) => total + receipt.outputTokens, 0),
|
|
979
|
-
`heldout cell ${cell.cellId} output receipts`
|
|
980
|
-
);
|
|
981
|
-
assertMeasuredNumber(
|
|
982
|
-
cell.tokenUsage.cached ?? 0,
|
|
983
|
-
agentReceipts.reduce((total, receipt) => total + (receipt.cachedTokens ?? 0), 0),
|
|
984
|
-
`heldout cell ${cell.cellId} cached receipts`
|
|
985
|
-
);
|
|
986
|
-
for (const [judge, score] of Object.entries(cell.judgeScores)) {
|
|
987
|
-
if (score.failed) {
|
|
988
|
-
throw new Error(`heldout cell ${cell.cellId} contains failed judge '${judge}'`);
|
|
989
|
-
}
|
|
990
|
-
finiteMeasuredValue(score.composite, `objective:${judge}`);
|
|
991
|
-
for (const [dimension, value] of Object.entries(score.dimensions)) {
|
|
992
|
-
finiteMeasuredValue(value, `dimension:${judge}:${dimension}`);
|
|
993
|
-
}
|
|
1033
|
+
}
|
|
1034
|
+
function completedSuccessfully(evidence) {
|
|
1035
|
+
const termination = evidence.receipt.termination;
|
|
1036
|
+
return termination.kind === "exit" && termination.exitCode === 0;
|
|
1037
|
+
}
|
|
1038
|
+
function verifyMaterialAddressed(evidence, label) {
|
|
1039
|
+
if (canonicalCandidateDigest(evidence.material) !== evidence.digest) {
|
|
1040
|
+
throw new Error(`${label} digest is invalid`);
|
|
994
1041
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
const candidate = pairs.map(([, cell]) => finiteMeasuredValue(value(cell), key));
|
|
1001
|
-
const interval = pairedBootstrap(baseline, candidate, {
|
|
1002
|
-
confidence: 0.95,
|
|
1003
|
-
resamples: 2e3,
|
|
1042
|
+
}
|
|
1043
|
+
function measuredEstimate(baseline, candidate, options) {
|
|
1044
|
+
const bootstrap = pairedBootstrap(baseline, candidate, {
|
|
1045
|
+
confidence: options.confidence,
|
|
1046
|
+
resamples: options.resamples,
|
|
1004
1047
|
statistic: "mean",
|
|
1005
|
-
seed:
|
|
1048
|
+
seed: options.seed
|
|
1006
1049
|
});
|
|
1007
|
-
const baselineMean =
|
|
1008
|
-
const candidateMean =
|
|
1050
|
+
const baselineMean = mean(baseline);
|
|
1051
|
+
const candidateMean = mean(candidate);
|
|
1052
|
+
const delta = candidateMean - baselineMean;
|
|
1009
1053
|
return {
|
|
1010
|
-
...identity,
|
|
1011
|
-
availability: "measured",
|
|
1012
1054
|
baseline: baselineMean,
|
|
1013
1055
|
candidate: candidateMean,
|
|
1014
|
-
delta
|
|
1056
|
+
delta,
|
|
1015
1057
|
confidenceInterval: {
|
|
1016
|
-
level:
|
|
1017
|
-
lower:
|
|
1018
|
-
upper:
|
|
1058
|
+
level: bootstrap.confidence,
|
|
1059
|
+
lower: Math.min(bootstrap.low, delta),
|
|
1060
|
+
upper: Math.max(bootstrap.high, delta),
|
|
1019
1061
|
method: "paired-bootstrap",
|
|
1020
1062
|
statistic: "mean",
|
|
1021
|
-
resamples:
|
|
1063
|
+
resamples: bootstrap.resamples
|
|
1022
1064
|
},
|
|
1023
|
-
n:
|
|
1065
|
+
n: bootstrap.n
|
|
1024
1066
|
};
|
|
1025
1067
|
}
|
|
1026
|
-
function
|
|
1027
|
-
const
|
|
1028
|
-
const
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
)
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1068
|
+
function sharedDimensions(measurements) {
|
|
1069
|
+
const expected = dimensionNames(measurements[0]?.baseline);
|
|
1070
|
+
for (const [index, measurement] of measurements.entries()) {
|
|
1071
|
+
for (const [arm, evidence] of [
|
|
1072
|
+
["baseline", measurement.baseline],
|
|
1073
|
+
["candidate", measurement.candidate]
|
|
1074
|
+
]) {
|
|
1075
|
+
const actual = dimensionNames(evidence);
|
|
1076
|
+
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
|
|
1077
|
+
throw new Error(
|
|
1078
|
+
`candidate experiment measurement ${index} ${arm} dimensions do not match the suite`
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1039
1082
|
}
|
|
1040
|
-
return
|
|
1083
|
+
return expected;
|
|
1041
1084
|
}
|
|
1042
|
-
function
|
|
1043
|
-
return
|
|
1085
|
+
function dimensionNames(evidence) {
|
|
1086
|
+
return (evidence?.receipt.benchmarkResult.material.dimensions ?? []).map(
|
|
1087
|
+
(dimension) => dimension.name
|
|
1088
|
+
);
|
|
1044
1089
|
}
|
|
1045
|
-
function
|
|
1046
|
-
return
|
|
1090
|
+
function scoreOf(arm) {
|
|
1091
|
+
return (measurement) => measurement[arm].receipt.benchmarkResult.material.score;
|
|
1047
1092
|
}
|
|
1048
|
-
function
|
|
1049
|
-
|
|
1050
|
-
|
|
1093
|
+
function dimensionOf(arm, name) {
|
|
1094
|
+
return (measurement) => {
|
|
1095
|
+
const dimension = measurement[arm].receipt.benchmarkResult.material.dimensions.find(
|
|
1096
|
+
(entry) => entry.name === name
|
|
1097
|
+
);
|
|
1098
|
+
if (!dimension) throw new Error(`candidate experiment is missing dimension '${name}'`);
|
|
1099
|
+
return dimension.score;
|
|
1100
|
+
};
|
|
1051
1101
|
}
|
|
1052
|
-
function
|
|
1053
|
-
|
|
1054
|
-
return value;
|
|
1102
|
+
function costOf(arm) {
|
|
1103
|
+
return (measurement) => costFromEvidence(measurement[arm]);
|
|
1055
1104
|
}
|
|
1056
|
-
function
|
|
1057
|
-
|
|
1058
|
-
throw new Error(`${name} must be a non-negative safe integer`);
|
|
1059
|
-
}
|
|
1060
|
-
return value;
|
|
1105
|
+
function latencyOf(arm) {
|
|
1106
|
+
return (measurement) => latencyFromEvidence(measurement[arm]);
|
|
1061
1107
|
}
|
|
1062
|
-
function
|
|
1063
|
-
|
|
1064
|
-
return values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
1108
|
+
function costFromEvidence(evidence) {
|
|
1109
|
+
return combinedUsage(evidence).costUsdNanos / 1e9;
|
|
1065
1110
|
}
|
|
1066
|
-
function
|
|
1067
|
-
|
|
1068
|
-
for (const byte of Buffer.from(value, "utf8")) {
|
|
1069
|
-
seed = Math.imul(seed ^ byte, 16777619) >>> 0;
|
|
1070
|
-
}
|
|
1071
|
-
return seed;
|
|
1111
|
+
function latencyFromEvidence(evidence) {
|
|
1112
|
+
return evidence.receipt.timing.durationMs + evidence.receipt.benchmarkResult.material.grading.timing.durationMs;
|
|
1072
1113
|
}
|
|
1073
|
-
function
|
|
1074
|
-
const
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1114
|
+
function combinedUsage(evidence) {
|
|
1115
|
+
const candidate = evidence.receipt.modelSettlement.material.usage;
|
|
1116
|
+
const grader = evidence.receipt.benchmarkResult.material.grading.usage;
|
|
1117
|
+
return {
|
|
1118
|
+
inputTokens: candidate.inputTokens + grader.inputTokens,
|
|
1119
|
+
outputTokens: candidate.outputTokens + grader.outputTokens,
|
|
1120
|
+
cachedInputTokens: candidate.cachedInputTokens + grader.cachedInputTokens,
|
|
1121
|
+
reasoningTokens: candidate.reasoningTokens + grader.reasoningTokens,
|
|
1122
|
+
modelCalls: candidate.modelCalls + grader.modelCalls,
|
|
1123
|
+
costUsdNanos: candidate.costUsdNanos + grader.costUsdNanos
|
|
1124
|
+
};
|
|
1078
1125
|
}
|
|
1079
|
-
function
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
const key = receiptCellKey(tags.runDir, tags.cellId, tags.scenarioId, tags.rep);
|
|
1091
|
-
const ids = idsByCell.get(key) ?? [];
|
|
1092
|
-
ids.push(receipt.callId);
|
|
1093
|
-
idsByCell.set(key, ids);
|
|
1094
|
-
}
|
|
1095
|
-
return idsByCell;
|
|
1126
|
+
function cellIds(experiment) {
|
|
1127
|
+
const { suite, tasks } = experiment.benchmark;
|
|
1128
|
+
return suite.seeds.map((_, index) => {
|
|
1129
|
+
const taskIndex = Math.floor(index / suite.reps);
|
|
1130
|
+
const repetition = index % suite.reps;
|
|
1131
|
+
return `${tasks[taskIndex]?.scenario.id ?? taskIndex}:${repetition}`;
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
function mean(values) {
|
|
1135
|
+
if (values.length === 0) throw new Error("candidate experiment requires measured values");
|
|
1136
|
+
return values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
1096
1137
|
}
|
|
1097
|
-
function
|
|
1098
|
-
return
|
|
1138
|
+
function abortError(signal) {
|
|
1139
|
+
return signal.reason instanceof Error ? signal.reason : new Error("candidate experiment aborted");
|
|
1099
1140
|
}
|
|
1100
1141
|
|
|
1101
1142
|
// src/contract/eval-reporting-suite.ts
|
|
@@ -1637,17 +1678,27 @@ export {
|
|
|
1637
1678
|
gepaProposer,
|
|
1638
1679
|
heldOutGate,
|
|
1639
1680
|
inMemoryCampaignStorage,
|
|
1640
|
-
|
|
1681
|
+
measuredComparisonFromCandidateExperiment,
|
|
1682
|
+
observeCodeAgentSession,
|
|
1641
1683
|
paretoPolicy,
|
|
1642
1684
|
paretoSignificanceGate,
|
|
1643
1685
|
parseAgentTrace,
|
|
1644
1686
|
parseCodeAgentJsonl,
|
|
1645
1687
|
partitionRunsByAuthoringModel,
|
|
1646
1688
|
runCampaign,
|
|
1689
|
+
runCandidateExperiment,
|
|
1647
1690
|
runEval,
|
|
1648
1691
|
runImprovementLoop,
|
|
1649
1692
|
runReferenceEquivalenceJudge,
|
|
1693
|
+
sealCandidateBenchmarkSuite,
|
|
1694
|
+
sealCandidateBenchmarkTask,
|
|
1695
|
+
sealCandidateExperiment,
|
|
1650
1696
|
selfImprove,
|
|
1651
|
-
summarizeExecution
|
|
1697
|
+
summarizeExecution,
|
|
1698
|
+
verifyCandidateBenchmarkSuite,
|
|
1699
|
+
verifyCandidateBenchmarkSuiteInputs,
|
|
1700
|
+
verifyCandidateBenchmarkTask,
|
|
1701
|
+
verifyCandidateExperiment,
|
|
1702
|
+
verifyCandidateExperimentComparison
|
|
1652
1703
|
};
|
|
1653
1704
|
//# sourceMappingURL=index.js.map
|