@tangle-network/agent-eval 0.127.0 → 0.128.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 +15 -0
- package/README.md +4 -0
- package/dist/analyst/index.d.ts +5 -8
- package/dist/belief-state/index.d.ts +5 -8
- package/dist/benchmarks/index.js +7 -8
- package/dist/campaign/index.d.ts +16 -21
- package/dist/campaign/index.js +6 -7
- package/dist/{chunk-NL33OXEP.js → chunk-2JX3CFMB.js} +60 -5
- package/dist/chunk-2JX3CFMB.js.map +1 -0
- package/dist/{chunk-ZPUEEM5U.js → chunk-2MKQIFS4.js} +7 -3
- package/dist/chunk-2MKQIFS4.js.map +1 -0
- package/dist/{chunk-IN455XKS.js → chunk-7ZZMD7UK.js} +50 -2
- package/dist/chunk-7ZZMD7UK.js.map +1 -0
- package/dist/{chunk-OD5NQ2CS.js → chunk-BYT7ELPS.js} +6 -4
- package/dist/chunk-BYT7ELPS.js.map +1 -0
- package/dist/{chunk-IG35YDN3.js → chunk-DRYIUNWY.js} +11 -3
- package/dist/chunk-DRYIUNWY.js.map +1 -0
- package/dist/{chunk-X6VOPMLD.js → chunk-EOSZT7PL.js} +11 -7
- package/dist/chunk-EOSZT7PL.js.map +1 -0
- package/dist/{chunk-WED5KLZQ.js → chunk-EZJEIH2R.js} +2 -2
- package/dist/{chunk-UTA2TGC4.js → chunk-IHQDPH7D.js} +2 -2
- package/dist/{chunk-FA3MFYNA.js → chunk-NACAGYSY.js} +26 -17
- package/dist/chunk-NACAGYSY.js.map +1 -0
- package/dist/{chunk-65QETEKG.js → chunk-NKAGIDE2.js} +5 -5
- package/dist/{chunk-424XHVKV.js → chunk-NYLOYM6N.js} +2 -2
- package/dist/{chunk-CLELFRQG.js → chunk-TBL77AUT.js} +5 -7
- package/dist/chunk-TBL77AUT.js.map +1 -0
- package/dist/{chunk-PRB53E3J.js → chunk-UB2LOJ6Q.js} +6 -8
- package/dist/{chunk-PRB53E3J.js.map → chunk-UB2LOJ6Q.js.map} +1 -1
- package/dist/{chunk-IMGJZBFG.js → chunk-VLOATJQ2.js} +2 -2
- package/dist/{chunk-Y5CYOL42.js → chunk-XDWDC2MP.js} +43 -14
- package/dist/chunk-XDWDC2MP.js.map +1 -0
- package/dist/{chunk-ARCFIY7U.js → chunk-XPRT64IE.js} +2 -2
- package/dist/contract/index.d.ts +25 -22
- package/dist/contract/index.js +37 -18
- package/dist/contract/index.js.map +1 -1
- package/dist/control.d.ts +26 -11
- package/dist/control.js +2 -3
- package/dist/hosted/index.d.ts +13 -13
- package/dist/hosted/index.js +2 -1
- package/dist/index.d.ts +40 -27
- package/dist/index.js +63 -33
- package/dist/index.js.map +1 -1
- package/dist/meta-eval/index.d.ts +5 -8
- package/dist/openapi.json +1 -1
- package/dist/reporting.d.ts +8 -10
- package/dist/reporting.js +4 -3
- package/dist/rl.d.ts +25 -15
- package/dist/rl.js +9 -7
- package/dist/rl.js.map +1 -1
- package/dist/rollout/index.d.ts +5 -8
- package/dist/rollout/index.js +2 -3
- package/dist/{run-campaign-3A2EBYBE.js → run-campaign-ISHFZ7FJ.js} +5 -3
- package/dist/traces.d.ts +10 -13
- package/dist/traces.js +3 -4
- package/docs/customer-journeys.md +7 -6
- package/docs/insight-report.md +21 -0
- package/package.json +1 -1
- package/dist/chunk-CLELFRQG.js.map +0 -1
- package/dist/chunk-FA3MFYNA.js.map +0 -1
- package/dist/chunk-IG35YDN3.js.map +0 -1
- package/dist/chunk-IN455XKS.js.map +0 -1
- package/dist/chunk-NL33OXEP.js.map +0 -1
- package/dist/chunk-OD5NQ2CS.js.map +0 -1
- package/dist/chunk-VSMTAMNK.js +0 -53
- package/dist/chunk-VSMTAMNK.js.map +0 -1
- package/dist/chunk-X6VOPMLD.js.map +0 -1
- package/dist/chunk-Y5CYOL42.js.map +0 -1
- package/dist/chunk-ZPUEEM5U.js.map +0 -1
- /package/dist/{chunk-WED5KLZQ.js.map → chunk-EZJEIH2R.js.map} +0 -0
- /package/dist/{chunk-UTA2TGC4.js.map → chunk-IHQDPH7D.js.map} +0 -0
- /package/dist/{chunk-65QETEKG.js.map → chunk-NKAGIDE2.js.map} +0 -0
- /package/dist/{chunk-424XHVKV.js.map → chunk-NYLOYM6N.js.map} +0 -0
- /package/dist/{chunk-IMGJZBFG.js.map → chunk-VLOATJQ2.js.map} +0 -0
- /package/dist/{chunk-ARCFIY7U.js.map → chunk-XPRT64IE.js.map} +0 -0
- /package/dist/{run-campaign-3A2EBYBE.js.map → run-campaign-ISHFZ7FJ.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,21 @@ All notable changes to `@tangle-network/agent-eval` and its sibling `agent-eval-
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [0.128.0] - 2026-07-25 - canonical task failure evidence
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Both OTel run-record import paths read `tangle.task.failure_class` and `tangle.task.failure_mode` from process roots.
|
|
12
|
+
- Invalid or conflicting root labels fail loudly, and child-span labels cannot become task failures.
|
|
13
|
+
- `failureMode` is valid only as detail under a non-success `failureClass`.
|
|
14
|
+
- Product benchmark rows expose canonical `failureClass` plus optional `failureDetail`; failed rows cannot omit classification.
|
|
15
|
+
- `InsightReport.failureClasses` replaces `failureModes`; each row exposes `failureClass`, `count`, and `share`.
|
|
16
|
+
- `ReleaseConfidenceMetrics.failureClassCounts` replaces `failureModeCounts`, and direct trace evidence accepts canonical `failureClass` instead of free-form `failureMode`.
|
|
17
|
+
- Analysis and release decisions validate every `RunRecord`; campaign projections validate before returning.
|
|
18
|
+
- `selfImprove()` uses the concrete model from paid-call receipts, or the new `model` option for unmetered agents, instead of writing a fabricated campaign model.
|
|
19
|
+
- Failed control stop decisions can supply a canonical failure class that is preserved in the result.
|
|
20
|
+
- A control stop that omits `pass` is recorded as a failed task with an `unknown` class.
|
|
21
|
+
|
|
7
22
|
## [0.127.0] - 2026-07-25 - explicit run evidence and truthful release checks
|
|
8
23
|
|
|
9
24
|
### Changed
|
package/README.md
CHANGED
|
@@ -316,6 +316,7 @@ const proposer: SurfaceProposer = {
|
|
|
316
316
|
const result = await defineAgentEval({
|
|
317
317
|
scenarios,
|
|
318
318
|
agent,
|
|
319
|
+
model: 'gpt-4.1-2025-04-14',
|
|
319
320
|
judge,
|
|
320
321
|
baselineSurface,
|
|
321
322
|
proposer,
|
|
@@ -323,6 +324,9 @@ const result = await defineAgentEval({
|
|
|
323
324
|
}).improve()
|
|
324
325
|
```
|
|
325
326
|
|
|
327
|
+
`model` supplies the worker snapshot when the agent does not report paid calls through `ctx.cost.runPaidCall()`.
|
|
328
|
+
When every cell reports a concrete model receipt, omit it.
|
|
329
|
+
|
|
326
330
|
Run the complete offline example:
|
|
327
331
|
|
|
328
332
|
```sh
|
package/dist/analyst/index.d.ts
CHANGED
|
@@ -600,15 +600,12 @@ interface RunRecord {
|
|
|
600
600
|
/** Per-split scores + raw bag. */
|
|
601
601
|
outcome: RunOutcome;
|
|
602
602
|
/** Canonical task-failure class drawn from the shared
|
|
603
|
-
* `FAILURE_CLASSES` taxonomy.
|
|
604
|
-
*
|
|
605
|
-
*
|
|
606
|
-
* set it only from task-result evidence. Execution errors belong in
|
|
607
|
-
* `outcome.raw.execution_error_count`, even when the run later fails. */
|
|
603
|
+
* `FAILURE_CLASSES` taxonomy. Producers set it only from task-result
|
|
604
|
+
* evidence. Execution errors belong in
|
|
605
|
+
* `outcome.raw.execution_error_count`. */
|
|
608
606
|
failureClass?: FailureClass;
|
|
609
|
-
/** Free-form task-failure detail
|
|
610
|
-
*
|
|
611
|
-
* Do not populate this from a child execution error alone. */
|
|
607
|
+
/** Free-form task-failure detail scoped under a non-success
|
|
608
|
+
* `failureClass`. It is invalid without that class. */
|
|
612
609
|
failureMode?: string;
|
|
613
610
|
/** Which split this run was drawn from. */
|
|
614
611
|
splitTag: RunSplitTag;
|
|
@@ -800,15 +800,12 @@ interface RunRecord {
|
|
|
800
800
|
/** Per-split scores + raw bag. */
|
|
801
801
|
outcome: RunOutcome;
|
|
802
802
|
/** Canonical task-failure class drawn from the shared
|
|
803
|
-
* `FAILURE_CLASSES` taxonomy.
|
|
804
|
-
*
|
|
805
|
-
*
|
|
806
|
-
* set it only from task-result evidence. Execution errors belong in
|
|
807
|
-
* `outcome.raw.execution_error_count`, even when the run later fails. */
|
|
803
|
+
* `FAILURE_CLASSES` taxonomy. Producers set it only from task-result
|
|
804
|
+
* evidence. Execution errors belong in
|
|
805
|
+
* `outcome.raw.execution_error_count`. */
|
|
808
806
|
failureClass?: FailureClass;
|
|
809
|
-
/** Free-form task-failure detail
|
|
810
|
-
*
|
|
811
|
-
* Do not populate this from a child execution error alone. */
|
|
807
|
+
/** Free-form task-failure detail scoped under a non-success
|
|
808
|
+
* `failureClass`. It is invalid without that class. */
|
|
812
809
|
failureMode?: string;
|
|
813
810
|
/** Which split this run was drawn from. */
|
|
814
811
|
splitTag: RunSplitTag;
|
package/dist/benchmarks/index.js
CHANGED
|
@@ -16,13 +16,13 @@ import {
|
|
|
16
16
|
routing_exports,
|
|
17
17
|
runBenchmarkAdapter,
|
|
18
18
|
summarizeBenchmarkCampaign
|
|
19
|
-
} from "../chunk-
|
|
20
|
-
import "../chunk-
|
|
21
|
-
import "../chunk-
|
|
22
|
-
import "../chunk-
|
|
19
|
+
} from "../chunk-XPRT64IE.js";
|
|
20
|
+
import "../chunk-UB2LOJ6Q.js";
|
|
21
|
+
import "../chunk-NKAGIDE2.js";
|
|
22
|
+
import "../chunk-EZJEIH2R.js";
|
|
23
23
|
import "../chunk-WGXIEX7P.js";
|
|
24
|
-
import "../chunk-
|
|
25
|
-
import "../chunk-
|
|
24
|
+
import "../chunk-NYLOYM6N.js";
|
|
25
|
+
import "../chunk-2MKQIFS4.js";
|
|
26
26
|
import "../chunk-PBE2LOSS.js";
|
|
27
27
|
import "../chunk-DPUHNQLN.js";
|
|
28
28
|
import "../chunk-MHELPNRP.js";
|
|
@@ -32,9 +32,8 @@ import "../chunk-5DTSBUL2.js";
|
|
|
32
32
|
import "../chunk-GGE4NNQT.js";
|
|
33
33
|
import "../chunk-P6FYH6K4.js";
|
|
34
34
|
import "../chunk-PC4UYEBM.js";
|
|
35
|
-
import "../chunk-
|
|
35
|
+
import "../chunk-2JX3CFMB.js";
|
|
36
36
|
import "../chunk-MA6HLL3S.js";
|
|
37
|
-
import "../chunk-VSMTAMNK.js";
|
|
38
37
|
import "../chunk-ONWEPEDO.js";
|
|
39
38
|
import "../chunk-K4DBDHLK.js";
|
|
40
39
|
import "../chunk-PZ5AY32C.js";
|
package/dist/campaign/index.d.ts
CHANGED
|
@@ -603,15 +603,12 @@ interface RunRecord {
|
|
|
603
603
|
/** Per-split scores + raw bag. */
|
|
604
604
|
outcome: RunOutcome;
|
|
605
605
|
/** Canonical task-failure class drawn from the shared
|
|
606
|
-
* `FAILURE_CLASSES` taxonomy.
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
* set it only from task-result evidence. Execution errors belong in
|
|
610
|
-
* `outcome.raw.execution_error_count`, even when the run later fails. */
|
|
606
|
+
* `FAILURE_CLASSES` taxonomy. Producers set it only from task-result
|
|
607
|
+
* evidence. Execution errors belong in
|
|
608
|
+
* `outcome.raw.execution_error_count`. */
|
|
611
609
|
failureClass?: FailureClass;
|
|
612
|
-
/** Free-form task-failure detail
|
|
613
|
-
*
|
|
614
|
-
* Do not populate this from a child execution error alone. */
|
|
610
|
+
/** Free-form task-failure detail scoped under a non-success
|
|
611
|
+
* `failureClass`. It is invalid without that class. */
|
|
615
612
|
failureMode?: string;
|
|
616
613
|
/** Which split this run was drawn from. */
|
|
617
614
|
splitTag: RunSplitTag;
|
|
@@ -4999,10 +4996,10 @@ interface InsightReport {
|
|
|
4999
4996
|
* Surfaced metrics: composite, cost, duration, tokenUsage, plus any
|
|
5000
4997
|
* per-dimension judge metric present in both windows. */
|
|
5001
4998
|
priorPeriodComparison?: PriorPeriodComparison;
|
|
5002
|
-
/** Model-free task-failure breakdown from `RunRecord.failureClass
|
|
5003
|
-
*
|
|
5004
|
-
*
|
|
5005
|
-
|
|
4999
|
+
/** Model-free task-failure breakdown from `RunRecord.failureClass`, ranked
|
|
5000
|
+
* by count descending. Domain-specific `failureMode` detail is retained on
|
|
5001
|
+
* each record but never creates a second aggregation vocabulary. */
|
|
5002
|
+
failureClasses?: FailureClassTally[];
|
|
5006
5003
|
/** Top-N actionable recommendations, ranked by priority. The packet's
|
|
5007
5004
|
* human-readable layer; the numeric sections are the evidence. */
|
|
5008
5005
|
recommendations: Recommendation[];
|
|
@@ -5210,15 +5207,13 @@ interface FailureClusterInsight {
|
|
|
5210
5207
|
}>;
|
|
5211
5208
|
totalFailures: number;
|
|
5212
5209
|
}
|
|
5213
|
-
/** Model-free failure breakdown over
|
|
5214
|
-
*
|
|
5215
|
-
*
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
/**
|
|
5220
|
-
mode: string;
|
|
5221
|
-
/** Number of runs carrying this tag. */
|
|
5210
|
+
/** Model-free task-failure breakdown over canonical `RunRecord.failureClass`
|
|
5211
|
+
* values. Unlike semantic failure clusters, this is computed directly from
|
|
5212
|
+
* run records and does not require a model analyst. */
|
|
5213
|
+
interface FailureClassTally {
|
|
5214
|
+
/** Canonical task-failure class. */
|
|
5215
|
+
failureClass: FailureClass;
|
|
5216
|
+
/** Number of failed runs carrying this class. */
|
|
5222
5217
|
count: number;
|
|
5223
5218
|
/** Share of the whole corpus, 0..1. */
|
|
5224
5219
|
share: number;
|
package/dist/campaign/index.js
CHANGED
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
userStoryScoreboard,
|
|
33
33
|
validateSearchLedgerEvent,
|
|
34
34
|
verifyCodeSurface
|
|
35
|
-
} from "../chunk-
|
|
35
|
+
} from "../chunk-UB2LOJ6Q.js";
|
|
36
36
|
import {
|
|
37
37
|
acquireSingleRunLock,
|
|
38
38
|
assertCodeSurfaceIdentity,
|
|
@@ -79,7 +79,7 @@ import {
|
|
|
79
79
|
surfaceContentHash,
|
|
80
80
|
surfaceHash,
|
|
81
81
|
verifyLoopProvenanceRecord
|
|
82
|
-
} from "../chunk-
|
|
82
|
+
} from "../chunk-NKAGIDE2.js";
|
|
83
83
|
import {
|
|
84
84
|
SearchLedgerConflictError,
|
|
85
85
|
SearchLedgerError,
|
|
@@ -96,10 +96,10 @@ import {
|
|
|
96
96
|
resolveRunDir,
|
|
97
97
|
runCampaign,
|
|
98
98
|
tangleTracesRoot
|
|
99
|
-
} from "../chunk-
|
|
99
|
+
} from "../chunk-EZJEIH2R.js";
|
|
100
100
|
import "../chunk-WGXIEX7P.js";
|
|
101
|
-
import "../chunk-
|
|
102
|
-
import "../chunk-
|
|
101
|
+
import "../chunk-NYLOYM6N.js";
|
|
102
|
+
import "../chunk-2MKQIFS4.js";
|
|
103
103
|
import "../chunk-PBE2LOSS.js";
|
|
104
104
|
import "../chunk-DPUHNQLN.js";
|
|
105
105
|
import "../chunk-MHELPNRP.js";
|
|
@@ -109,9 +109,8 @@ import "../chunk-5DTSBUL2.js";
|
|
|
109
109
|
import "../chunk-GGE4NNQT.js";
|
|
110
110
|
import "../chunk-P6FYH6K4.js";
|
|
111
111
|
import "../chunk-PC4UYEBM.js";
|
|
112
|
-
import "../chunk-
|
|
112
|
+
import "../chunk-2JX3CFMB.js";
|
|
113
113
|
import "../chunk-MA6HLL3S.js";
|
|
114
|
-
import "../chunk-VSMTAMNK.js";
|
|
115
114
|
import "../chunk-ONWEPEDO.js";
|
|
116
115
|
import "../chunk-K4DBDHLK.js";
|
|
117
116
|
import "../chunk-PZ5AY32C.js";
|
|
@@ -1,13 +1,55 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FAILURE_CLASSES
|
|
3
3
|
} from "./chunk-MA6HLL3S.js";
|
|
4
|
-
import {
|
|
5
|
-
hashJson
|
|
6
|
-
} from "./chunk-VSMTAMNK.js";
|
|
7
4
|
import {
|
|
8
5
|
ValidationError
|
|
9
6
|
} from "./chunk-ONWEPEDO.js";
|
|
10
7
|
|
|
8
|
+
// src/pre-registration.ts
|
|
9
|
+
function canonicalize(v) {
|
|
10
|
+
if (v === null || typeof v !== "object") return v;
|
|
11
|
+
if (Array.isArray(v)) return v.map(canonicalize);
|
|
12
|
+
const keys = Object.keys(v).sort();
|
|
13
|
+
const out = {};
|
|
14
|
+
for (const k of keys) out[k] = canonicalize(v[k]);
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
async function hashJson(obj) {
|
|
18
|
+
const canonical = canonicalize(obj);
|
|
19
|
+
const bytes = new TextEncoder().encode(JSON.stringify(canonical));
|
|
20
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
|
|
21
|
+
return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
22
|
+
}
|
|
23
|
+
async function signManifest(m) {
|
|
24
|
+
const hash = await hashJson(m);
|
|
25
|
+
return { ...m, contentHash: hash, algo: "sha256-content" };
|
|
26
|
+
}
|
|
27
|
+
async function verifyManifest(m) {
|
|
28
|
+
const { contentHash, algo: _algo, ...rest } = m;
|
|
29
|
+
void _algo;
|
|
30
|
+
const resigned = await signManifest(rest);
|
|
31
|
+
return resigned.contentHash === contentHash;
|
|
32
|
+
}
|
|
33
|
+
async function evaluateHypothesis(manifest, observed) {
|
|
34
|
+
if (!await verifyManifest(manifest)) {
|
|
35
|
+
throw new Error("evaluateHypothesis: manifest content hash mismatch (tampered)");
|
|
36
|
+
}
|
|
37
|
+
const reasons = [];
|
|
38
|
+
const directionOk = manifest.direction === "increase" ? observed.effect > 0 : observed.effect < 0;
|
|
39
|
+
if (!directionOk) reasons.push("wrong_direction");
|
|
40
|
+
if (Math.abs(observed.effect) < manifest.minEffect) reasons.push("effect_too_small");
|
|
41
|
+
if (observed.pValue >= manifest.alpha) reasons.push("not_significant");
|
|
42
|
+
if (observed.n < manifest.preRegisteredN) reasons.push("undersampled");
|
|
43
|
+
return {
|
|
44
|
+
manifest,
|
|
45
|
+
observedN: observed.n,
|
|
46
|
+
observedEffect: observed.effect,
|
|
47
|
+
observedPValue: observed.pValue,
|
|
48
|
+
confirmed: reasons.length === 0,
|
|
49
|
+
rejectionReasons: reasons
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
11
53
|
// src/agent-profile-cell.ts
|
|
12
54
|
var AgentProfileCellValidationError = class extends ValidationError {
|
|
13
55
|
path;
|
|
@@ -443,7 +485,15 @@ function validateRunRecord(input) {
|
|
|
443
485
|
"failureClass"
|
|
444
486
|
);
|
|
445
487
|
}
|
|
446
|
-
if (obj.failureMode !== void 0)
|
|
488
|
+
if (obj.failureMode !== void 0) {
|
|
489
|
+
expectString2(obj.failureMode, "failureMode");
|
|
490
|
+
if (obj.failureClass === void 0 || obj.failureClass === "success") {
|
|
491
|
+
throw new RunRecordValidationError(
|
|
492
|
+
"failureMode requires a non-success failureClass",
|
|
493
|
+
"failureMode"
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
447
497
|
if (typeof obj.terminalOutcome !== "string" || !TERMINAL_OUTCOMES.includes(obj.terminalOutcome)) {
|
|
448
498
|
throw new RunRecordValidationError(
|
|
449
499
|
`terminalOutcome must be one of ${TERMINAL_OUTCOMES.join(", ")}`,
|
|
@@ -617,6 +667,11 @@ function modelHasSnapshot(model) {
|
|
|
617
667
|
}
|
|
618
668
|
|
|
619
669
|
export {
|
|
670
|
+
canonicalize,
|
|
671
|
+
hashJson,
|
|
672
|
+
signManifest,
|
|
673
|
+
verifyManifest,
|
|
674
|
+
evaluateHypothesis,
|
|
620
675
|
AgentProfileCellValidationError,
|
|
621
676
|
buildAgentProfileCell,
|
|
622
677
|
agentProfileCellHashMaterial,
|
|
@@ -637,4 +692,4 @@ export {
|
|
|
637
692
|
roundTripRunRecord,
|
|
638
693
|
modelHasSnapshot
|
|
639
694
|
};
|
|
640
|
-
//# sourceMappingURL=chunk-
|
|
695
|
+
//# sourceMappingURL=chunk-2JX3CFMB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pre-registration.ts","../src/agent-profile-cell.ts","../src/run-record.ts"],"sourcesContent":["/**\n * Pre-registered hypotheses — declare what you're testing BEFORE the\n * run, check it AFTER. Prevents p-hacking, optional stopping, and the\n * \"we ran until it looked good\" failure mode.\n *\n * Manifest is a plain JSON-friendly object. Sign it with a content hash\n * + timestamp; the registered record becomes immutable. Post-run,\n * evaluate the manifest against observed results — the library refuses\n * to let you re-interpret a different metric as the declared one.\n */\n\nexport interface HypothesisManifest {\n id: string\n /** Human prose — goes into the audit trail. */\n hypothesis: string\n /** Metric the hypothesis claims to move. */\n metric: string\n /** 'increase' = candidate should score higher than baseline; 'decrease' = lower. */\n direction: 'increase' | 'decrease'\n /** Minimum effect size to count (same units as the metric). */\n minEffect: number\n /** Alpha threshold. */\n alpha: number\n /** Target statistical power at which sample size was pre-computed. */\n power: number\n /** Declared N per arm before running. */\n preRegisteredN: number\n /** ISO8601 timestamp the manifest was registered. */\n registeredAt: string\n /** Optional identifiers to tie into the trace corpus. */\n baselineLabel?: string\n candidateLabel?: string\n}\n\n/**\n * Identifier for the hashing scheme used to produce `contentHash`.\n *\n * `'sha256-content'` — sha256 hex over the canonicalized manifest with\n * the `contentHash` and `algo` fields stripped. Held as a string union\n * so future schemes can be added without breaking parsers; SignedManifest\n * values without `algo` deserialize cleanly because the field is optional.\n */\nexport type SignedManifestAlgo = 'sha256-content'\n\nexport interface SignedManifest extends HypothesisManifest {\n /** sha256 hex of canonicalized manifest (everything except contentHash and algo). */\n contentHash: string\n /**\n * Algorithm string describing how `contentHash` was produced.\n *\n * Optional on the type so serialized manifests without it still parse,\n * but ALWAYS populated by {@link signManifest}. Consumers that want to\n * enforce a known algorithm should reject manifests where this field\n * is missing or unrecognized.\n */\n algo?: SignedManifestAlgo\n}\n\nexport interface HypothesisResult {\n manifest: SignedManifest\n observedN: number\n observedEffect: number\n observedPValue: number\n /** True iff the observed effect hits the pre-declared direction with\n * magnitude ≥ minEffect AND p < alpha. */\n confirmed: boolean\n /** Enumerated reasons the hypothesis was rejected (each a machine-tag). */\n rejectionReasons: Array<\n 'wrong_direction' | 'effect_too_small' | 'not_significant' | 'undersampled'\n >\n notes?: string\n}\n\n/**\n * Deterministic JSON canonicalization — sort object keys recursively.\n *\n * Two semantically-equal objects produce byte-identical canonicalized output;\n * this is what makes a content-hash stable across encoders, key insertion\n * orders, and runtime versions. Exported for any consumer that needs the same\n * canonicalization guarantee outside the manifest-signing path (e.g., signing\n * an artifact bundle, hashing a dataset version, etc.).\n */\nexport function canonicalize(v: unknown): unknown {\n if (v === null || typeof v !== 'object') return v\n if (Array.isArray(v)) return v.map(canonicalize)\n const keys = Object.keys(v as Record<string, unknown>).sort()\n const out: Record<string, unknown> = {}\n for (const k of keys) out[k] = canonicalize((v as Record<string, unknown>)[k])\n return out\n}\n\n/**\n * SHA-256 hex (full 64 chars) over the canonicalized JSON encoding of `obj`.\n *\n * The same primitive `signManifest` and `verifyManifest` are built on, exposed\n * directly so consumers signing arbitrary structured content (artifact bundles,\n * production packets, dataset manifests, etc.) don't have to re-derive\n * canonicalize+sha256 from scratch.\n *\n * Stable across:\n * - object key insertion order (canonicalization sorts keys recursively)\n * - encoder choice (UTF-8 via TextEncoder, fixed)\n * - runtime (uses the Web Crypto subtle digest, present in Node ≥18 and browsers)\n *\n * Named `hashJson` to disambiguate from `prompt-registry.ts`'s `hashContent`,\n * which takes a string input and returns a truncated 12-char prompt id.\n * Use `hashJson` when you mean \"canonicalize then hash.\"\n *\n * @example\n * const hash = await hashJson({ id: '1', kind: 'spec' })\n * // 'a3f1...' (64 hex chars)\n */\nexport async function hashJson<T>(obj: T): Promise<string> {\n const canonical = canonicalize(obj)\n const bytes = new TextEncoder().encode(JSON.stringify(canonical))\n const digest = await globalThis.crypto.subtle.digest('SHA-256', bytes)\n return Array.from(new Uint8Array(digest))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Sign a manifest with a SHA-256 content hash.\n *\n * The hash covers the canonicalized manifest with the `contentHash`\n * and `algo` fields stripped; this lets verifiers re-sign the rest and\n * compare. Returned manifest always carries `algo: 'sha256-content'`\n * so downstream consumers can identify the scheme; manifests without\n * `algo` still verify because it is stripped before hashing on both sides.\n */\nexport async function signManifest(m: HypothesisManifest): Promise<SignedManifest> {\n const hash = await hashJson(m)\n return { ...m, contentHash: hash, algo: 'sha256-content' }\n}\n\n/**\n * Verify that a signed manifest has not been tampered with.\n *\n * Strips `contentHash` and `algo` before re-signing so manifests without\n * `algo` verify identically to ones that carry it.\n */\nexport async function verifyManifest(m: SignedManifest): Promise<boolean> {\n const { contentHash, algo: _algo, ...rest } = m\n void _algo\n const resigned = await signManifest(rest)\n return resigned.contentHash === contentHash\n}\n\n/**\n * Evaluate a pre-registered hypothesis against observed results.\n * Mechanical — no re-interpretation permitted.\n */\nexport async function evaluateHypothesis(\n manifest: SignedManifest,\n observed: { n: number; effect: number; pValue: number },\n): Promise<HypothesisResult> {\n if (!(await verifyManifest(manifest))) {\n throw new Error('evaluateHypothesis: manifest content hash mismatch (tampered)')\n }\n const reasons: HypothesisResult['rejectionReasons'] = []\n const directionOk = manifest.direction === 'increase' ? observed.effect > 0 : observed.effect < 0\n if (!directionOk) reasons.push('wrong_direction')\n if (Math.abs(observed.effect) < manifest.minEffect) reasons.push('effect_too_small')\n if (observed.pValue >= manifest.alpha) reasons.push('not_significant')\n if (observed.n < manifest.preRegisteredN) reasons.push('undersampled')\n return {\n manifest,\n observedN: observed.n,\n observedEffect: observed.effect,\n observedPValue: observed.pValue,\n confirmed: reasons.length === 0,\n rejectionReasons: reasons,\n }\n}\n","import type { AgentProfile } from '@tangle-network/agent-interface'\nimport { ValidationError } from './errors'\nimport { hashJson } from './pre-registration'\n\nexport type AgentProfileCellSchemaVersion = 'agent-profile-cell/v1'\n\nexport type AgentProfileJsonObject = { [key: string]: AgentProfileJson }\n\nexport type AgentProfileJson =\n | string\n | number\n | boolean\n | null\n | AgentProfileJson[]\n | AgentProfileJsonObject\n\nexport type AgentProfileDimensionValue = string | number | boolean | null\n\nexport interface AgentProfileSource {\n /** Runtime/profile contract being fingerprinted, e.g. `agent-interface-profile`. */\n kind: string\n /** sha256 over the canonical source profile object. */\n hash: string\n}\n\nexport interface AgentProfileSourceInput {\n kind: string\n /** Precomputed sha256 for callers that already sign their profile artifact. */\n hash?: string\n /** Full canonical runtime profile; hashed and then discarded from the cell. */\n profile?: AgentProfileJson\n}\n\nexport interface AgentProfileHarness {\n id: string\n version?: string\n hash?: string\n}\n\nexport interface AgentProfileCellInput {\n profileId: string\n sourceProfile: AgentProfileSourceInput\n harness?: AgentProfileHarness\n model?: string\n promptHash?: string\n dimensions?: Record<string, AgentProfileDimensionValue>\n}\n\nexport interface AgentProfileCell {\n schemaVersion: AgentProfileCellSchemaVersion\n cellId: string\n profileId: string\n sourceProfile: AgentProfileSource\n harness?: AgentProfileHarness\n model?: string\n promptHash?: string\n dimensions?: Record<string, AgentProfileDimensionValue>\n}\n\nexport class AgentProfileCellValidationError extends ValidationError {\n readonly path: string\n constructor(message: string, path = '') {\n super(path ? `${message} (at ${path})` : message)\n this.path = path\n }\n}\n\nconst SHA256_HEX = /^[0-9a-f]{64}$/\nconst CELL_ID = /^agent-profile-cell:sha256:[0-9a-f]{64}$/\n\nexport async function buildAgentProfileCell(\n input: AgentProfileCellInput,\n): Promise<AgentProfileCell> {\n const material = await normalizeAgentProfileCellInput(input)\n const cellId = `agent-profile-cell:sha256:${await hashJson(material)}`\n return { ...material, cellId }\n}\n\nexport function agentProfileCellHashMaterial(\n cell: AgentProfileCell,\n): Omit<AgentProfileCell, 'cellId'> {\n const { cellId: _cellId, ...material } = cell\n void _cellId\n return normalizeAgentProfileCell(material)\n}\n\n/**\n * Verify an `AgentProfileCell`'s `cellId` matches the sha256 of its hash-material fields, confirming the record has not been tampered with.\n */\nexport async function verifyAgentProfileCell(cell: AgentProfileCell): Promise<boolean> {\n validateAgentProfileCell(cell)\n return (\n cell.cellId ===\n `agent-profile-cell:sha256:${await hashJson(agentProfileCellHashMaterial(cell))}`\n )\n}\n\nexport function validateAgentProfileCell(input: unknown): AgentProfileCell {\n if (input === null || typeof input !== 'object') {\n throw new AgentProfileCellValidationError('expected object')\n }\n const obj = input as Record<string, unknown>\n expectLiteral(obj.schemaVersion, 'agent-profile-cell/v1', 'schemaVersion')\n if (typeof obj.cellId !== 'string' || !CELL_ID.test(obj.cellId)) {\n throw new AgentProfileCellValidationError(\n 'cellId must match agent-profile-cell:sha256:<64 lowercase hex chars>',\n 'cellId',\n )\n }\n expectString(obj.profileId, 'profileId')\n validateSource(obj.sourceProfile, 'sourceProfile')\n if (obj.harness !== undefined) validateHarness(obj.harness, 'harness')\n if (obj.model !== undefined) expectString(obj.model, 'model')\n if (obj.promptHash !== undefined) expectString(obj.promptHash, 'promptHash')\n if (obj.dimensions !== undefined) validateDimensions(obj.dimensions, 'dimensions')\n return input as AgentProfileCell\n}\n\nexport function requireAgentProfileCell(record: {\n runId: string\n agentProfile?: AgentProfileCell\n}): AgentProfileCell {\n if (!record.agentProfile) {\n throw new AgentProfileCellValidationError(\n `run \"${record.runId}\" is missing agentProfile; profile-cell grouping requires explicit profile identity`,\n 'agentProfile',\n )\n }\n return validateAgentProfileCell(record.agentProfile)\n}\n\nexport function agentProfileCellKey(record: {\n runId: string\n agentProfile?: AgentProfileCell\n}): string {\n return requireAgentProfileCell(record).cellId\n}\n\nexport async function assertRunAgentProfileCell(record: {\n runId: string\n model: string\n promptHash: string\n agentProfile?: AgentProfileCell\n}): Promise<AgentProfileCell> {\n const profile = requireAgentProfileCell(record)\n if (!(await verifyAgentProfileCell(profile))) {\n throw new AgentProfileCellValidationError(\n `run \"${record.runId}\" has an agentProfile.cellId that does not match its content`,\n 'agentProfile.cellId',\n )\n }\n if (profile.model !== undefined && profile.model !== record.model) {\n throw new AgentProfileCellValidationError(\n `run \"${record.runId}\" agentProfile.model \"${profile.model}\" does not match model \"${record.model}\"`,\n 'agentProfile.model',\n )\n }\n if (profile.promptHash !== undefined && profile.promptHash !== record.promptHash) {\n throw new AgentProfileCellValidationError(\n `run \"${record.runId}\" agentProfile.promptHash \"${profile.promptHash}\" does not match promptHash \"${record.promptHash}\"`,\n 'agentProfile.promptHash',\n )\n }\n return profile\n}\n\nexport function groupRunsByAgentProfileCell<\n T extends { runId: string; agentProfile?: AgentProfileCell },\n>(records: readonly T[]): Map<string, T[]> {\n const groups = new Map<string, T[]>()\n for (const record of records) {\n const key = agentProfileCellKey(record)\n const bucket = groups.get(key)\n if (bucket) bucket.push(record)\n else groups.set(key, [record])\n }\n return groups\n}\n\nasync function normalizeAgentProfileCellInput(\n input: AgentProfileCellInput,\n): Promise<Omit<AgentProfileCell, 'cellId'>> {\n return normalizeAgentProfileCell({\n schemaVersion: 'agent-profile-cell/v1',\n profileId: input.profileId,\n sourceProfile: await normalizeSourceInput(input.sourceProfile),\n harness: input.harness,\n model: input.model,\n promptHash: input.promptHash,\n dimensions: input.dimensions,\n })\n}\n\nfunction normalizeAgentProfileCell(\n input: Omit<AgentProfileCell, 'cellId'>,\n): Omit<AgentProfileCell, 'cellId'> {\n return compactObject({\n schemaVersion: 'agent-profile-cell/v1' as const,\n profileId: requireNonEmpty(input.profileId, 'profileId'),\n sourceProfile: normalizeSource(input.sourceProfile),\n harness: input.harness ? normalizeHarness(input.harness, 'harness') : undefined,\n model: optionalNonEmpty(input.model, 'model'),\n promptHash: optionalNonEmpty(input.promptHash, 'promptHash'),\n dimensions: input.dimensions\n ? nonEmptyRecord(normalizeDimensions(input.dimensions))\n : undefined,\n })\n}\n\nasync function normalizeSourceInput(input: AgentProfileSourceInput): Promise<AgentProfileSource> {\n const kind = requireNonEmpty(input.kind, 'sourceProfile.kind')\n if (input.hash !== undefined && input.profile !== undefined) {\n throw new AgentProfileCellValidationError(\n 'sourceProfile must provide either hash or profile, not both',\n 'sourceProfile',\n )\n }\n if (input.hash !== undefined) {\n return { kind, hash: requireSha256Hex(input.hash, 'sourceProfile.hash') }\n }\n if (input.profile === undefined) {\n throw new AgentProfileCellValidationError(\n 'sourceProfile must provide hash or profile',\n 'sourceProfile',\n )\n }\n assertJson(input.profile, 'sourceProfile.profile')\n return { kind, hash: await hashJson(input.profile) }\n}\n\nfunction normalizeSource(input: AgentProfileSource): AgentProfileSource {\n return {\n kind: requireNonEmpty(input.kind, 'sourceProfile.kind'),\n hash: requireSha256Hex(input.hash, 'sourceProfile.hash'),\n }\n}\n\nfunction normalizeHarness(input: AgentProfileHarness, path: string): AgentProfileHarness {\n return compactObject({\n id: requireNonEmpty(input.id, `${path}.id`),\n version: optionalNonEmpty(input.version, `${path}.version`),\n hash: optionalNonEmpty(input.hash, `${path}.hash`),\n })\n}\n\nfunction normalizeDimensions(\n input: Record<string, AgentProfileDimensionValue>,\n): Record<string, AgentProfileDimensionValue> {\n const out: Record<string, AgentProfileDimensionValue> = {}\n for (const key of Object.keys(input).sort()) {\n const value = input[key]\n requireNonEmpty(key, 'dimensions.<key>')\n if (\n value !== null &&\n typeof value !== 'string' &&\n typeof value !== 'number' &&\n typeof value !== 'boolean'\n ) {\n throw new AgentProfileCellValidationError(\n 'expected primitive dimension value',\n `dimensions.${key}`,\n )\n }\n if (typeof value === 'number' && !Number.isFinite(value)) {\n throw new AgentProfileCellValidationError('expected finite number', `dimensions.${key}`)\n }\n out[key] = value\n }\n return out\n}\n\nfunction compactObject<T extends Record<string, unknown>>(input: T): T {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(input)) {\n if (value !== undefined) out[key] = value\n }\n return out as T\n}\n\nfunction nonEmptyRecord<T extends Record<string, unknown>>(input: T): T | undefined {\n return Object.keys(input).length > 0 ? input : undefined\n}\n\nfunction validateSource(value: unknown, path: string): void {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new AgentProfileCellValidationError('expected object', path)\n }\n const rec = value as Record<string, unknown>\n expectString(rec.kind, `${path}.kind`)\n requireSha256Hex(rec.hash, `${path}.hash`)\n}\n\nfunction validateHarness(value: unknown, path: string): void {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new AgentProfileCellValidationError('expected object', path)\n }\n const rec = value as Record<string, unknown>\n expectString(rec.id, `${path}.id`)\n if (rec.version !== undefined) expectString(rec.version, `${path}.version`)\n if (rec.hash !== undefined) expectString(rec.hash, `${path}.hash`)\n}\n\nfunction validateDimensions(value: unknown, path: string): void {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new AgentProfileCellValidationError('expected object', path)\n }\n normalizeDimensions(value as Record<string, AgentProfileDimensionValue>)\n}\n\nfunction assertJson(value: AgentProfileJson, path: string): void {\n if (value === null) return\n const type = typeof value\n if (type === 'string' || type === 'boolean') return\n if (type === 'number') {\n if (!Number.isFinite(value)) {\n throw new AgentProfileCellValidationError('expected finite number', path)\n }\n return\n }\n if (Array.isArray(value)) {\n value.forEach((item, index) => {\n assertJson(item, `${path}[${index}]`)\n })\n return\n }\n if (type === 'object') {\n for (const [key, nested] of Object.entries(value)) {\n requireNonEmpty(key, `${path}.<key>`)\n assertJson(nested, `${path}.${key}`)\n }\n return\n }\n throw new AgentProfileCellValidationError('expected JSON-compatible value', path)\n}\n\nfunction expectLiteral(value: unknown, expected: string, path: string): void {\n if (value !== expected) {\n throw new AgentProfileCellValidationError(`expected ${expected}`, path)\n }\n}\n\nfunction expectString(value: unknown, path: string): void {\n if (typeof value !== 'string' || value.length === 0) {\n throw new AgentProfileCellValidationError('expected non-empty string', path)\n }\n}\n\nfunction requireNonEmpty(value: string, path: string): string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new AgentProfileCellValidationError('expected non-empty string', path)\n }\n return value\n}\n\nfunction optionalNonEmpty(value: string | undefined, path: string): string | undefined {\n if (value === undefined) return undefined\n return requireNonEmpty(value, path)\n}\n\nfunction requireSha256Hex(value: unknown, path: string): string {\n if (typeof value !== 'string' || !SHA256_HEX.test(value)) {\n throw new AgentProfileCellValidationError('expected 64 lowercase sha256 hex chars', path)\n }\n return value\n}\n\n// ── Consumer helpers ─────────────────────────────────────────────────\n//\n// Boilerplate every product consuming `buildAgentProfileCell` used to duplicate:\n//\n// 1. A `JSON.parse(JSON.stringify(value))` helper that canonicalizes an\n// arbitrary `@tangle-network/agent-interface` `AgentProfile` into the recursive\n// `AgentProfileJson` shape, with a fail-loud error when the profile\n// is not JSON-serializable.\n//\n// 2. The magic string `'agent-interface-profile'` for `sourceProfile.kind`.\n//\n// Both belong here so the cross-product cell join (same canonical profile\n// hashes to the same `sourceProfile.hash` across products) is enforced by\n// the type system, not by every consumer remembering to do it right.\n// See blueprint-agent issue tangle-network/agent-eval#82.\n\n/** Canonical `sourceProfile.kind` values. Two products fingerprinting the\n * same canonical profile MUST use the same kind for their cells to share\n * `sourceProfile.hash`. Extend rather than create new strings — adding a\n * new kind is a deliberate cross-product schema change. */\nexport const AGENT_PROFILE_KINDS = {\n /** A profile declared via `defineAgentProfile(...)` from\n * `@tangle-network/agent-interface`. The default kind for router-backed\n * and sandbox-backed products. */\n AGENT_INTERFACE_PROFILE: 'agent-interface-profile',\n} as const\n\nexport type AgentProfileKind = (typeof AGENT_PROFILE_KINDS)[keyof typeof AGENT_PROFILE_KINDS]\n\n/** Canonicalize an arbitrary value into `AgentProfileJson` by JSON\n * round-trip. Throws when the value contains anything not representable\n * as JSON (functions, BigInt, cycles) — non-portable profiles fail loud\n * rather than silently dropping fields. */\nexport function toAgentProfileJson(value: unknown): AgentProfileJson {\n let serialized: string | undefined\n try {\n serialized = JSON.stringify(value)\n } catch (err) {\n throw new AgentProfileCellValidationError(\n `agent profile must be JSON-serializable: ${err instanceof Error ? err.message : String(err)}`,\n 'sourceProfile.profile',\n )\n }\n if (serialized === undefined) {\n throw new AgentProfileCellValidationError(\n 'agent profile must be JSON-serializable (got undefined after JSON.stringify)',\n 'sourceProfile.profile',\n )\n }\n return JSON.parse(serialized) as AgentProfileJson\n}\n\n/** Canonical AgentProfile shape required when deriving a stable cell id. */\nexport type AgentInterfaceProfileLike = AgentProfile & { name: string; version: string }\n\n/** Higher-level helper that hard-codes the canonical\n * `agent-interface-profile` kind plus the JSON canonicalization. Equivalent\n * to calling `buildAgentProfileCell` with `profileId = \\`${name}@${version}\\``\n * and `sourceProfile = { kind: AGENT_INTERFACE_PROFILE, profile: <round-tripped> }`.\n *\n * Use this from any product consuming an agent-interface `AgentProfile`; the\n * manual `buildAgentProfileCell` call is reserved for advanced cases\n * (custom kinds, pre-computed source hashes, alternate profileId\n * conventions). */\nexport async function buildAgentInterfaceProfileCell(\n profile: AgentInterfaceProfileLike,\n input: Omit<AgentProfileCellInput, 'profileId' | 'sourceProfile'>,\n): Promise<AgentProfileCell> {\n if (!profile || typeof profile !== 'object') {\n throw new AgentProfileCellValidationError('AgentProfile must be an object', 'profile')\n }\n if (typeof profile.name !== 'string' || profile.name.length === 0) {\n throw new AgentProfileCellValidationError(\n 'AgentProfile must have a non-empty `name`',\n 'profile.name',\n )\n }\n if (typeof profile.version !== 'string' || profile.version.length === 0) {\n throw new AgentProfileCellValidationError(\n 'AgentProfile must have a non-empty `version`',\n 'profile.version',\n )\n }\n return buildAgentProfileCell({\n ...input,\n profileId: `${profile.name}@${profile.version}`,\n sourceProfile: {\n kind: AGENT_PROFILE_KINDS.AGENT_INTERFACE_PROFILE,\n profile: toAgentProfileJson(profile),\n },\n })\n}\n","/**\n * Paper-grade RunRecord schema + runtime validator.\n *\n * Every run that participates in a promotion gate, paper table, or\n * researcher loop SHOULD be recorded as a `RunRecord`. The mandatory\n * fields are exactly those the paper \"Two Loops, Three Roles\" requires\n * for reproducibility: who/what/when/cost/seed/hash, plus the search vs\n * holdout split tag. A task score is optional because execution-only records\n * must preserve missing labels instead of converting errors into zero quality.\n *\n * This is intentionally NOT a replacement for the rich `Run` /\n * `ProposeReviewReport` / `ScenarioResult` types already in the\n * package. Those are runtime structures with full provenance. A\n * `RunRecord` is the analysis-time projection — the JSON-friendly\n * row you'd put in a parquet file or paste into a notebook.\n *\n * Validate at the boundary:\n *\n * const rec = validateRunRecord(rawJson) // throws on missing\n * const ok = isRunRecord(rawJson) // boolean check\n * const rec = parseRunRecordSafe(rawJson) // { ok, value | error }\n *\n * The validator runs in pure TS — zod is intentionally NOT a\n * dependency. Round-trip tested in `tests/run-record.test.ts`.\n */\n\nimport type { AgentProfileCell } from './agent-profile-cell'\nimport { validateAgentProfileCell } from './agent-profile-cell'\nimport { ValidationError } from './errors'\nimport { FAILURE_CLASSES, type FailureClass } from './trace/schema'\n\n/** Search/dev/holdout split tag. 'search' is the paper-grade alias for the\n * combined train+test pool that the optimizer is allowed to read. */\nexport type RunSplitTag = 'search' | 'dev' | 'holdout'\n\n/**\n * Explicit execution-lifecycle result for a run.\n *\n * This is separate from task quality (`outcome`) and failure classification.\n * Producers set it only from root-run or process evidence.\n */\nexport type RunTerminalOutcome = 'succeeded' | 'failed' | 'cancelled' | 'incomplete' | 'unknown'\n\nexport interface RunTokenUsage {\n input: number\n /** All generated tokens charged as output, including reasoning tokens. */\n output: number\n /** Reasoning-token subset of `output`, when the provider reports it. */\n reasoning?: number\n /** Prompt tokens served from a provider cache. */\n cached?: number\n /** Prompt tokens written into a provider cache. */\n cacheWrite?: number\n}\n\n/**\n * How a run's USD amount was obtained.\n */\nexport type RunCostProvenance =\n | { kind: 'observed'; usd: number }\n | { kind: 'estimated'; usd: number }\n | { kind: 'uncaptured'; usd: null }\n\nexport interface RunJudgeMetadata {\n model: string\n promptVersion: string\n /** [0,1] confidence the judge declared. Constant judge confidence\n * across many runs is a fallback signal (see `canary.ts`). */\n confidence: number\n /** True if the judge degraded to a fallback path (rules-only,\n * prior-call cache, etc.). The canary uses this to alert. */\n fallback: boolean\n}\n\n/**\n * Per-judge / per-dimension breakdown for runs scored by an ensemble of\n * judges over a multi-dimensional rubric.\n *\n * The collapsed `outcome.searchScore` / `holdoutScore` carries the\n * composite the gate uses. The full breakdown belongs here so consumers\n * can answer \"which judge disagreed?\", \"which dimension dragged the\n * composite down?\", and \"did half the panel fail?\" without re-running.\n *\n * `perJudge[judgeId][dim]` is the canonical source; `perDimMean` and\n * `composite` are convenience projections — derivable but precomputed so\n * downstream IRR primitives (`interRaterReliability`,\n * `corpusInterRaterAgreement`) and reporters don't pay the same\n * aggregation twice.\n *\n * Fail-loud discipline: judges that errored out land in `failedJudges`\n * by id. A missing key in `perJudge` is ambiguous (silent zero vs not\n * run); the explicit list makes a partial-failure recorded as such.\n */\nexport interface JudgeScoresRecord {\n /** Per-judge per-dimension scores. `{ \"kimi-k2.6\": { helpfulness: 0.8, clarity: 0.7 }, ... }`. */\n perJudge: Record<string, Record<string, number>>\n /** Per-dim mean across judges. Convenience — derivable from `perJudge`. */\n perDimMean: Record<string, number>\n /** Composite mean across successful judges. Mirrors the task score only\n * when `failedJudges` is empty. */\n composite: number\n /** Judges that errored or returned an unparseable verdict. Recorded\n * by id (e.g. `['glm-5.1']`) so a partial-failure case is explicit,\n * not inferred from missing keys in `perJudge`. */\n failedJudges?: string[]\n /** Free-form notes the judges emitted (joined across judges or\n * first-judge only — consumer's choice). */\n notes?: string\n}\n\nexport interface RunOutcome {\n /** Score on the search/optimization split. Optional for holdout-only and\n * execution-only records. */\n searchScore?: number\n /** Score on the held-out split. Optional for search-only and execution-only\n * records. When both scores are absent, the run is explicitly unlabeled. */\n holdoutScore?: number\n /** Bag of any other metric the run produced — judge dimensions,\n * pass/fail counters, latency stats, etc. Numeric only — keeps\n * reporters honest. */\n raw: Record<string, number>\n /** Per-judge / per-dim breakdown. Consumers writing ensemble\n * judgements populate this; substrate primitives like\n * `interRaterReliability` and `corpusInterRaterAgreement` accept\n * these records as input. Optional — single-judge or scalar-only\n * runs leave it unset. */\n judgeScores?: JudgeScoresRecord\n /** Authenticity / realness verdict — did the run build the REAL thing on the\n * intended infra, or fake it (see `./authenticity`)? Optional: only domains\n * with an authenticity config populate it. Carried in the corpus so the\n * flywheel / off-policy learning can optimize for real completion, not gamed\n * pass-rate. `score` is 0-1; `gated` is the anti-Goodhart flag — a gated run\n * must not count as a real success regardless of `score`. */\n realness?: { score: number; gated: boolean; reason?: string }\n}\n\n/**\n * Mandatory paper-grade fields for a single evaluation run. Optional\n * fields are extension points; mandatory fields throw if missing.\n *\n * Hash discipline:\n * - `promptHash` is the sha256 of the EFFECTIVE prompt sent to the\n * model (after any steering bundle merge).\n * - `configHash` is the sha256 of the effective run config (model,\n * temperature, tools, judges, splits). The pair (promptHash,\n * configHash) uniquely identifies an experiment cell.\n *\n * Model snapshot discipline:\n * - `model` MUST encode a snapshot version. Bare aliases like\n * `claude-sonnet-4` or `gpt-4o` are banned — they remap silently.\n * Use `claude-sonnet-4-6@2025-04-15` or `gpt-4o-2024-11-20`.\n */\nexport interface RunRecord {\n /** UUID for the run. */\n runId: string\n /** Logical experiment grouping (a treatment vs a baseline within\n * the same sweep should share `experimentId`). */\n experimentId: string\n /** Stable identifier for the candidate (variant) being run. The\n * promotion gate compares two `candidateId`s on matched items. */\n candidateId: string\n /** RNG seed for the run. Always recorded — silent re-seeding is\n * the most common cause of non-reproducible numbers. */\n seed: number\n /** Model identifier WITH snapshot version. */\n model: string\n /** sha256 of the effective prompt (post-steering). */\n promptHash: string\n /** sha256 of the effective config. */\n configHash: string\n /** Git SHA the harness was run from. */\n commitSha: string\n /** End-to-end wall-clock duration in milliseconds. */\n wallMs: number\n /** Time spent queued before execution started, if known. */\n queueMs?: number\n /** Total USD cost, or null when the producer could not capture one. */\n costUsd: number | null\n /** Whether `costUsd` came from billing data, a price calculation, or is unavailable. */\n costProvenance: RunCostProvenance\n /** Token usage breakdown. */\n tokenUsage: RunTokenUsage\n /** Root-run or process terminal result. Never inferred from a child span. */\n terminalOutcome: RunTerminalOutcome\n /** Root-run or process failure reason. Valid only for a failed, cancelled,\n * or incomplete terminal result; never populated from a child span. */\n terminalFailureReason?: string\n /** Judge-side metadata, if a judge was used. */\n judgeMetadata?: RunJudgeMetadata\n /** Per-split scores + raw bag. */\n outcome: RunOutcome\n /** Canonical task-failure class drawn from the shared\n * `FAILURE_CLASSES` taxonomy. Producers set it only from task-result\n * evidence. Execution errors belong in\n * `outcome.raw.execution_error_count`. */\n failureClass?: FailureClass\n /** Free-form task-failure detail scoped under a non-success\n * `failureClass`. It is invalid without that class. */\n failureMode?: string\n /** Which split this run was drawn from. */\n splitTag: RunSplitTag\n /**\n * Stable scenario identifier the run observed or was scored against.\n * Comparison primitives match this identity rather than input order.\n */\n scenarioId: string\n /**\n * Canonical identity for the agent profile cell that produced this row:\n * profile artifact hash plus optional harness/model/prompt/reporting\n * dimensions. Use `agentProfile.cellId` to group persona sweeps and\n * longitudinal reports by the complete source profile, not by a loose\n * candidate label or opaque config hash.\n */\n agentProfile?: AgentProfileCell\n}\n\n/**\n * Canonical task-result classification.\n *\n * A producer may omit classification, record explicit success, or attach\n * domain-specific detail to a non-success class. Detail can never stand alone.\n * Execution errors belong in `outcome.raw.execution_error_count`.\n */\nexport type RunTaskFailure =\n | { failureClass?: undefined; failureMode?: undefined }\n | { failureClass: 'success'; failureMode?: undefined }\n | {\n failureClass: Exclude<FailureClass, 'success'>\n failureMode?: string\n }\n\n/** Return task quality, preferring held-out evidence when both scores exist. */\nexport function runTaskScore(record: RunRecord): number | undefined {\n const score = record.outcome.holdoutScore ?? record.outcome.searchScore\n return typeof score === 'number' && Number.isFinite(score) ? score : undefined\n}\n\n// ── Validation ───────────────────────────────────────────────────────\n\nconst MANDATORY_TOP_LEVEL = [\n 'runId',\n 'experimentId',\n 'candidateId',\n 'seed',\n 'model',\n 'promptHash',\n 'configHash',\n 'commitSha',\n 'wallMs',\n 'costUsd',\n 'costProvenance',\n 'tokenUsage',\n 'terminalOutcome',\n 'outcome',\n 'splitTag',\n 'scenarioId',\n] as const\n\nconst SPLIT_TAGS: ReadonlyArray<RunSplitTag> = ['search', 'dev', 'holdout']\nconst TERMINAL_OUTCOMES: ReadonlyArray<RunTerminalOutcome> = [\n 'succeeded',\n 'failed',\n 'cancelled',\n 'incomplete',\n 'unknown',\n]\n\nexport class RunRecordValidationError extends ValidationError {\n readonly path: string\n constructor(message: string, path = '') {\n super(path ? `${message} (at ${path})` : message)\n this.path = path\n }\n}\n\n/**\n * Strict validator. Throws `RunRecordValidationError` on the first\n * missing or wrongly-typed field. Returns the input cast to\n * `RunRecord` on success — the validator does not coerce.\n */\nexport function validateRunRecord(input: unknown): RunRecord {\n if (input === null || typeof input !== 'object') {\n throw new RunRecordValidationError('expected object')\n }\n const obj = input as Record<string, unknown>\n\n for (const key of MANDATORY_TOP_LEVEL) {\n if (!(key in obj)) {\n throw new RunRecordValidationError(`missing mandatory field \"${key}\"`)\n }\n }\n\n expectString(obj.runId, 'runId')\n expectString(obj.experimentId, 'experimentId')\n expectString(obj.candidateId, 'candidateId')\n expectFiniteNumber(obj.seed, 'seed')\n expectString(obj.model, 'model')\n expectString(obj.promptHash, 'promptHash')\n expectString(obj.configHash, 'configHash')\n expectString(obj.commitSha, 'commitSha')\n expectNonNegativeNumber(obj.wallMs, 'wallMs')\n if (obj.queueMs !== undefined) expectNonNegativeNumber(obj.queueMs, 'queueMs')\n validateCost(obj.costUsd, obj.costProvenance)\n\n // Snapshot discipline: bare model aliases are not paper-grade.\n if (!modelHasSnapshot(obj.model as string)) {\n throw new RunRecordValidationError(\n `model \"${obj.model}\" lacks a snapshot version (use 'name@YYYY-MM-DD' or 'name-YYYYMMDD')`,\n 'model',\n )\n }\n\n // Token usage.\n const tu = obj.tokenUsage\n if (tu === null || typeof tu !== 'object') {\n throw new RunRecordValidationError('tokenUsage must be an object', 'tokenUsage')\n }\n const tuRec = tu as Record<string, unknown>\n expectNonNegativeNumber(tuRec.input, 'tokenUsage.input')\n expectNonNegativeNumber(tuRec.output, 'tokenUsage.output')\n if (tuRec.reasoning !== undefined) {\n expectNonNegativeNumber(tuRec.reasoning, 'tokenUsage.reasoning')\n if ((tuRec.reasoning as number) > (tuRec.output as number)) {\n throw new RunRecordValidationError(\n 'reasoning tokens must be a subset of output tokens',\n 'tokenUsage.reasoning',\n )\n }\n }\n if (tuRec.cached !== undefined) expectNonNegativeNumber(tuRec.cached, 'tokenUsage.cached')\n if (tuRec.cacheWrite !== undefined) {\n expectNonNegativeNumber(tuRec.cacheWrite, 'tokenUsage.cacheWrite')\n }\n\n // Judge metadata, optional.\n if (obj.judgeMetadata !== undefined) {\n const jm = obj.judgeMetadata\n if (jm === null || typeof jm !== 'object') {\n throw new RunRecordValidationError('judgeMetadata must be an object', 'judgeMetadata')\n }\n const jmRec = jm as Record<string, unknown>\n expectString(jmRec.model, 'judgeMetadata.model')\n expectString(jmRec.promptVersion, 'judgeMetadata.promptVersion')\n expectFiniteNumber(jmRec.confidence, 'judgeMetadata.confidence')\n if (typeof jmRec.fallback !== 'boolean') {\n throw new RunRecordValidationError(\n 'judgeMetadata.fallback must be boolean',\n 'judgeMetadata.fallback',\n )\n }\n }\n\n // Outcome.\n const out = obj.outcome\n if (out === null || typeof out !== 'object') {\n throw new RunRecordValidationError('outcome must be an object', 'outcome')\n }\n const outRec = out as Record<string, unknown>\n if (outRec.searchScore !== undefined)\n expectFiniteNumber(outRec.searchScore, 'outcome.searchScore')\n if (outRec.holdoutScore !== undefined)\n expectFiniteNumber(outRec.holdoutScore, 'outcome.holdoutScore')\n const raw = outRec.raw\n if (raw === null || typeof raw !== 'object') {\n throw new RunRecordValidationError('outcome.raw must be an object', 'outcome.raw')\n }\n for (const [k, v] of Object.entries(raw as Record<string, unknown>)) {\n expectFiniteNumber(v, `outcome.raw.${k}`)\n }\n // Realness verdict, optional.\n if (outRec.realness !== undefined) {\n const r = outRec.realness\n if (r === null || typeof r !== 'object') {\n throw new RunRecordValidationError('outcome.realness must be an object', 'outcome.realness')\n }\n const rr = r as Record<string, unknown>\n expectFiniteNumber(rr.score, 'outcome.realness.score')\n if (typeof rr.gated !== 'boolean') {\n throw new RunRecordValidationError(\n 'outcome.realness.gated must be a boolean',\n 'outcome.realness.gated',\n )\n }\n }\n\n // Per-judge / per-dim breakdown, optional.\n if (outRec.judgeScores !== undefined) {\n validateJudgeScores(outRec.judgeScores, 'outcome.judgeScores')\n }\n\n // Failure mode optional.\n if (\n obj.failureClass !== undefined &&\n (typeof obj.failureClass !== 'string' ||\n !FAILURE_CLASSES.includes(obj.failureClass as FailureClass))\n ) {\n throw new RunRecordValidationError(\n `failureClass must be one of ${FAILURE_CLASSES.join(', ')}`,\n 'failureClass',\n )\n }\n if (obj.failureMode !== undefined) {\n expectString(obj.failureMode, 'failureMode')\n if (obj.failureClass === undefined || obj.failureClass === 'success') {\n throw new RunRecordValidationError(\n 'failureMode requires a non-success failureClass',\n 'failureMode',\n )\n }\n }\n\n if (\n typeof obj.terminalOutcome !== 'string' ||\n !TERMINAL_OUTCOMES.includes(obj.terminalOutcome as RunTerminalOutcome)\n ) {\n throw new RunRecordValidationError(\n `terminalOutcome must be one of ${TERMINAL_OUTCOMES.join(', ')}`,\n 'terminalOutcome',\n )\n }\n if (obj.terminalFailureReason !== undefined) {\n expectString(obj.terminalFailureReason, 'terminalFailureReason')\n if (\n obj.terminalOutcome !== 'failed' &&\n obj.terminalOutcome !== 'cancelled' &&\n obj.terminalOutcome !== 'incomplete'\n ) {\n throw new RunRecordValidationError(\n 'terminalFailureReason requires terminalOutcome failed, cancelled, or incomplete',\n 'terminalFailureReason',\n )\n }\n }\n\n if (obj.agentProfile !== undefined) {\n try {\n const profile = validateAgentProfileCell(obj.agentProfile)\n if (profile.model !== undefined && profile.model !== obj.model) {\n throw new RunRecordValidationError(\n `agentProfile.model \"${profile.model}\" does not match model \"${obj.model}\"`,\n 'agentProfile.model',\n )\n }\n if (profile.promptHash !== undefined && profile.promptHash !== obj.promptHash) {\n throw new RunRecordValidationError(\n `agentProfile.promptHash \"${profile.promptHash}\" does not match promptHash \"${obj.promptHash}\"`,\n 'agentProfile.promptHash',\n )\n }\n } catch (error) {\n if (error instanceof RunRecordValidationError) throw error\n if (error instanceof Error) {\n throw new RunRecordValidationError(error.message, 'agentProfile')\n }\n throw error\n }\n }\n\n expectString(obj.scenarioId, 'scenarioId')\n\n // Split tag.\n if (typeof obj.splitTag !== 'string' || !SPLIT_TAGS.includes(obj.splitTag as RunSplitTag)) {\n throw new RunRecordValidationError(\n `splitTag must be one of ${SPLIT_TAGS.join(', ')}, got ${String(obj.splitTag)}`,\n 'splitTag',\n )\n }\n\n return input as RunRecord\n}\n\nfunction validateCost(costUsd: unknown, provenance: unknown): void {\n if (provenance === null || typeof provenance !== 'object') {\n throw new RunRecordValidationError('costProvenance must be an object', 'costProvenance')\n }\n const value = provenance as Record<string, unknown>\n if (value.kind !== 'observed' && value.kind !== 'estimated' && value.kind !== 'uncaptured') {\n throw new RunRecordValidationError(\n 'costProvenance.kind must be observed, estimated, or uncaptured',\n 'costProvenance.kind',\n )\n }\n if (value.kind === 'uncaptured') {\n if (value.usd !== null) {\n throw new RunRecordValidationError(\n 'uncaptured costProvenance.usd must be null',\n 'costProvenance.usd',\n )\n }\n if (costUsd !== null) {\n throw new RunRecordValidationError('uncaptured cost requires costUsd to be null', 'costUsd')\n }\n return\n }\n expectNonNegativeNumber(costUsd, 'costUsd')\n expectNonNegativeNumber(value.usd, 'costProvenance.usd')\n if (value.usd !== costUsd) {\n throw new RunRecordValidationError(\n 'costProvenance.usd must equal costUsd',\n 'costProvenance.usd',\n )\n }\n}\n\n/** Boolean validator — convenience for filtering arrays. */\nexport function isRunRecord(input: unknown): input is RunRecord {\n try {\n validateRunRecord(input)\n return true\n } catch {\n return false\n }\n}\n\n/** Non-throwing validator — returns a discriminated union. */\nexport function parseRunRecordSafe(\n input: unknown,\n): { ok: true; value: RunRecord } | { ok: false; error: RunRecordValidationError } {\n try {\n return { ok: true, value: validateRunRecord(input) }\n } catch (e) {\n if (e instanceof RunRecordValidationError) return { ok: false, error: e }\n throw e\n }\n}\n\n/** Round-trip helper — `JSON.parse(JSON.stringify(record))` then validate. */\nexport function roundTripRunRecord(record: RunRecord): RunRecord {\n const json = JSON.stringify(record)\n return validateRunRecord(JSON.parse(json))\n}\n\n// ── Internals ────────────────────────────────────────────────────────\n\nfunction expectString(value: unknown, path: string): void {\n if (typeof value !== 'string' || value.length === 0) {\n throw new RunRecordValidationError(`expected non-empty string`, path)\n }\n}\n\nfunction expectFiniteNumber(value: unknown, path: string): void {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new RunRecordValidationError(`expected finite number`, path)\n }\n}\n\nfunction expectNonNegativeNumber(value: unknown, path: string): void {\n expectFiniteNumber(value, path)\n if ((value as number) < 0) {\n throw new RunRecordValidationError('expected non-negative number', path)\n }\n}\n\nfunction validateJudgeScores(value: unknown, path: string): void {\n if (value === null || typeof value !== 'object') {\n throw new RunRecordValidationError('judgeScores must be an object', path)\n }\n const rec = value as Record<string, unknown>\n\n const perJudge = rec.perJudge\n if (perJudge === null || typeof perJudge !== 'object') {\n throw new RunRecordValidationError('perJudge must be an object', `${path}.perJudge`)\n }\n for (const [judgeId, dims] of Object.entries(perJudge as Record<string, unknown>)) {\n if (dims === null || typeof dims !== 'object') {\n throw new RunRecordValidationError(\n 'per-judge entry must be an object of dimension scores',\n `${path}.perJudge.${judgeId}`,\n )\n }\n for (const [dim, score] of Object.entries(dims as Record<string, unknown>)) {\n expectFiniteNumber(score, `${path}.perJudge.${judgeId}.${dim}`)\n }\n }\n\n const perDimMean = rec.perDimMean\n if (perDimMean === null || typeof perDimMean !== 'object') {\n throw new RunRecordValidationError('perDimMean must be an object', `${path}.perDimMean`)\n }\n for (const [dim, mean] of Object.entries(perDimMean as Record<string, unknown>)) {\n expectFiniteNumber(mean, `${path}.perDimMean.${dim}`)\n }\n\n expectFiniteNumber(rec.composite, `${path}.composite`)\n\n if (rec.failedJudges !== undefined) {\n if (!Array.isArray(rec.failedJudges)) {\n throw new RunRecordValidationError(\n 'failedJudges must be an array of strings',\n `${path}.failedJudges`,\n )\n }\n for (let i = 0; i < rec.failedJudges.length; i++) {\n const id = rec.failedJudges[i]\n if (typeof id !== 'string' || id.length === 0) {\n throw new RunRecordValidationError(\n 'failedJudges entry must be a non-empty string',\n `${path}.failedJudges[${i}]`,\n )\n }\n }\n }\n\n if (rec.notes !== undefined && typeof rec.notes !== 'string') {\n throw new RunRecordValidationError('notes must be a string', `${path}.notes`)\n }\n}\n\n/**\n * Heuristic snapshot check. Accepts:\n * - `name@YYYY-MM-DD` (Anthropic style: `claude-sonnet-4-6@2025-04-15`)\n * - `name-YYYYMMDD` (OpenAI style: `gpt-4o-2024-11-20`)\n * - `name@<arbitrary-token>` (allow opaque snapshots like `@v3`)\n * - explicit `:date-...` Vertex-style tags\n *\n * Rejects bare aliases like `claude-sonnet-4` or `gpt-4o` that remap\n * silently as providers ship new snapshots.\n */\nexport function modelHasSnapshot(model: string): boolean {\n if (model.includes('@')) return true\n if (/-\\d{8}$/.test(model)) return true\n if (/-\\d{4}-\\d{2}-\\d{2}$/.test(model)) return true\n if (/:date-/.test(model)) return true\n return false\n}\n"],"mappings":"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","names":["expectString"]}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
validateRunRecord
|
|
3
|
+
} from "./chunk-2JX3CFMB.js";
|
|
4
|
+
|
|
1
5
|
// src/campaign/run-record.ts
|
|
2
6
|
function campaignCellToRunRecord(cell, options) {
|
|
3
7
|
const quality = projectCampaignCellQuality(cell);
|
|
@@ -45,7 +49,7 @@ function campaignCellToRunRecord(cell, options) {
|
|
|
45
49
|
if (options.splitTag === "holdout") outcome.holdoutScore = quality.score;
|
|
46
50
|
else outcome.searchScore = quality.score;
|
|
47
51
|
}
|
|
48
|
-
return {
|
|
52
|
+
return validateRunRecord({
|
|
49
53
|
runId: options.runId,
|
|
50
54
|
experimentId: options.experimentId,
|
|
51
55
|
candidateId: options.candidateId,
|
|
@@ -64,7 +68,7 @@ function campaignCellToRunRecord(cell, options) {
|
|
|
64
68
|
splitTag: options.splitTag,
|
|
65
69
|
scenarioId: options.scenarioId ?? cell.scenarioId,
|
|
66
70
|
...options.agentProfile ? { agentProfile: options.agentProfile } : {}
|
|
67
|
-
};
|
|
71
|
+
});
|
|
68
72
|
}
|
|
69
73
|
function campaignCellExecutionEvidence(cell) {
|
|
70
74
|
if (cell.errorStage === "dispatch") {
|
|
@@ -176,4 +180,4 @@ export {
|
|
|
176
180
|
campaignCellTaskScore,
|
|
177
181
|
campaignCellJudgeDimensions
|
|
178
182
|
};
|
|
179
|
-
//# sourceMappingURL=chunk-
|
|
183
|
+
//# sourceMappingURL=chunk-2MKQIFS4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/campaign/run-record.ts"],"sourcesContent":["import type { AgentProfileCell } from '../agent-profile-cell'\nimport type {\n JudgeScoresRecord,\n RunOutcome,\n RunRecord,\n RunSplitTag,\n RunTerminalOutcome,\n} from '../run-record'\nimport { validateRunRecord } from '../run-record'\nimport type { CampaignCellResult, JudgeScore } from './types'\n\nexport interface CampaignCellRunRecordOptions {\n runId: string\n experimentId: string\n candidateId: string\n model: string\n promptHash: string\n configHash: string\n commitSha: string\n splitTag: RunSplitTag\n seed?: number\n scenarioId?: string\n defaultCostUsd?: number\n agentProfile?: AgentProfileCell\n raw?: Record<string, number>\n}\n\nexport interface CampaignCellQualityProjection {\n score?: number\n judgeScores?: JudgeScoresRecord\n successfulJudgeScores: Record<string, JudgeScore>\n failedJudges: string[]\n raw: Record<string, number>\n}\n\nexport interface CampaignCellExecutionEvidence {\n terminalOutcome: RunTerminalOutcome\n executionErrorCount?: number\n judgeErrorCount?: number\n unclassifiedErrorCount?: number\n terminalFailureReason?: string\n}\n\n/**\n * Project one campaign cell into the canonical run format.\n *\n * A dispatch error establishes terminal execution failure. A judge error only\n * establishes that quality measurement failed after dispatch completed.\n * Failures without a stage remain unknown. No failure becomes a zero-quality\n * label.\n */\nexport function campaignCellToRunRecord<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n options: CampaignCellRunRecordOptions,\n): RunRecord {\n const quality = projectCampaignCellQuality(cell)\n const execution = campaignCellExecutionEvidence(cell)\n const judgeErrorCount = Math.max(\n quality.raw.judge_error_count ?? 0,\n execution.judgeErrorCount ?? 0,\n )\n const cellCostCaptured = Number.isFinite(cell.costUsd) && cell.costUsd >= 0\n const costUsd = cellCostCaptured ? cell.costUsd : (options.defaultCostUsd ?? null)\n const costProvenance =\n costUsd === null\n ? ({ kind: 'uncaptured', usd: null } as const)\n : cellCostCaptured && !cell.costEstimated\n ? ({ kind: 'observed', usd: costUsd } as const)\n : ({ kind: 'estimated', usd: costUsd } as const)\n const raw: Record<string, number> = {\n ...finiteMetrics(options.raw),\n ...quality.raw,\n rep: cell.rep,\n duration_ms: cell.durationMs,\n ...(costUsd === null ? {} : { cost_usd: costUsd }),\n cost_estimated: cell.costEstimated ? 1 : 0,\n tokens_input: cell.tokenUsage.input,\n tokens_output: cell.tokenUsage.output,\n latency_ms: cell.durationMs,\n ...(execution.executionErrorCount === undefined\n ? {}\n : { execution_error_count: execution.executionErrorCount }),\n ...(judgeErrorCount > 0 ? { judge_error_count: judgeErrorCount } : {}),\n ...(execution.unclassifiedErrorCount === undefined\n ? {}\n : { unclassified_error_count: execution.unclassifiedErrorCount }),\n }\n if (typeof cell.generation === 'number') raw.generation = cell.generation\n if (cell.tokenUsage.reasoning !== undefined) {\n raw.tokens_reasoning = cell.tokenUsage.reasoning\n }\n if (cell.tokenUsage.cached !== undefined) raw.tokens_cached = cell.tokenUsage.cached\n if (cell.tokenUsage.cacheWrite !== undefined) {\n raw.tokens_cache_write = cell.tokenUsage.cacheWrite\n }\n if (costUsd !== null && costUsd > 0) {\n raw.tokens_per_dollar = (cell.tokenUsage.input + cell.tokenUsage.output) / costUsd\n }\n if (costUsd !== null && quality.score !== undefined && quality.score > 0.01) {\n raw.cost_per_quality = costUsd / quality.score\n }\n\n const outcome: RunOutcome = {\n raw,\n ...(quality.judgeScores ? { judgeScores: quality.judgeScores } : {}),\n }\n if (quality.score !== undefined) {\n if (options.splitTag === 'holdout') outcome.holdoutScore = quality.score\n else outcome.searchScore = quality.score\n }\n\n return validateRunRecord({\n runId: options.runId,\n experimentId: options.experimentId,\n candidateId: options.candidateId,\n seed: options.seed ?? cell.seed,\n model: options.model,\n promptHash: options.promptHash,\n configHash: options.configHash,\n commitSha: options.commitSha,\n wallMs: cell.durationMs,\n costUsd,\n costProvenance,\n tokenUsage: { ...cell.tokenUsage },\n terminalOutcome: execution.terminalOutcome,\n ...(execution.terminalFailureReason\n ? { terminalFailureReason: execution.terminalFailureReason }\n : {}),\n outcome,\n splitTag: options.splitTag,\n scenarioId: options.scenarioId ?? cell.scenarioId,\n ...(options.agentProfile ? { agentProfile: options.agentProfile } : {}),\n })\n}\n\nexport function campaignCellExecutionEvidence<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n): CampaignCellExecutionEvidence {\n if (cell.errorStage === 'dispatch') {\n return {\n terminalOutcome: 'failed',\n executionErrorCount: 1,\n ...(cell.error ? { terminalFailureReason: cell.error } : {}),\n }\n }\n if (cell.errorStage === 'judge') {\n return {\n terminalOutcome: 'succeeded',\n executionErrorCount: 0,\n judgeErrorCount: 1,\n }\n }\n if (!cell.error) {\n return { terminalOutcome: 'succeeded', executionErrorCount: 0 }\n }\n return {\n terminalOutcome: 'unknown',\n unclassifiedErrorCount: 1,\n }\n}\n\n/**\n * Produce the only task-quality view used by campaign aggregates and exports.\n *\n * Successful judge results remain available for diagnosis after another judge\n * fails, but a task score exists only for an error-free cell whose reported\n * judge values are all finite.\n */\nexport function projectCampaignCellQuality<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n): CampaignCellQualityProjection {\n if (cell.errorStage === 'dispatch') {\n return { successfulJudgeScores: {}, failedJudges: [], raw: {} }\n }\n\n const perJudge: Record<string, Record<string, number>> = {}\n const successfulJudgeScores: Record<string, JudgeScore> = {}\n const dimensionValues = new Map<string, number[]>()\n const composites: number[] = []\n const notes: string[] = []\n const failedJudges = new Set<string>(\n cell.errorStage === 'judge' ? [cell.errorJudge ?? 'unknown-judge'] : [],\n )\n const raw: Record<string, number> = {}\n\n for (const [judgeName, score] of Object.entries(cell.judgeScores)) {\n const finiteDimensions = Object.values(score.dimensions).every(Number.isFinite)\n if (score.failed || !Number.isFinite(score.composite) || !finiteDimensions) {\n failedJudges.add(judgeName)\n continue\n }\n\n composites.push(score.composite)\n successfulJudgeScores[judgeName] = score\n const dimensions = { ...score.dimensions }\n perJudge[judgeName] = dimensions\n for (const [dimension, value] of Object.entries(dimensions)) {\n raw[`${judgeName}.${dimension}`] = value\n const values = dimensionValues.get(dimension) ?? []\n values.push(value)\n dimensionValues.set(dimension, values)\n }\n if (score.notes) notes.push(`${judgeName}: ${score.notes}`)\n for (const failedJudge of score.failedJudges ?? []) {\n failedJudges.add(`${judgeName}/${failedJudge}`)\n }\n }\n\n if (failedJudges.size > 0) raw.judge_error_count = failedJudges.size\n const sortedFailedJudges = [...failedJudges].sort()\n if (composites.length === 0) {\n return {\n successfulJudgeScores,\n failedJudges: sortedFailedJudges,\n raw,\n }\n }\n\n const composite = mean(composites)\n const perDimMean = Object.fromEntries(\n [...dimensionValues.entries()].map(([dimension, values]) => [dimension, mean(values)]),\n )\n const complete =\n cell.error === undefined && cell.errorStage === undefined && failedJudges.size === 0\n if (complete) raw.composite = composite\n\n return {\n ...(complete ? { score: composite } : {}),\n raw,\n successfulJudgeScores,\n failedJudges: sortedFailedJudges,\n judgeScores: {\n perJudge,\n perDimMean,\n composite,\n ...(sortedFailedJudges.length > 0 ? { failedJudges: sortedFailedJudges } : {}),\n ...(notes.length > 0 ? { notes: notes.join(' | ') } : {}),\n },\n }\n}\n\n/** Read the canonical task score without recomputing cell quality. */\nexport function campaignCellTaskScore<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n): number | undefined {\n return projectCampaignCellQuality(cell).score\n}\n\n/** Read canonical successful judge dimensions without recomputing cell quality. */\nexport function campaignCellJudgeDimensions<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n): Record<string, Record<string, number>> {\n return projectCampaignCellQuality(cell).judgeScores?.perJudge ?? {}\n}\n\nfunction finiteMetrics(metrics: Record<string, number> | undefined): Record<string, number> {\n const finite: Record<string, number> = {}\n for (const [key, value] of Object.entries(metrics ?? {})) {\n if (Number.isFinite(value)) finite[key] = value\n }\n return finite\n}\n\nfunction mean(values: number[]): number {\n return values.reduce((sum, value) => sum + value, 0) / values.length\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FAILURE_CLASSES
|
|
3
|
+
} from "./chunk-MA6HLL3S.js";
|
|
4
|
+
import {
|
|
5
|
+
ValidationError
|
|
6
|
+
} from "./chunk-ONWEPEDO.js";
|
|
1
7
|
import {
|
|
2
8
|
LLM_CACHED_TOKEN_ATTR_KEYS,
|
|
3
9
|
LLM_CACHE_WRITE_TOKEN_ATTR_KEYS,
|
|
@@ -330,9 +336,51 @@ function readNumber(attributes, keys) {
|
|
|
330
336
|
return void 0;
|
|
331
337
|
}
|
|
332
338
|
|
|
339
|
+
// src/trace/task-failure-attributes.ts
|
|
340
|
+
var TASK_FAILURE_CLASS_ATTR = "tangle.task.failure_class";
|
|
341
|
+
var TASK_FAILURE_MODE_ATTR = "tangle.task.failure_mode";
|
|
342
|
+
function readTaskFailureLabels(roots, context) {
|
|
343
|
+
const failureClass = readConsistentRootString(roots, TASK_FAILURE_CLASS_ATTR, context);
|
|
344
|
+
const failureMode = readConsistentRootString(roots, TASK_FAILURE_MODE_ATTR, context);
|
|
345
|
+
if (failureClass !== void 0 && !FAILURE_CLASSES.includes(failureClass)) {
|
|
346
|
+
throw new ValidationError(
|
|
347
|
+
`${context}: ${TASK_FAILURE_CLASS_ATTR} must be one of ${FAILURE_CLASSES.join(", ")}`
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
if (failureMode !== void 0 && (failureClass === void 0 || failureClass === "success")) {
|
|
351
|
+
throw new ValidationError(
|
|
352
|
+
`${context}: ${TASK_FAILURE_MODE_ATTR} requires a non-success ${TASK_FAILURE_CLASS_ATTR}`
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
if (failureClass === void 0) return {};
|
|
356
|
+
if (failureClass === "success") return { failureClass };
|
|
357
|
+
return {
|
|
358
|
+
failureClass,
|
|
359
|
+
...failureMode ? { failureMode } : {}
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function readConsistentRootString(roots, key, context) {
|
|
363
|
+
const values = /* @__PURE__ */ new Set();
|
|
364
|
+
for (const root of roots) {
|
|
365
|
+
if (!Object.hasOwn(root.attributes, key)) continue;
|
|
366
|
+
const value = root.attributes[key];
|
|
367
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
368
|
+
throw new ValidationError(`${context}: ${key} must be a non-empty string`);
|
|
369
|
+
}
|
|
370
|
+
values.add(value);
|
|
371
|
+
}
|
|
372
|
+
if (values.size > 1) {
|
|
373
|
+
throw new ValidationError(
|
|
374
|
+
`${context}: conflicting ${key} values: ${[...values].sort().join(", ")}`
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
return values.values().next().value;
|
|
378
|
+
}
|
|
379
|
+
|
|
333
380
|
export {
|
|
334
381
|
summarizeTraceErrors,
|
|
335
382
|
summarizeExecutionMeasurements,
|
|
336
|
-
recordAggregateMeasurements
|
|
383
|
+
recordAggregateMeasurements,
|
|
384
|
+
readTaskFailureLabels
|
|
337
385
|
};
|
|
338
|
-
//# sourceMappingURL=chunk-
|
|
386
|
+
//# sourceMappingURL=chunk-7ZZMD7UK.js.map
|