@openpond/evals 0.8.1 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -0
- package/dist/deterministic-graders.js +110 -0
- package/dist/graders.js +9 -51
- package/dist/index.js +1 -0
- package/dist/metric-policy.js +50 -0
- package/dist/metrics-node.js +16 -0
- package/dist/metrics.js +105 -0
- package/dist/runs.js +12 -0
- package/dist/tasksets.js +5 -0
- package/dist/types/builtin-benchmarks/harness-refiner.d.ts +14 -0
- package/dist/types/builtin-benchmarks/harness-refiner.d.ts.map +1 -1
- package/dist/types/conformance.d.ts +28 -0
- package/dist/types/conformance.d.ts.map +1 -1
- package/dist/types/deterministic-graders.d.ts +23 -0
- package/dist/types/deterministic-graders.d.ts.map +1 -0
- package/dist/types/evidence/conformance.d.ts +4 -4
- package/dist/types/evidence/contracts.d.ts +8 -8
- package/dist/types/graders.d.ts +1 -0
- package/dist/types/graders.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/javascript-isolate.d.ts +1 -1
- package/dist/types/javascript-isolate.d.ts.map +1 -1
- package/dist/types/learning/admission.d.ts +3 -3
- package/dist/types/learning/contracts.d.ts +3 -3
- package/dist/types/learning/operations.d.ts +12 -12
- package/dist/types/learning/repository.d.ts +26 -4
- package/dist/types/learning/repository.d.ts.map +1 -1
- package/dist/types/learning/transport.d.ts +33 -11
- package/dist/types/learning/transport.d.ts.map +1 -1
- package/dist/types/metric-policy.d.ts +112 -0
- package/dist/types/metric-policy.d.ts.map +1 -0
- package/dist/types/metrics-node.d.ts +8 -0
- package/dist/types/metrics-node.d.ts.map +1 -0
- package/dist/types/metrics.d.ts +37 -0
- package/dist/types/metrics.d.ts.map +1 -0
- package/dist/types/preferences.d.ts +3 -3
- package/dist/types/rewards.d.ts +9 -9
- package/dist/types/runs.d.ts +88 -0
- package/dist/types/runs.d.ts.map +1 -1
- package/dist/types/tasksets.d.ts +44 -0
- package/dist/types/tasksets.d.ts.map +1 -1
- package/dist/types/telemetry-analysis.d.ts +1 -1
- package/dist/types/telemetry-bundle.d.ts +4 -4
- package/dist/types/telemetry.d.ts +3 -3
- package/package.json +9 -1
- package/schemas/learning/v1/package.schema.json +108 -0
package/README.md
CHANGED
|
@@ -44,6 +44,53 @@ Subpath exports are available at `/harness`, `/tasksets`, `/benchmarks`, `/grade
|
|
|
44
44
|
not a hosted client. It does not execute OpenPond Desktop or Sandbox sessions,
|
|
45
45
|
resolve credentials, or persist artifacts.
|
|
46
46
|
|
|
47
|
+
## Ordinary graders
|
|
48
|
+
|
|
49
|
+
`evaluateDeterministicGrader` and `portableDeterministicCheck` from `/graders`
|
|
50
|
+
provide the shared local/portable interpretation of ordinary checks. They retain
|
|
51
|
+
explicit exact-text normalization, final-answer extraction, structured JSON,
|
|
52
|
+
artifact and runtime-event requirements, and structural state comparisons.
|
|
53
|
+
Native test/diff checks declare their expected output field when exported.
|
|
54
|
+
Empty, unsupported or unavailable checks remain unscorable rather than earning
|
|
55
|
+
a zero or a passing reward. Desktop grade components preserve null scores and
|
|
56
|
+
display them as not scored.
|
|
57
|
+
|
|
58
|
+
## Authored Taskset metrics
|
|
59
|
+
|
|
60
|
+
`@openpond/evals/metrics` exports the shared `TasksetMetricPolicySchema` and
|
|
61
|
+
`executeTasksetMetric`. Supply the policy from the pinned Taskset Release, its
|
|
62
|
+
Run Manifest, and verified attempt receipts. The result carries the policy,
|
|
63
|
+
policy hash, all input receipt references, population counts and a content hash.
|
|
64
|
+
It is separate from the evaluation's ordinary mean-score accounting.
|
|
65
|
+
|
|
66
|
+
The release's optional `metrics` field is the authoritative policy. For complete
|
|
67
|
+
evaluations, use `aggregateTasksetEvaluationReceipts` or the Node
|
|
68
|
+
`aggregateTasksetEvaluationInWorker` export. They bind the release and task IDs
|
|
69
|
+
to the manifest, calculate `authoredMetric`, and attach it only to the exact
|
|
70
|
+
receipt population. `meanScore` remains the ordinary mean. Hosts should capture
|
|
71
|
+
and validate custom source with `assertTasksetMetricSource` before model work,
|
|
72
|
+
then retain those bytes throughout the run. Complete Taskset packages require
|
|
73
|
+
the declared module as a private, content-matching file.
|
|
74
|
+
|
|
75
|
+
Mean score, explicit grader pass rate, weighted mean and custom aggregation use
|
|
76
|
+
one population rule: nonterminal attempts, infrastructure failures, timeouts and
|
|
77
|
+
cancellations are excluded. Other missing or ineligible rewards obey the
|
|
78
|
+
policy's `zero` or `exclude` setting. Pass rate requires an explicit boolean
|
|
79
|
+
`passed` verdict. Empty populations return `null`.
|
|
80
|
+
|
|
81
|
+
Weighted means require positive `taskWeights` keyed by task ID; each attempt
|
|
82
|
+
uses its task's declared weight. Missing weights are errors. Custom modules
|
|
83
|
+
export `aggregate(scores)` (or the declared export) and return a finite number
|
|
84
|
+
between zero and one. Exact UTF-8 source must match the policy's SHA-256 before
|
|
85
|
+
execution. Module source is limited to 512 KiB and custom inputs to 4 MiB.
|
|
86
|
+
|
|
87
|
+
Node hosts use `executeTasksetMetricInWorker` from `@openpond/evals/metrics/node`.
|
|
88
|
+
It strips type annotations from `.ts`, `.mts` and `.cts` modules, then executes
|
|
89
|
+
them in a fresh deterministic interpreter without host APIs or imports. Workers
|
|
90
|
+
stop before success, failure or cancellation is returned. Other hosts pass an
|
|
91
|
+
isolated executor to the portable function; authored source must never run in
|
|
92
|
+
the host JavaScript context.
|
|
93
|
+
|
|
47
94
|
## Benchmarks
|
|
48
95
|
|
|
49
96
|
`BenchmarkDefinition` binds a named benchmark to an immutable Taskset Release,
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { contentHash } from "@openpond/harness";
|
|
2
|
+
import { validateTaskSchema, validateTaskValue } from "./task-schema.js";
|
|
3
|
+
/** Local and portable execution interpret the same declared checks. Missing or
|
|
4
|
+
* unsupported checks are unscorable; an empty check cannot earn a reward. */
|
|
5
|
+
export function evaluateDeterministicGrader(input) {
|
|
6
|
+
const { grader, task, evidence } = input;
|
|
7
|
+
const config = grader.config;
|
|
8
|
+
if (grader.kind === "content") {
|
|
9
|
+
const outputField = text(config.outputField) ?? "text";
|
|
10
|
+
const actual = text(evidence.output[outputField]);
|
|
11
|
+
if (config.operator === "exact_equals") {
|
|
12
|
+
const expected = text(config.expectedValue);
|
|
13
|
+
if (expected === null)
|
|
14
|
+
return unavailable("Exact content grading requires an expected value.");
|
|
15
|
+
const normalize = (value) => {
|
|
16
|
+
const unicode = config.normalizeUnicode === true ? value.normalize("NFC") : value;
|
|
17
|
+
return config.trimWhitespace === true ? unicode.trim() : unicode;
|
|
18
|
+
};
|
|
19
|
+
return outcome(actual !== null && normalize(actual) === normalize(expected));
|
|
20
|
+
}
|
|
21
|
+
if (config.operator !== undefined && config.operator !== "final_answer_equals_expected")
|
|
22
|
+
return unavailable("Unsupported content grader operator.");
|
|
23
|
+
if (config.operator === undefined && (config.includes !== undefined || config.excludes !== undefined)) {
|
|
24
|
+
const includes = strings(config.includes), excludes = strings(config.excludes);
|
|
25
|
+
if (!includes.length && !excludes.length)
|
|
26
|
+
return unavailable("Content grading requires a nonempty check.");
|
|
27
|
+
const value = typeof evidence.output.text === "string" ? evidence.output.text : JSON.stringify(evidence.output);
|
|
28
|
+
return outcome(includes.every(item => value.includes(item)) && excludes.every(item => !value.includes(item)));
|
|
29
|
+
}
|
|
30
|
+
const expected = text(config.expectedValue) ?? text(task.expectedOutput?.[text(config.expectedField) ?? "text"]);
|
|
31
|
+
const normalize = config.operator === "final_answer_equals_expected" ? normalizeFinalAnswer : normalizeContent;
|
|
32
|
+
if (expected === null || !normalize(expected))
|
|
33
|
+
return unavailable("Content grading requires a nonempty expected value.");
|
|
34
|
+
return outcome(actual !== null && normalize(actual) === normalize(expected));
|
|
35
|
+
}
|
|
36
|
+
if (grader.kind === "schema") {
|
|
37
|
+
if (config.operator !== undefined && config.operator !== "json_schema_subset")
|
|
38
|
+
return unavailable("Unsupported schema grader operator.");
|
|
39
|
+
const schema = config.operator === "json_schema_subset" ? config.schema : config.jsonSchema;
|
|
40
|
+
if (schema !== undefined) {
|
|
41
|
+
const checked = validateTaskSchema(schema);
|
|
42
|
+
if (!checked.valid)
|
|
43
|
+
return unavailable(checked.issues[0].message);
|
|
44
|
+
let value = evidence.output;
|
|
45
|
+
if (config.operator === "json_schema_subset") {
|
|
46
|
+
const encoded = evidence.output[text(config.jsonField) ?? "text"];
|
|
47
|
+
if (typeof encoded === "string") {
|
|
48
|
+
try {
|
|
49
|
+
value = JSON.parse(encoded.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, ""));
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return outcome(false, "The model output was not valid JSON.");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const checkedValue = validateTaskValue(schema, value);
|
|
57
|
+
return outcome(checkedValue.valid, checkedValue.valid ? undefined : checkedValue.issues.map(issue => issue.message).join(" "));
|
|
58
|
+
}
|
|
59
|
+
const required = strings(config.requiredKeys);
|
|
60
|
+
if (!required.length)
|
|
61
|
+
return unavailable("Schema grading requires a JSON Schema or explicit required keys.");
|
|
62
|
+
return outcome(required.every(key => Object.hasOwn(evidence.output, key)));
|
|
63
|
+
}
|
|
64
|
+
if (grader.kind === "artifact") {
|
|
65
|
+
const contains = text(config.refIncludes);
|
|
66
|
+
if (!contains)
|
|
67
|
+
return unavailable("Artifact grading requires a declared artifact reference.");
|
|
68
|
+
return outcome(evidence.artifactRefs.some(ref => ref.includes(contains)));
|
|
69
|
+
}
|
|
70
|
+
if (grader.kind === "runtime_event") {
|
|
71
|
+
const required = strings(config.requiredEvents);
|
|
72
|
+
if (!required.length)
|
|
73
|
+
return unavailable("Runtime event grading requires declared events.");
|
|
74
|
+
return outcome(required.every(event => evidence.runtimeEventRefs.some(ref => ref.includes(event))));
|
|
75
|
+
}
|
|
76
|
+
if (config.operator === "output_field_equals") {
|
|
77
|
+
const field = text(config.outputField);
|
|
78
|
+
if (!field || !Object.hasOwn(config, "expectedValue"))
|
|
79
|
+
return unavailable("Output comparison requires a field and expected value.");
|
|
80
|
+
return outcome(Object.hasOwn(evidence.output, field) && contentHash(evidence.output[field]) === contentHash(config.expectedValue));
|
|
81
|
+
}
|
|
82
|
+
if (config.operator !== undefined)
|
|
83
|
+
return unavailable("Unsupported state grader operator.");
|
|
84
|
+
const fields = strings(config.fields);
|
|
85
|
+
const compared = fields.length ? fields : Object.keys(task.expectedOutput ?? {});
|
|
86
|
+
if (!compared.length || compared.some(field => !task.expectedOutput || !Object.hasOwn(task.expectedOutput, field)))
|
|
87
|
+
return unavailable("State grading requires expected values for every compared field.");
|
|
88
|
+
return outcome(compared.every(field => Object.hasOwn(evidence.output, field) && contentHash(evidence.output[field]) === contentHash(task.expectedOutput[field])));
|
|
89
|
+
}
|
|
90
|
+
/** Encode native artifact/test checks without changing their meaning in transit. */
|
|
91
|
+
export function portableDeterministicCheck(grader) {
|
|
92
|
+
if (grader.kind === "file") {
|
|
93
|
+
const { pathIncludes, ...config } = grader.config;
|
|
94
|
+
return { kind: "artifact", config: { ...config, ...(pathIncludes === undefined ? {} : { refIncludes: pathIncludes }) } };
|
|
95
|
+
}
|
|
96
|
+
if (grader.kind === "diff" || grader.kind === "test")
|
|
97
|
+
return { kind: "state", config: { operator: "output_field_equals", outputField: grader.kind === "test" ? "testsPassed" : "diffAccepted", expectedValue: true } };
|
|
98
|
+
return { kind: grader.kind, config: grader.config };
|
|
99
|
+
}
|
|
100
|
+
function outcome(passed, feedback) { return { score: Number(passed), passed, feedback: feedback ?? (passed ? "Deterministic grader passed." : "Deterministic grader failed.") }; }
|
|
101
|
+
function unavailable(feedback) { return { score: null, passed: false, feedback }; }
|
|
102
|
+
function text(value) { return typeof value === "string" ? value : null; }
|
|
103
|
+
function strings(value) { return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.trim().length > 0) : []; }
|
|
104
|
+
function normalizeContent(value) { return value.normalize("NFKC").trim().replace(/[,,]/g, "").replace(/[.\s]+$/g, "").replace(/\s+/g, " "); }
|
|
105
|
+
function normalizeFinalAnswer(value) {
|
|
106
|
+
const boxed = [...value.matchAll(/\\boxed\{([^{}]+)\}/g)].at(-1)?.[1];
|
|
107
|
+
const hashAnswer = value.match(/####\s*([^\n\r]+)/)?.[1];
|
|
108
|
+
const label = value.match(/(?:final\s+answer|answer)\s*(?::|is|=)\s*([^\n\r]+)/i)?.[1];
|
|
109
|
+
return normalizeContent((boxed ?? hashAnswer ?? label ?? value).normalize("NFKC").trim().replace(/^\$+|\$+$/g, "").replace(/^\\\(|\\\)$/g, ""));
|
|
110
|
+
}
|
package/dist/graders.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { FailureClassSchema, ReleaseHashSchema, ReleaseIdSchema, contentHash } from "@openpond/harness";
|
|
3
|
-
import {
|
|
3
|
+
import { evaluateDeterministicGrader } from "./deterministic-graders.js";
|
|
4
|
+
export { evaluateDeterministicGrader, portableDeterministicCheck } from "./deterministic-graders.js";
|
|
4
5
|
export const GraderEvidenceContentSchema = z.object({
|
|
5
6
|
schemaVersion: z.literal("openpond.graderEvidence.v1"),
|
|
6
7
|
graderId: ReleaseIdSchema,
|
|
@@ -43,55 +44,15 @@ export async function gradeEvidence(input) {
|
|
|
43
44
|
}));
|
|
44
45
|
}
|
|
45
46
|
function gradeDeterministic(grader, task, attempt) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const outputField = string(config.outputField) ?? "text";
|
|
50
|
-
const actual = string(attempt.output[outputField]);
|
|
51
|
-
const expected = string(config.expectedValue) ?? string(task.expectedOutput?.[string(config.expectedField) ?? "text"]);
|
|
52
|
-
if (expected === null || !normalize(expected))
|
|
53
|
-
return unavailable("Content grading requires a nonempty expected value.");
|
|
54
|
-
passed = actual !== null && expected !== null && normalize(actual) === normalize(expected);
|
|
55
|
-
}
|
|
56
|
-
else if (grader.kind === "schema") {
|
|
57
|
-
if (config.jsonSchema !== undefined) {
|
|
58
|
-
const schema = validateTaskSchema(config.jsonSchema);
|
|
59
|
-
if (!schema.valid)
|
|
60
|
-
return unavailable(schema.issues[0].message);
|
|
61
|
-
passed = validateTaskValue(config.jsonSchema, attempt.output).valid;
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
const required = strings(config.requiredKeys);
|
|
65
|
-
if (!required.length)
|
|
66
|
-
return unavailable("Schema grading requires a JSON Schema or explicit required keys.");
|
|
67
|
-
passed = required.every((key) => Object.hasOwn(attempt.output, key));
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
else if (grader.kind === "artifact") {
|
|
71
|
-
const contains = string(config.refIncludes) ?? "";
|
|
72
|
-
if (!contains)
|
|
73
|
-
return unavailable("Artifact grading requires a declared artifact reference.");
|
|
74
|
-
passed = attempt.artifactRefs.some((ref) => ref.includes(contains));
|
|
75
|
-
}
|
|
76
|
-
else if (grader.kind === "runtime_event") {
|
|
77
|
-
const requiredEvents = strings(config.requiredEvents);
|
|
78
|
-
if (!requiredEvents.length)
|
|
79
|
-
return unavailable("Runtime event grading requires declared events.");
|
|
80
|
-
passed = requiredEvents.every((required) => attempt.runtimeEventRefs.some((ref) => ref.includes(required)));
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
const fields = strings(config.fields);
|
|
84
|
-
const compared = fields.length ? fields : Object.keys(task.expectedOutput ?? {});
|
|
85
|
-
if (!compared.length || compared.some((field) => !task.expectedOutput || !Object.hasOwn(task.expectedOutput, field)))
|
|
86
|
-
return unavailable("State grading requires expected values for every compared field.");
|
|
87
|
-
passed = compared.every((field) => Object.hasOwn(attempt.output, field) && contentHash(attempt.output[field]) === contentHash(task.expectedOutput[field]));
|
|
88
|
-
}
|
|
47
|
+
const result = evaluateDeterministicGrader({ grader, task, evidence: attempt });
|
|
48
|
+
if (result.score === null)
|
|
49
|
+
return unavailable(result.feedback);
|
|
89
50
|
return {
|
|
90
|
-
score:
|
|
91
|
-
passed,
|
|
51
|
+
score: result.score,
|
|
52
|
+
passed: result.passed,
|
|
92
53
|
rewardEligible: grader.rewardEligible,
|
|
93
|
-
failureClass: passed ? null : "policy_failure",
|
|
94
|
-
feedback: [
|
|
54
|
+
failureClass: result.passed ? null : "policy_failure",
|
|
55
|
+
feedback: [result.feedback],
|
|
95
56
|
visibleEvidenceRefs: [...attempt.runtimeEventRefs, ...attempt.artifactRefs],
|
|
96
57
|
privilegedEvidenceRefs: grader.privileged ? [task.privilegedContextRef].filter((ref) => ref !== null) : [],
|
|
97
58
|
};
|
|
@@ -109,6 +70,3 @@ function evidence(grader, result) {
|
|
|
109
70
|
function unavailable(message) {
|
|
110
71
|
return { score: null, passed: false, rewardEligible: false, failureClass: "grader_failure", feedback: [message], visibleEvidenceRefs: [], privilegedEvidenceRefs: [] };
|
|
111
72
|
}
|
|
112
|
-
function string(value) { return typeof value === "string" ? value : null; }
|
|
113
|
-
function strings(value) { return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.trim().length > 0) : []; }
|
|
114
|
-
function normalize(value) { return value.normalize("NFKC").trim().replace(/[,,]/g, "").replace(/[.\s]+$/g, "").replace(/\s+/g, " "); }
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export * from "./graders.js";
|
|
|
8
8
|
export * from "./harness.js";
|
|
9
9
|
export * from "./learned-preference.js";
|
|
10
10
|
export * from "./runs.js";
|
|
11
|
+
export * from "./metrics.js";
|
|
11
12
|
export * from "./model-improvement-qualification.js";
|
|
12
13
|
export * from "./preferences.js";
|
|
13
14
|
export * from "./review-conformance.js";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { assertContentHash, contentHash, ImmutableReleaseRefSchema, ReleaseHashSchema } from "@openpond/harness";
|
|
3
|
+
const MetricIdSchema = z.string().trim().min(1).max(240);
|
|
4
|
+
const ModulePathSchema = z.string().trim().min(1).max(1_000).refine((value) => !/[\\:\0]/.test(value) && value.split("/").every((part) => part && part !== "." && part !== ".." && !part.startsWith(".env")), "Metric modules must use a safe relative path.");
|
|
5
|
+
export const TasksetMetricPolicySchema = z.object({
|
|
6
|
+
schemaVersion: z.literal("openpond.tasksetMetricPolicy.v1"),
|
|
7
|
+
primaryMetric: MetricIdSchema,
|
|
8
|
+
aggregation: z.enum(["mean_score", "pass_rate", "weighted_mean", "custom"]),
|
|
9
|
+
missingReward: z.enum(["zero", "exclude"]),
|
|
10
|
+
taskWeights: z.record(MetricIdSchema, z.number().positive().max(1_000_000)).optional(),
|
|
11
|
+
customAggregator: z.object({
|
|
12
|
+
module: ModulePathSchema,
|
|
13
|
+
exportName: z.string().trim().regex(/^[A-Za-z_$][A-Za-z0-9_$]*$/),
|
|
14
|
+
contentHash: ReleaseHashSchema,
|
|
15
|
+
timeoutMs: z.number().int().positive().max(300_000),
|
|
16
|
+
networkPolicy: z.literal("none"),
|
|
17
|
+
}).strict().nullable(),
|
|
18
|
+
}).strict().superRefine((policy, context) => {
|
|
19
|
+
if ((policy.aggregation === "custom") !== (policy.customAggregator !== null)) {
|
|
20
|
+
context.addIssue({ code: "custom", path: ["customAggregator"], message: "Only custom aggregation requires a content-hashed module." });
|
|
21
|
+
}
|
|
22
|
+
if (policy.aggregation === "weighted_mean" ? !policy.taskWeights || !Object.keys(policy.taskWeights).length : policy.taskWeights !== undefined) {
|
|
23
|
+
context.addIssue({ code: "custom", path: ["taskWeights"], message: "Only weighted means require explicit positive task weights." });
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
export const TasksetMetricResultContentSchema = z.object({
|
|
27
|
+
schemaVersion: z.literal("openpond.tasksetMetricResult.v1"),
|
|
28
|
+
runManifest: ImmutableReleaseRefSchema,
|
|
29
|
+
tasksetRelease: ImmutableReleaseRefSchema,
|
|
30
|
+
policy: TasksetMetricPolicySchema,
|
|
31
|
+
policyHash: ReleaseHashSchema,
|
|
32
|
+
receiptRefs: z.array(ImmutableReleaseRefSchema).min(1).max(1_000_000),
|
|
33
|
+
includedCount: z.number().int().nonnegative(),
|
|
34
|
+
missingRewardCount: z.number().int().nonnegative(),
|
|
35
|
+
excludedCount: z.number().int().nonnegative(),
|
|
36
|
+
value: z.number().min(0).max(1).nullable(),
|
|
37
|
+
}).strict();
|
|
38
|
+
export const TasksetMetricResultSchema = TasksetMetricResultContentSchema.extend({ contentHash: ReleaseHashSchema }).strict();
|
|
39
|
+
export function assertTasksetMetricResult(input) {
|
|
40
|
+
const result = TasksetMetricResultSchema.parse(input);
|
|
41
|
+
assertContentHash(result, "Taskset metric result");
|
|
42
|
+
if (result.policyHash !== contentHash(result.policy))
|
|
43
|
+
throw new Error("Taskset metric policy hash differs from its policy.");
|
|
44
|
+
if (result.includedCount + result.excludedCount !== result.receiptRefs.length
|
|
45
|
+
|| (result.includedCount === 0) !== (result.value === null)
|
|
46
|
+
|| result.missingRewardCount > (result.policy.missingReward === "zero" ? result.includedCount : result.excludedCount)
|
|
47
|
+
|| new Set(result.receiptRefs.map(ref => ref.id)).size !== result.receiptRefs.length) {
|
|
48
|
+
throw new Error("Taskset metric population differs from its receipt references.");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { stripTypeScriptTypes } from "node:module";
|
|
2
|
+
import { executeJavaScriptIsolateInWorker } from "./javascript-isolate-node.js";
|
|
3
|
+
import { aggregateTasksetEvaluationReceipts, executeTasksetMetric } from "./metrics.js";
|
|
4
|
+
/** Verifies original source before stripping TS, then waits for worker termination
|
|
5
|
+
* on success, error or cancellation. Authored imports and host APIs are unavailable. */
|
|
6
|
+
export function executeTasksetMetricInWorker(input) {
|
|
7
|
+
return executeTasksetMetric(input, executeMetric);
|
|
8
|
+
}
|
|
9
|
+
export function aggregateTasksetEvaluationInWorker(input) {
|
|
10
|
+
return aggregateTasksetEvaluationReceipts(input, executeMetric);
|
|
11
|
+
}
|
|
12
|
+
const executeMetric = ({ source, module, exportName, scores, timeoutMs, signal }) => executeJavaScriptIsolateInWorker({
|
|
13
|
+
source: /\.[cm]?ts$/.test(module) ? stripTypeScriptTypes(source, { mode: "strip" }) : source,
|
|
14
|
+
exportName, value: scores, timeoutMs, signal,
|
|
15
|
+
maxResultBytes: 1_024, deterministic: true, errorPrefix: "metric",
|
|
16
|
+
});
|
package/dist/metrics.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { assertContentHash, contentHash, sha256 } from "@openpond/harness";
|
|
2
|
+
import { aggregateEvaluationReceipts, RunManifestSchema, verifyAttemptReceipt } from "./runs.js";
|
|
3
|
+
import { TasksetMetricPolicySchema, TasksetMetricResultContentSchema, TasksetMetricResultSchema } from "./metric-policy.js";
|
|
4
|
+
import { assertTasksetRelease } from "./tasksets.js";
|
|
5
|
+
export * from "./metric-policy.js";
|
|
6
|
+
/** Preflight the exact metric source before any model or tool execution. */
|
|
7
|
+
export function assertTasksetMetricSource(taskset, source) {
|
|
8
|
+
assertTasksetRelease(taskset);
|
|
9
|
+
if (taskset.metrics?.customAggregator)
|
|
10
|
+
assertMetricSource(taskset.metrics.customAggregator, source);
|
|
11
|
+
}
|
|
12
|
+
/** Bind the declared metric to one frozen release and population, retaining
|
|
13
|
+
* ordinary mean-score accounting independently of the authored calculation. */
|
|
14
|
+
export async function aggregateTasksetEvaluationReceipts(input, executor) {
|
|
15
|
+
assertTasksetMetricSource(input.taskset, input.source);
|
|
16
|
+
if (input.taskset.id !== input.manifest.tasksetRelease.id || input.taskset.contentHash !== input.manifest.tasksetRelease.contentHash)
|
|
17
|
+
throw new Error("Metric Taskset differs from the Run Manifest's pinned release.");
|
|
18
|
+
const taskIds = new Set(input.taskset.tasks.map(task => task.id));
|
|
19
|
+
if (input.receipts.some(receipt => !taskIds.has(receipt.taskId)))
|
|
20
|
+
throw new Error("Metric receipt names a task outside the pinned Taskset.");
|
|
21
|
+
const authoredMetric = input.taskset.metrics ? await executeTasksetMetric({ ...input, policy: input.taskset.metrics }, executor) : undefined;
|
|
22
|
+
return aggregateEvaluationReceipts({ id: input.id, manifest: input.manifest, receipts: input.receipts, metadata: input.metadata, authoredMetric });
|
|
23
|
+
}
|
|
24
|
+
/** Hosts supply the policy from the pinned Taskset, never a mutable form.
|
|
25
|
+
* Operational failures and nonterminal receipts are excluded for every policy.
|
|
26
|
+
* Missing rewards on the remaining receipts obey zero/exclude. A task's weight
|
|
27
|
+
* applies to each of its attempts; pass rate uses the grader's explicit verdict.
|
|
28
|
+
*/
|
|
29
|
+
export async function executeTasksetMetric(input, executor) {
|
|
30
|
+
input.signal?.throwIfAborted();
|
|
31
|
+
const policy = TasksetMetricPolicySchema.parse(input.policy);
|
|
32
|
+
const manifest = RunManifestSchema.parse(input.manifest);
|
|
33
|
+
assertContentHash(manifest, "Metric Run Manifest");
|
|
34
|
+
if (!input.receipts.length || input.receipts.length > 1_000_000)
|
|
35
|
+
throw new Error("Metric execution requires 1 to 1,000,000 attempt receipts.");
|
|
36
|
+
const ids = new Set();
|
|
37
|
+
const scores = [];
|
|
38
|
+
const weights = [];
|
|
39
|
+
let missingRewardCount = 0;
|
|
40
|
+
for (const receipt of input.receipts) {
|
|
41
|
+
input.signal?.throwIfAborted();
|
|
42
|
+
if (!verifyAttemptReceipt(receipt))
|
|
43
|
+
throw new Error(`Metric receipt ${receipt.id} has an invalid content hash.`);
|
|
44
|
+
if (receipt.runManifest.id !== manifest.id || receipt.runManifest.contentHash !== manifest.contentHash)
|
|
45
|
+
throw new Error(`Metric receipt ${receipt.id} belongs to a different Run Manifest.`);
|
|
46
|
+
if (ids.has(receipt.id))
|
|
47
|
+
throw new Error(`Metric receipt ${receipt.id} is duplicated.`);
|
|
48
|
+
ids.add(receipt.id);
|
|
49
|
+
if (!receipt.terminal || ["infrastructure_failure", "timeout", "cancelled"].includes(receipt.failureClass ?? ""))
|
|
50
|
+
continue;
|
|
51
|
+
const score = receipt.metadata.score;
|
|
52
|
+
if (typeof score === "number" && (!Number.isFinite(score) || score < 0 || score > 1))
|
|
53
|
+
throw new Error(`Metric receipt ${receipt.id} has an invalid score.`);
|
|
54
|
+
const hasReward = receipt.metadata.rewardEligible === true && typeof score === "number"
|
|
55
|
+
&& (policy.aggregation !== "pass_rate" || typeof receipt.metadata.passed === "boolean");
|
|
56
|
+
if (!hasReward) {
|
|
57
|
+
missingRewardCount += 1;
|
|
58
|
+
if (policy.missingReward === "exclude")
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const weight = policy.aggregation === "weighted_mean" && Object.hasOwn(policy.taskWeights, receipt.taskId) ? policy.taskWeights[receipt.taskId] : undefined;
|
|
62
|
+
if (policy.aggregation === "weighted_mean" && weight === undefined)
|
|
63
|
+
throw new Error(`Metric policy has no weight for task ${receipt.taskId}.`);
|
|
64
|
+
scores.push(hasReward ? policy.aggregation === "pass_rate" ? Number(receipt.metadata.passed) : score : 0);
|
|
65
|
+
weights.push(weight ?? 1);
|
|
66
|
+
}
|
|
67
|
+
let value = null;
|
|
68
|
+
const receiptRefs = input.receipts.map(({ id, contentHash }) => ({ id, contentHash }));
|
|
69
|
+
const includedCount = scores.length;
|
|
70
|
+
if (policy.customAggregator) {
|
|
71
|
+
assertMetricSource(policy.customAggregator, input.source);
|
|
72
|
+
if (!executor)
|
|
73
|
+
throw new Error("Custom metrics require an isolated executor.");
|
|
74
|
+
// Empty populations remain unscorable, even if authored code would return a value.
|
|
75
|
+
if (scores.length) {
|
|
76
|
+
const result = await executor({ source: input.source, module: policy.customAggregator.module, exportName: policy.customAggregator.exportName, scores, timeoutMs: policy.customAggregator.timeoutMs, signal: input.signal });
|
|
77
|
+
if (typeof result !== "number" || !Number.isFinite(result) || result < 0 || result > 1)
|
|
78
|
+
throw new Error("Custom metric must return a finite number between 0 and 1.");
|
|
79
|
+
value = result;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else if (scores.length) {
|
|
83
|
+
const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
|
|
84
|
+
value = scores.reduce((sum, score, index) => sum + score * (weights[index] / totalWeight), 0);
|
|
85
|
+
value = Math.max(0, Math.min(1, value));
|
|
86
|
+
}
|
|
87
|
+
input.signal?.throwIfAborted();
|
|
88
|
+
const content = TasksetMetricResultContentSchema.parse({
|
|
89
|
+
schemaVersion: "openpond.tasksetMetricResult.v1",
|
|
90
|
+
runManifest: { id: manifest.id, contentHash: manifest.contentHash },
|
|
91
|
+
tasksetRelease: manifest.tasksetRelease,
|
|
92
|
+
policy,
|
|
93
|
+
policyHash: contentHash(policy),
|
|
94
|
+
receiptRefs,
|
|
95
|
+
includedCount,
|
|
96
|
+
missingRewardCount,
|
|
97
|
+
excludedCount: receiptRefs.length - includedCount,
|
|
98
|
+
value,
|
|
99
|
+
});
|
|
100
|
+
return TasksetMetricResultSchema.parse({ ...content, contentHash: contentHash(content) });
|
|
101
|
+
}
|
|
102
|
+
function assertMetricSource(aggregator, source) {
|
|
103
|
+
if (source === undefined || new TextEncoder().encode(source).byteLength > 524_288 || sha256(source) !== aggregator.contentHash)
|
|
104
|
+
throw new Error("Metric module bytes do not match the pinned content hash or exceed the source limit.");
|
|
105
|
+
}
|
package/dist/runs.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { FailureClassSchema, ImmutableArtifactRefSchema, ImmutableReleaseRefSchema, MetadataSchema, ModelRefSchema, ReleaseHashSchema, ReleaseIdSchema, ReleaseTimestampSchema, assertContentHash, contentHash, } from "@openpond/harness";
|
|
3
|
+
import { assertTasksetMetricResult, TasksetMetricResultSchema } from "./metric-policy.js";
|
|
3
4
|
export const RuntimeTargetBindingSchema = z.object({
|
|
4
5
|
adapterId: ReleaseIdSchema,
|
|
5
6
|
placement: z.enum(["local", "remote", "colocated", "provider_native"]),
|
|
@@ -58,6 +59,7 @@ export const EvaluationResultContentSchema = z.object({
|
|
|
58
59
|
terminalCount: z.number().int().nonnegative(),
|
|
59
60
|
meanScore: z.number().min(0).max(1).nullable(),
|
|
60
61
|
failureCounts: z.record(FailureClassSchema, z.number().int().nonnegative()),
|
|
62
|
+
authoredMetric: TasksetMetricResultSchema.optional(),
|
|
61
63
|
metadata: MetadataSchema,
|
|
62
64
|
}).strict();
|
|
63
65
|
export const EvaluationResultSchema = EvaluationResultContentSchema.extend({ contentHash: ReleaseHashSchema }).strict();
|
|
@@ -101,6 +103,15 @@ export function aggregateEvaluationReceipts(input) {
|
|
|
101
103
|
if (!verifyAttemptReceipt(receipt))
|
|
102
104
|
throw new Error(`Attempt receipt ${receipt.id} has an invalid content hash.`);
|
|
103
105
|
}
|
|
106
|
+
if (input.authoredMetric) {
|
|
107
|
+
assertTasksetMetricResult(input.authoredMetric);
|
|
108
|
+
const metric = input.authoredMetric;
|
|
109
|
+
if (metric.runManifest.id !== input.manifest.id || metric.runManifest.contentHash !== input.manifest.contentHash
|
|
110
|
+
|| contentHash(metric.tasksetRelease) !== contentHash(input.manifest.tasksetRelease)
|
|
111
|
+
|| contentHash(metric.receiptRefs) !== contentHash(input.receipts.map(({ id, contentHash }) => ({ id, contentHash })))) {
|
|
112
|
+
throw new Error("Authored metric does not describe this evaluation's exact manifest and receipts.");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
104
115
|
const scores = input.receipts.flatMap((receipt) => typeof receipt.metadata.score === "number" && Number.isFinite(receipt.metadata.score)
|
|
105
116
|
? [receipt.metadata.score]
|
|
106
117
|
: []);
|
|
@@ -118,6 +129,7 @@ export function aggregateEvaluationReceipts(input) {
|
|
|
118
129
|
terminalCount: input.receipts.filter((receipt) => receipt.terminal).length,
|
|
119
130
|
meanScore: scores.length ? scores.reduce((total, score) => total + score, 0) / scores.length : null,
|
|
120
131
|
failureCounts,
|
|
132
|
+
...(input.authoredMetric ? { authoredMetric: input.authoredMetric } : {}),
|
|
121
133
|
metadata: input.metadata ?? {},
|
|
122
134
|
});
|
|
123
135
|
return EvaluationResultSchema.parse({ ...content, contentHash: contentHash(content) });
|
package/dist/tasksets.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { CapabilityRequirementSchema, ImmutableAssetRefSchema, MetadataSchema, ReleaseHashSchema, ReleaseIdSchema, ToolDeclarationSchema, assertContentHash, contentHash, } from "@openpond/harness";
|
|
3
|
+
import { TasksetMetricPolicySchema } from "./metric-policy.js";
|
|
3
4
|
export const TaskSplitSchema = z.enum(["train", "validation", "test", "frozen_eval"]);
|
|
4
5
|
export const RequiredOutputContractSchema = z.object({
|
|
5
6
|
path: z.string().trim().min(1).max(2_000).refine(safeRelativePath),
|
|
@@ -85,6 +86,7 @@ export const TasksetReleaseContentSchema = z.object({
|
|
|
85
86
|
tasks: z.array(TaskRecordSchema).min(1).max(1_000_000),
|
|
86
87
|
graders: z.array(GraderSpecSchema).min(1).max(1_000),
|
|
87
88
|
verifierSetRelease: z.object({ id: ReleaseIdSchema, contentHash: ReleaseHashSchema }).strict().optional(),
|
|
89
|
+
metrics: TasksetMetricPolicySchema.optional(),
|
|
88
90
|
metadata: MetadataSchema,
|
|
89
91
|
}).strict();
|
|
90
92
|
export const TasksetReleaseSchema = TasksetReleaseContentSchema.extend({ contentHash: ReleaseHashSchema }).strict();
|
|
@@ -115,6 +117,9 @@ export function validateTasksetRelease(input) {
|
|
|
115
117
|
}
|
|
116
118
|
const clusterSplits = new Map();
|
|
117
119
|
for (const task of taskset.tasks) {
|
|
120
|
+
if (taskset.metrics?.aggregation === "weighted_mean" && !Object.hasOwn(taskset.metrics.taskWeights, task.id)) {
|
|
121
|
+
issues.push({ code: "metric_task_weight_missing", severity: "error", message: `Metric policy has no weight for task ${task.id}.`, path: "metrics.taskWeights" });
|
|
122
|
+
}
|
|
118
123
|
const splits = clusterSplits.get(task.clusterKey) ?? new Set();
|
|
119
124
|
splits.add(task.split);
|
|
120
125
|
clusterSplits.set(task.clusterKey, splits);
|
|
@@ -143,6 +143,20 @@ export declare const harnessRefinerBenchmarkRelease: {
|
|
|
143
143
|
id: string;
|
|
144
144
|
contentHash: string;
|
|
145
145
|
} | undefined;
|
|
146
|
+
metrics?: {
|
|
147
|
+
schemaVersion: "openpond.tasksetMetricPolicy.v1";
|
|
148
|
+
primaryMetric: string;
|
|
149
|
+
aggregation: "mean_score" | "pass_rate" | "weighted_mean" | "custom";
|
|
150
|
+
missingReward: "zero" | "exclude";
|
|
151
|
+
customAggregator: {
|
|
152
|
+
module: string;
|
|
153
|
+
exportName: string;
|
|
154
|
+
contentHash: string;
|
|
155
|
+
timeoutMs: number;
|
|
156
|
+
networkPolicy: "none";
|
|
157
|
+
} | null;
|
|
158
|
+
taskWeights?: Record<string, number> | undefined;
|
|
159
|
+
} | undefined;
|
|
146
160
|
};
|
|
147
161
|
export declare const harnessRefinerBenchmarkAssets: Readonly<Record<string, string>>;
|
|
148
162
|
//# sourceMappingURL=harness-refiner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harness-refiner.d.ts","sourceRoot":"","sources":["../../../../../src/builtin-benchmarks/harness-refiner.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,8BAA8B
|
|
1
|
+
{"version":3,"file":"harness-refiner.d.ts","sourceRoot":"","sources":["../../../../../src/builtin-benchmarks/harness-refiner.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqqD1C,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASzE,CAAC"}
|
|
@@ -253,6 +253,20 @@ export declare const genericToolConformance: {
|
|
|
253
253
|
id: string;
|
|
254
254
|
contentHash: string;
|
|
255
255
|
} | undefined;
|
|
256
|
+
metrics?: {
|
|
257
|
+
schemaVersion: "openpond.tasksetMetricPolicy.v1";
|
|
258
|
+
primaryMetric: string;
|
|
259
|
+
aggregation: "mean_score" | "pass_rate" | "weighted_mean" | "custom";
|
|
260
|
+
missingReward: "zero" | "exclude";
|
|
261
|
+
customAggregator: {
|
|
262
|
+
module: string;
|
|
263
|
+
exportName: string;
|
|
264
|
+
contentHash: string;
|
|
265
|
+
timeoutMs: number;
|
|
266
|
+
networkPolicy: "none";
|
|
267
|
+
} | null;
|
|
268
|
+
taskWeights?: Record<string, number> | undefined;
|
|
269
|
+
} | undefined;
|
|
256
270
|
};
|
|
257
271
|
manifest: {
|
|
258
272
|
schemaVersion: "openpond.runManifest.v1";
|
|
@@ -549,6 +563,20 @@ export declare const marketingPortfolioConformance: {
|
|
|
549
563
|
id: string;
|
|
550
564
|
contentHash: string;
|
|
551
565
|
} | undefined;
|
|
566
|
+
metrics?: {
|
|
567
|
+
schemaVersion: "openpond.tasksetMetricPolicy.v1";
|
|
568
|
+
primaryMetric: string;
|
|
569
|
+
aggregation: "mean_score" | "pass_rate" | "weighted_mean" | "custom";
|
|
570
|
+
missingReward: "zero" | "exclude";
|
|
571
|
+
customAggregator: {
|
|
572
|
+
module: string;
|
|
573
|
+
exportName: string;
|
|
574
|
+
contentHash: string;
|
|
575
|
+
timeoutMs: number;
|
|
576
|
+
networkPolicy: "none";
|
|
577
|
+
} | null;
|
|
578
|
+
taskWeights?: Record<string, number> | undefined;
|
|
579
|
+
} | undefined;
|
|
552
580
|
};
|
|
553
581
|
manifest: {
|
|
554
582
|
schemaVersion: "openpond.runManifest.v1";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conformance.d.ts","sourceRoot":"","sources":["../../../../src/conformance.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,sBAAsB
|
|
1
|
+
{"version":3,"file":"conformance.d.ts","sourceRoot":"","sources":["../../../../src/conformance.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAEjC,CAAC;AAEH,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGxC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DeterministicGraderSpec, TaskRecord } from "./tasksets.js";
|
|
2
|
+
export type DeterministicGrade = {
|
|
3
|
+
score: number | null;
|
|
4
|
+
passed: boolean;
|
|
5
|
+
feedback: string;
|
|
6
|
+
};
|
|
7
|
+
/** Local and portable execution interpret the same declared checks. Missing or
|
|
8
|
+
* unsupported checks are unscorable; an empty check cannot earn a reward. */
|
|
9
|
+
export declare function evaluateDeterministicGrader(input: {
|
|
10
|
+
grader: Pick<DeterministicGraderSpec, "kind" | "config">;
|
|
11
|
+
task: Pick<TaskRecord, "expectedOutput">;
|
|
12
|
+
evidence: {
|
|
13
|
+
output: Record<string, unknown>;
|
|
14
|
+
artifactRefs: string[];
|
|
15
|
+
runtimeEventRefs: string[];
|
|
16
|
+
};
|
|
17
|
+
}): DeterministicGrade;
|
|
18
|
+
/** Encode native artifact/test checks without changing their meaning in transit. */
|
|
19
|
+
export declare function portableDeterministicCheck(grader: {
|
|
20
|
+
kind: DeterministicGraderSpec["kind"] | "file" | "diff" | "test";
|
|
21
|
+
config: Record<string, unknown>;
|
|
22
|
+
}): Pick<DeterministicGraderSpec, "kind" | "config">;
|
|
23
|
+
//# sourceMappingURL=deterministic-graders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deterministic-graders.d.ts","sourceRoot":"","sources":["../../../../src/deterministic-graders.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGzE,MAAM,MAAM,kBAAkB,GAAG;IAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7F;6EAC6E;AAC7E,wBAAgB,2BAA2B,CAAC,KAAK,EAAE;IACjD,MAAM,EAAE,IAAI,CAAC,uBAAuB,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC;IACzD,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;IACzC,QAAQ,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,YAAY,EAAE,MAAM,EAAE,CAAC;QAAC,gBAAgB,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACnG,GAAG,kBAAkB,CAoErB;AAED,oFAAoF;AACpF,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,uBAAuB,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,IAAI,CAAC,uBAAuB,EAAE,MAAM,GAAG,QAAQ,CAAC,CAO1M"}
|
|
@@ -32,7 +32,7 @@ export declare const completeWorkProcessTraceFixture: {
|
|
|
32
32
|
durationMs: number | null;
|
|
33
33
|
cpuTimeMs: number | null;
|
|
34
34
|
memoryPeakBytes: number | null;
|
|
35
|
-
errorClass: "
|
|
35
|
+
errorClass: "unknown" | "policy" | "validation" | "environment" | "cancelled" | "timeout" | "infrastructure" | null;
|
|
36
36
|
};
|
|
37
37
|
}[];
|
|
38
38
|
contentHash: string;
|
|
@@ -209,7 +209,7 @@ export declare const incompleteWorkProcessTraceFixture: {
|
|
|
209
209
|
durationMs: number | null;
|
|
210
210
|
cpuTimeMs: number | null;
|
|
211
211
|
memoryPeakBytes: number | null;
|
|
212
|
-
errorClass: "
|
|
212
|
+
errorClass: "unknown" | "policy" | "validation" | "environment" | "cancelled" | "timeout" | "infrastructure" | null;
|
|
213
213
|
};
|
|
214
214
|
}[];
|
|
215
215
|
contentHash: string;
|
|
@@ -415,7 +415,7 @@ export declare const workEvidenceConformance: {
|
|
|
415
415
|
durationMs: number | null;
|
|
416
416
|
cpuTimeMs: number | null;
|
|
417
417
|
memoryPeakBytes: number | null;
|
|
418
|
-
errorClass: "
|
|
418
|
+
errorClass: "unknown" | "policy" | "validation" | "environment" | "cancelled" | "timeout" | "infrastructure" | null;
|
|
419
419
|
};
|
|
420
420
|
}[];
|
|
421
421
|
contentHash: string;
|
|
@@ -648,7 +648,7 @@ export declare const workEvidenceConformance: {
|
|
|
648
648
|
durationMs: number | null;
|
|
649
649
|
cpuTimeMs: number | null;
|
|
650
650
|
memoryPeakBytes: number | null;
|
|
651
|
-
errorClass: "
|
|
651
|
+
errorClass: "unknown" | "policy" | "validation" | "environment" | "cancelled" | "timeout" | "infrastructure" | null;
|
|
652
652
|
};
|
|
653
653
|
}[];
|
|
654
654
|
contentHash: string;
|