@tangle-network/agent-eval 0.120.4 → 0.122.0
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 +4 -16
- package/dist/analyst/index.d.ts +1 -0
- package/dist/analyst/index.js +4 -4
- 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 +6 -6
- package/dist/campaign/index.d.ts +16 -18
- package/dist/campaign/index.js +7 -5
- package/dist/{chunk-SQQED7ZH.js → chunk-3A246TSA.js} +2 -2
- package/dist/{chunk-NMN4WGSJ.js → chunk-4I2E3LLO.js} +2 -2
- package/dist/chunk-7VYEGHWF.js +1425 -0
- package/dist/chunk-7VYEGHWF.js.map +1 -0
- package/dist/{chunk-ZMXDQ4K7.js → chunk-JHOJHHU7.js} +5 -8
- package/dist/{chunk-ZMXDQ4K7.js.map → chunk-JHOJHHU7.js.map} +1 -1
- package/dist/{chunk-3XH4Y2SS.js → chunk-P62I523A.js} +5 -3
- package/dist/{chunk-3XH4Y2SS.js.map → chunk-P62I523A.js.map} +1 -1
- package/dist/{chunk-CVJP5TMD.js → chunk-PICTDURQ.js} +2 -2
- package/dist/{chunk-5BYTIDZ7.js → chunk-QWMPPZ3X.js} +2 -2
- package/dist/{chunk-5CVUPHJ4.js → chunk-S5TT5R3L.js} +2 -2
- package/dist/{chunk-ZTJPIIVI.js → chunk-TDHX3BVA.js} +160 -7
- package/dist/chunk-TDHX3BVA.js.map +1 -0
- package/dist/{chunk-7QBFOJ3E.js → chunk-VZ6VKOJT.js} +32 -211
- package/dist/chunk-VZ6VKOJT.js.map +1 -0
- package/dist/{chunk-SYV364BL.js → chunk-XDIRG3TO.js} +2 -2
- package/dist/cli.js +2 -2
- package/dist/contract/index.d.ts +118 -29
- package/dist/contract/index.js +552 -502
- package/dist/contract/index.js.map +1 -1
- package/dist/fuzz.js +1 -1
- package/dist/index.d.ts +7 -19
- package/dist/index.js +13 -11
- package/dist/index.js.map +1 -1
- package/dist/openapi.json +1 -1
- package/dist/rl.d.ts +5 -1
- package/dist/{run-campaign-75RTPVV5.js → run-campaign-HNFPJET4.js} +3 -3
- package/dist/wire/index.js +2 -2
- package/docs/eval-surface-map.md +1 -1
- package/package.json +2 -2
- package/dist/chunk-7QBFOJ3E.js.map +0 -1
- package/dist/chunk-HKUCJ437.js +0 -787
- package/dist/chunk-HKUCJ437.js.map +0 -1
- package/dist/chunk-ZTJPIIVI.js.map +0 -1
- /package/dist/{chunk-SQQED7ZH.js.map → chunk-3A246TSA.js.map} +0 -0
- /package/dist/{chunk-NMN4WGSJ.js.map → chunk-4I2E3LLO.js.map} +0 -0
- /package/dist/{chunk-CVJP5TMD.js.map → chunk-PICTDURQ.js.map} +0 -0
- /package/dist/{chunk-5BYTIDZ7.js.map → chunk-QWMPPZ3X.js.map} +0 -0
- /package/dist/{chunk-5CVUPHJ4.js.map → chunk-S5TT5R3L.js.map} +0 -0
- /package/dist/{chunk-SYV364BL.js.map → chunk-XDIRG3TO.js.map} +0 -0
- /package/dist/{run-campaign-75RTPVV5.js.map → run-campaign-HNFPJET4.js.map} +0 -0
package/dist/contract/index.js
CHANGED
|
@@ -5,23 +5,20 @@ 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";
|
|
13
14
|
import {
|
|
14
15
|
analyzeRuns,
|
|
15
16
|
summarizeExecution
|
|
16
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-3A246TSA.js";
|
|
17
18
|
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,36 +26,31 @@ 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-7QBFOJ3E.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,
|
|
52
44
|
inMemoryCampaignStorage,
|
|
53
45
|
resolveRunDir,
|
|
54
46
|
runCampaign
|
|
55
|
-
} from "../chunk-
|
|
47
|
+
} from "../chunk-XDIRG3TO.js";
|
|
56
48
|
import {
|
|
57
49
|
buildDefaultAnalystRegistry,
|
|
58
50
|
createChatClient
|
|
59
|
-
} from "../chunk-
|
|
51
|
+
} from "../chunk-QWMPPZ3X.js";
|
|
60
52
|
import "../chunk-HHWE3POT.js";
|
|
61
|
-
import "../chunk-
|
|
53
|
+
import "../chunk-S5TT5R3L.js";
|
|
62
54
|
import {
|
|
63
55
|
FileSystemOutcomeStore,
|
|
64
56
|
InMemoryOutcomeStore
|
|
@@ -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-ZMXDQ4K7.js";
|
|
64
|
+
import "../chunk-JHOJHHU7.js";
|
|
75
65
|
import "../chunk-VI2UW6B6.js";
|
|
76
66
|
import {
|
|
77
67
|
recordAggregateMeasurements,
|
|
@@ -548,555 +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
|
-
|
|
694
|
-
|
|
797
|
+
const searchDurationMs = options.searchDurationMs ?? 0;
|
|
798
|
+
const durationMs = executionDurationMs + searchDurationMs;
|
|
799
|
+
const provisional = agentImprovementMeasuredComparisonSchema.parse({
|
|
695
800
|
kind: "agent-improvement-measured-comparison",
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
candidateBundleDigest: options.candidateBundleDigest,
|
|
801
|
+
experiment,
|
|
802
|
+
measurements,
|
|
699
803
|
overall: {
|
|
700
804
|
name: "composite",
|
|
701
|
-
baseline: composite.baseline,
|
|
702
|
-
candidate: composite.candidate,
|
|
703
|
-
delta: composite.delta,
|
|
704
|
-
confidenceInterval: composite.confidenceInterval,
|
|
705
|
-
n: composite.n,
|
|
706
805
|
direction: "higher-is-better",
|
|
707
|
-
unit: "score"
|
|
806
|
+
unit: "score",
|
|
807
|
+
...overall
|
|
708
808
|
},
|
|
709
|
-
objectives
|
|
710
|
-
...
|
|
711
|
-
candidate: {
|
|
712
|
-
...result.winner.label ? { label: result.winner.label } : {},
|
|
713
|
-
...result.winner.rationale ? { rationale: result.winner.rationale } : {}
|
|
714
|
-
}
|
|
715
|
-
} : {},
|
|
809
|
+
objectives,
|
|
810
|
+
...options.candidate ? { candidate: options.candidate } : {},
|
|
716
811
|
decision: {
|
|
717
|
-
outcome:
|
|
718
|
-
reasons:
|
|
719
|
-
contributingChecks:
|
|
720
|
-
name: check.name,
|
|
721
|
-
passed: check.passed
|
|
722
|
-
}))
|
|
812
|
+
outcome: shipped ? "ship" : significance.fewRuns || !powerSufficient ? "need_more_work" : "hold",
|
|
813
|
+
reasons: reasons.length > 0 ? reasons : ["all measured checks passed"],
|
|
814
|
+
contributingChecks: checks
|
|
723
815
|
},
|
|
724
816
|
power: {
|
|
725
|
-
sufficient:
|
|
726
|
-
n:
|
|
727
|
-
minimumDetectableDelta: power
|
|
728
|
-
confidenceLevel:
|
|
729
|
-
scaleAssumed: power
|
|
730
|
-
sharedScorerChannel:
|
|
731
|
-
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`
|
|
732
824
|
},
|
|
733
825
|
provenance: {
|
|
734
826
|
kind: "agent-eval-loop",
|
|
735
|
-
schema:
|
|
736
|
-
runId:
|
|
737
|
-
recordDigest:
|
|
738
|
-
baselineContentHash,
|
|
739
|
-
candidateContentHash
|
|
827
|
+
schema: "agent-candidate-experiment",
|
|
828
|
+
runId: options.runId,
|
|
829
|
+
recordDigest: canonicalCandidateDigest({}),
|
|
830
|
+
baselineContentHash: experiment.baseline.digest,
|
|
831
|
+
candidateContentHash: experiment.candidate.digest
|
|
740
832
|
},
|
|
741
|
-
diff
|
|
833
|
+
diff,
|
|
742
834
|
evaluation: {
|
|
743
|
-
generationsExplored,
|
|
744
|
-
|
|
745
|
-
|
|
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 })
|
|
746
851
|
}
|
|
747
852
|
});
|
|
748
853
|
}
|
|
749
|
-
function
|
|
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
|
-
|
|
784
|
-
canonicalDigest({
|
|
785
|
-
expectedCells: coverage.expectedCellIds.length,
|
|
786
|
-
scorableCells: coverage.scorableCellIds.length,
|
|
787
|
-
unscorableCells: coverage.unscorableCells
|
|
788
|
-
}),
|
|
789
|
-
`candidate ${measured.surfaceHash} coverage`
|
|
790
|
-
);
|
|
791
|
-
assertMeasuredIdentity(
|
|
792
|
-
String(candidate.eligibleForPromotion),
|
|
793
|
-
String(coverage.complete),
|
|
794
|
-
`candidate ${measured.surfaceHash} eligibility`
|
|
795
|
-
);
|
|
796
|
-
assertMeasuredIdentity(
|
|
797
|
-
canonicalDigest(candidate.dimensions),
|
|
798
|
-
canonicalDigest(breakdown.dimensions),
|
|
799
|
-
`candidate ${measured.surfaceHash} dimensions`
|
|
800
|
-
);
|
|
801
|
-
assertMeasuredIdentity(
|
|
802
|
-
canonicalDigest(candidate.scenarios),
|
|
803
|
-
canonicalDigest(breakdown.scenarios),
|
|
804
|
-
`candidate ${measured.surfaceHash} scenarios`
|
|
805
|
-
);
|
|
806
|
-
}
|
|
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");
|
|
807
889
|
}
|
|
890
|
+
return changed.join("\n\n");
|
|
808
891
|
}
|
|
809
|
-
function
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
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");
|
|
816
900
|
}
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
for (const cellId of scorableCellIds) {
|
|
822
|
-
const cell = cellsById.get(cellId);
|
|
823
|
-
if (!cell) throw new Error(`measured campaign is missing scorable cell ${cellId}`);
|
|
824
|
-
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");
|
|
825
905
|
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
for (const cell of [baseline, candidate]) {
|
|
831
|
-
for (const [objective, score] of Object.entries(cell.judgeScores)) {
|
|
832
|
-
if (score.failed) continue;
|
|
833
|
-
qualityColumns.set(`objective:${objective}`, {
|
|
834
|
-
kind: "objective",
|
|
835
|
-
name: objective,
|
|
836
|
-
direction: "higher-is-better",
|
|
837
|
-
unit: "score"
|
|
838
|
-
});
|
|
839
|
-
for (const name of Object.keys(score.dimensions)) {
|
|
840
|
-
qualityColumns.set(`dimension:${objective}:${name}`, {
|
|
841
|
-
kind: "dimension",
|
|
842
|
-
objective,
|
|
843
|
-
name,
|
|
844
|
-
direction: "higher-is-better",
|
|
845
|
-
unit: "score"
|
|
846
|
-
});
|
|
847
|
-
}
|
|
848
|
-
}
|
|
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`);
|
|
849
910
|
}
|
|
850
|
-
}
|
|
851
|
-
return
|
|
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
|
-
|
|
879
|
-
|
|
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"
|
|
880
963
|
);
|
|
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
|
-
|
|
909
|
-
|
|
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"]
|
|
910
993
|
];
|
|
911
|
-
const
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
}
|
|
915
|
-
return paired.pairs.map((pair) => {
|
|
916
|
-
const baseline = pair.baseline.cell;
|
|
917
|
-
const candidate = pair.treatment.cell;
|
|
918
|
-
if (baseline.seed !== candidate.seed) {
|
|
919
|
-
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}`);
|
|
920
997
|
}
|
|
921
|
-
return [baseline, candidate];
|
|
922
|
-
});
|
|
923
|
-
}
|
|
924
|
-
function assertMeasuredCell(cell, receiptsById, receiptIdsByCell, runDir) {
|
|
925
|
-
if (!cell.scenarioId.trim() || !Number.isSafeInteger(cell.rep) || cell.rep < 0 || !Number.isSafeInteger(cell.seed) || cell.cellId !== measuredCellKey(cell)) {
|
|
926
|
-
throw new Error(`heldout cell '${cell.cellId}' has an invalid scenario/rep identity`);
|
|
927
998
|
}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
if (!cell.tokenUsage) {
|
|
931
|
-
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`);
|
|
932
1001
|
}
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
if (!Array.isArray(cell.costCallIds)) {
|
|
939
|
-
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;
|
|
940
1007
|
}
|
|
941
|
-
|
|
942
|
-
|
|
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`);
|
|
943
1011
|
}
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
if (
|
|
949
|
-
|
|
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
|
+
}
|
|
950
1031
|
}
|
|
951
|
-
return receipt;
|
|
952
|
-
});
|
|
953
|
-
assertMeasuredIdentity(
|
|
954
|
-
canonicalDigest([...cell.costCallIds].sort()),
|
|
955
|
-
canonicalDigest(
|
|
956
|
-
[
|
|
957
|
-
...receiptIdsByCell.get(receiptCellKey(runDir, cell.cellId, cell.scenarioId, cell.rep)) ?? []
|
|
958
|
-
].sort()
|
|
959
|
-
),
|
|
960
|
-
`heldout cell ${cell.cellId} cost receipt IDs`
|
|
961
|
-
);
|
|
962
|
-
const agentReceipts = linkedReceipts.filter((receipt) => receipt.channel === "agent");
|
|
963
|
-
if (agentReceipts.some((receipt) => receipt.error)) {
|
|
964
|
-
throw new Error(`measured cell ${cell.cellId} links a failed agent receipt`);
|
|
965
1032
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
agentReceipts.reduce((total, receipt) => total + receipt.inputTokens, 0),
|
|
975
|
-
`heldout cell ${cell.cellId} input receipts`
|
|
976
|
-
);
|
|
977
|
-
assertMeasuredNumber(
|
|
978
|
-
cell.tokenUsage.output,
|
|
979
|
-
agentReceipts.reduce((total, receipt) => total + receipt.outputTokens, 0),
|
|
980
|
-
`heldout cell ${cell.cellId} output receipts`
|
|
981
|
-
);
|
|
982
|
-
assertMeasuredNumber(
|
|
983
|
-
cell.tokenUsage.cached ?? 0,
|
|
984
|
-
agentReceipts.reduce((total, receipt) => total + (receipt.cachedTokens ?? 0), 0),
|
|
985
|
-
`heldout cell ${cell.cellId} cached receipts`
|
|
986
|
-
);
|
|
987
|
-
for (const [judge, score] of Object.entries(cell.judgeScores)) {
|
|
988
|
-
if (score.failed) {
|
|
989
|
-
throw new Error(`heldout cell ${cell.cellId} contains failed judge '${judge}'`);
|
|
990
|
-
}
|
|
991
|
-
finiteMeasuredValue(score.composite, `objective:${judge}`);
|
|
992
|
-
for (const [dimension, value] of Object.entries(score.dimensions)) {
|
|
993
|
-
finiteMeasuredValue(value, `dimension:${judge}:${dimension}`);
|
|
994
|
-
}
|
|
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`);
|
|
995
1041
|
}
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
const candidate = pairs.map(([, cell]) => finiteMeasuredValue(value(cell), key));
|
|
1002
|
-
const interval = pairedBootstrap(baseline, candidate, {
|
|
1003
|
-
confidence: 0.95,
|
|
1004
|
-
resamples: 2e3,
|
|
1042
|
+
}
|
|
1043
|
+
function measuredEstimate(baseline, candidate, options) {
|
|
1044
|
+
const bootstrap = pairedBootstrap(baseline, candidate, {
|
|
1045
|
+
confidence: options.confidence,
|
|
1046
|
+
resamples: options.resamples,
|
|
1005
1047
|
statistic: "mean",
|
|
1006
|
-
seed:
|
|
1048
|
+
seed: options.seed
|
|
1007
1049
|
});
|
|
1008
|
-
const baselineMean =
|
|
1009
|
-
const candidateMean =
|
|
1050
|
+
const baselineMean = mean(baseline);
|
|
1051
|
+
const candidateMean = mean(candidate);
|
|
1052
|
+
const delta = candidateMean - baselineMean;
|
|
1010
1053
|
return {
|
|
1011
|
-
...identity,
|
|
1012
|
-
availability: "measured",
|
|
1013
1054
|
baseline: baselineMean,
|
|
1014
1055
|
candidate: candidateMean,
|
|
1015
|
-
delta
|
|
1056
|
+
delta,
|
|
1016
1057
|
confidenceInterval: {
|
|
1017
|
-
level:
|
|
1018
|
-
lower:
|
|
1019
|
-
upper:
|
|
1058
|
+
level: bootstrap.confidence,
|
|
1059
|
+
lower: Math.min(bootstrap.low, delta),
|
|
1060
|
+
upper: Math.max(bootstrap.high, delta),
|
|
1020
1061
|
method: "paired-bootstrap",
|
|
1021
1062
|
statistic: "mean",
|
|
1022
|
-
resamples:
|
|
1063
|
+
resamples: bootstrap.resamples
|
|
1023
1064
|
},
|
|
1024
|
-
n:
|
|
1065
|
+
n: bootstrap.n
|
|
1025
1066
|
};
|
|
1026
1067
|
}
|
|
1027
|
-
function
|
|
1028
|
-
const
|
|
1029
|
-
const
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
)
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
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
|
+
}
|
|
1040
1082
|
}
|
|
1041
|
-
return
|
|
1083
|
+
return expected;
|
|
1042
1084
|
}
|
|
1043
|
-
function
|
|
1044
|
-
return
|
|
1085
|
+
function dimensionNames(evidence) {
|
|
1086
|
+
return (evidence?.receipt.benchmarkResult.material.dimensions ?? []).map(
|
|
1087
|
+
(dimension) => dimension.name
|
|
1088
|
+
);
|
|
1045
1089
|
}
|
|
1046
|
-
function
|
|
1047
|
-
return
|
|
1090
|
+
function scoreOf(arm) {
|
|
1091
|
+
return (measurement) => measurement[arm].receipt.benchmarkResult.material.score;
|
|
1048
1092
|
}
|
|
1049
|
-
function
|
|
1050
|
-
|
|
1051
|
-
|
|
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
|
+
};
|
|
1052
1101
|
}
|
|
1053
|
-
function
|
|
1054
|
-
|
|
1055
|
-
return value;
|
|
1102
|
+
function costOf(arm) {
|
|
1103
|
+
return (measurement) => costFromEvidence(measurement[arm]);
|
|
1056
1104
|
}
|
|
1057
|
-
function
|
|
1058
|
-
|
|
1059
|
-
throw new Error(`${name} must be a non-negative safe integer`);
|
|
1060
|
-
}
|
|
1061
|
-
return value;
|
|
1105
|
+
function latencyOf(arm) {
|
|
1106
|
+
return (measurement) => latencyFromEvidence(measurement[arm]);
|
|
1062
1107
|
}
|
|
1063
|
-
function
|
|
1064
|
-
|
|
1065
|
-
return values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
1108
|
+
function costFromEvidence(evidence) {
|
|
1109
|
+
return combinedUsage(evidence).costUsdNanos / 1e9;
|
|
1066
1110
|
}
|
|
1067
|
-
function
|
|
1068
|
-
|
|
1069
|
-
for (const byte of Buffer.from(value, "utf8")) {
|
|
1070
|
-
seed = Math.imul(seed ^ byte, 16777619) >>> 0;
|
|
1071
|
-
}
|
|
1072
|
-
return seed;
|
|
1111
|
+
function latencyFromEvidence(evidence) {
|
|
1112
|
+
return evidence.receipt.timing.durationMs + evidence.receipt.benchmarkResult.material.grading.timing.durationMs;
|
|
1073
1113
|
}
|
|
1074
|
-
function
|
|
1075
|
-
const
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
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
|
+
};
|
|
1079
1125
|
}
|
|
1080
|
-
function
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
const key = receiptCellKey(tags.runDir, tags.cellId, tags.scenarioId, tags.rep);
|
|
1092
|
-
const ids = idsByCell.get(key) ?? [];
|
|
1093
|
-
ids.push(receipt.callId);
|
|
1094
|
-
idsByCell.set(key, ids);
|
|
1095
|
-
}
|
|
1096
|
-
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;
|
|
1097
1137
|
}
|
|
1098
|
-
function
|
|
1099
|
-
return
|
|
1138
|
+
function abortError(signal) {
|
|
1139
|
+
return signal.reason instanceof Error ? signal.reason : new Error("candidate experiment aborted");
|
|
1100
1140
|
}
|
|
1101
1141
|
|
|
1102
1142
|
// src/contract/eval-reporting-suite.ts
|
|
@@ -1638,17 +1678,27 @@ export {
|
|
|
1638
1678
|
gepaProposer,
|
|
1639
1679
|
heldOutGate,
|
|
1640
1680
|
inMemoryCampaignStorage,
|
|
1641
|
-
|
|
1681
|
+
measuredComparisonFromCandidateExperiment,
|
|
1682
|
+
observeCodeAgentSession,
|
|
1642
1683
|
paretoPolicy,
|
|
1643
1684
|
paretoSignificanceGate,
|
|
1644
1685
|
parseAgentTrace,
|
|
1645
1686
|
parseCodeAgentJsonl,
|
|
1646
1687
|
partitionRunsByAuthoringModel,
|
|
1647
1688
|
runCampaign,
|
|
1689
|
+
runCandidateExperiment,
|
|
1648
1690
|
runEval,
|
|
1649
1691
|
runImprovementLoop,
|
|
1650
1692
|
runReferenceEquivalenceJudge,
|
|
1693
|
+
sealCandidateBenchmarkSuite,
|
|
1694
|
+
sealCandidateBenchmarkTask,
|
|
1695
|
+
sealCandidateExperiment,
|
|
1651
1696
|
selfImprove,
|
|
1652
|
-
summarizeExecution
|
|
1697
|
+
summarizeExecution,
|
|
1698
|
+
verifyCandidateBenchmarkSuite,
|
|
1699
|
+
verifyCandidateBenchmarkSuiteInputs,
|
|
1700
|
+
verifyCandidateBenchmarkTask,
|
|
1701
|
+
verifyCandidateExperiment,
|
|
1702
|
+
verifyCandidateExperimentComparison
|
|
1653
1703
|
};
|
|
1654
1704
|
//# sourceMappingURL=index.js.map
|