@openpond/evals 0.4.1 → 0.5.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/CONTRACT.md +14 -0
- package/README.md +6 -1
- package/dist/artifact-verification.js +172 -0
- package/dist/builtin-benchmarks/harness-refiner.js +469 -23
- package/dist/execution-contracts.js +153 -0
- package/dist/execution-receipts.js +185 -0
- package/dist/graders.js +8 -2
- package/dist/index.js +5 -0
- package/dist/preferences.js +737 -0
- package/dist/rollouts.js +241 -0
- package/dist/tasksets.js +24 -0
- package/dist/types/artifact-verification.d.ts +31 -0
- package/dist/types/artifact-verification.d.ts.map +1 -0
- package/dist/types/builtin-benchmarks/harness-refiner.d.ts +22 -0
- package/dist/types/builtin-benchmarks/harness-refiner.d.ts.map +1 -1
- package/dist/types/conformance.d.ts +44 -0
- package/dist/types/conformance.d.ts.map +1 -1
- package/dist/types/evidence/conformance.d.ts +24 -24
- package/dist/types/evidence/contracts.d.ts +42 -42
- package/dist/types/execution-contracts.d.ts +806 -0
- package/dist/types/execution-contracts.d.ts.map +1 -0
- package/dist/types/execution-receipts.d.ts +55 -0
- package/dist/types/execution-receipts.d.ts.map +1 -0
- package/dist/types/graders.d.ts.map +1 -1
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/preferences.d.ts +535 -0
- package/dist/types/preferences.d.ts.map +1 -0
- package/dist/types/review-conformance.d.ts +20 -15
- package/dist/types/review-conformance.d.ts.map +1 -1
- package/dist/types/rollouts.d.ts +221 -0
- package/dist/types/rollouts.d.ts.map +1 -0
- package/dist/types/tasksets.d.ts +89 -0
- package/dist/types/tasksets.d.ts.map +1 -1
- package/package.json +9 -1
package/CONTRACT.md
CHANGED
|
@@ -17,6 +17,8 @@ runtime processes.
|
|
|
17
17
|
| `HarnessRunTrace` | `HarnessTrace` | Preserve ordered actions, observations, lifecycle events, terminal state, failure class, and trace hash. Learning-signal envelopes remain a training projection of the trace and receipt. |
|
|
18
18
|
| `TaskAttemptResult` | `AttemptReceipt` | Preserve the old record for application persistence while adding a lossless receipt reference. Output becomes `outputHash`; trace and artifacts are separately hash-bound. |
|
|
19
19
|
| `GradeResult` | `GraderEvidence[]` | Preserve component score, pass, reward eligibility, failure class, feedback, and visible/private evidence references. Aggregate UI results remain host projections. |
|
|
20
|
+
| Human or model comparison of attempts | `PreferenceComparisonRelease` + `ComparisonAssignment` + `PreferenceReceipt` | Keep release policy, blinded candidate ordering, exact attempt/artifact references, reviewer identity, and ranking immutable. Human and model reviewers emit the same receipt; provider sessions, identity details, queue state, and artifact bytes remain host-owned. |
|
|
21
|
+
| Comparative reward | `PreferenceAggregationReceipt` + standard `RewardComponentReceipt` | Aggregate only with the release's named quorum algorithm, calibrate automated reviewers against non-frozen human receipts, then project the named pairwise-win fraction into the existing per-attempt reward component boundary. |
|
|
20
22
|
| managed-RL local receipt | `AttemptReceipt` | Submit canonical manifest/task/trace/artifact/grader identities; policy token responses and provider request IDs remain host-private trace data. |
|
|
21
23
|
| resolved training bundle | `HarnessRelease` + host training binding | Agent snapshot, program, lifecycle, tool declarations, files, and grader interface belong to the Harness. Taskset environment/policy/graders and dataset/evidence, recipe, compute, engine, approval, and opaque leases remain explicit host-side bindings. |
|
|
22
24
|
| completed Work or Development turn | `WorkEvidenceReceipt` | Project the authoritative terminal turn, immutable Agent snapshot when available, model/runtime identity, sanitized trace reference, exact output revisions, validation evidence, interventions, timing, usage, and explicit consent provenance. Keep the raw source and trace host-private. |
|
|
@@ -51,6 +53,18 @@ runtime processes.
|
|
|
51
53
|
upper bounds.
|
|
52
54
|
- Immutable content never contains secret values, opaque lease values, mutable
|
|
53
55
|
provider resource IDs, database keys, UI state, or process handles.
|
|
56
|
+
- Preference comparisons are an additive group-evaluation protocol, not a new
|
|
57
|
+
per-attempt grader kind and not a replacement for benchmark comparisons.
|
|
58
|
+
Releases contain two through four candidates, an ordered-tie-group result
|
|
59
|
+
policy, a frozen rubric artifact, presentation policy, aggregation policy,
|
|
60
|
+
reward projection, and calibration thresholds. Assignments bind every visible
|
|
61
|
+
artifact to an existing attempt and manifest under one Taskset, Harness,
|
|
62
|
+
Environment, Verifier, tool, and policy lineage.
|
|
63
|
+
- A model preference receipt is reward-eligible only when a passed calibration
|
|
64
|
+
report binds the exact comparison release and immutable model-reviewer
|
|
65
|
+
release. Frozen-evaluation assignments cannot contribute calibration or
|
|
66
|
+
training evidence. Invalid or unrenderable candidates remain unscorable;
|
|
67
|
+
they are not silently converted into aesthetic losses.
|
|
54
68
|
- The Work evidence schemas first ship as additive `0.2.x` package exports. The
|
|
55
69
|
package version does not replace the `openpond.workEvidenceReceipt.v1`,
|
|
56
70
|
`openpond.workProcessTrace.v1`, `openpond.workFeedbackReceipt.v1`, or
|
package/README.md
CHANGED
|
@@ -8,6 +8,11 @@ eligibility, and no-training/SFT/preference/RL qualification receipts. The packa
|
|
|
8
8
|
does not re-export Harness APIs. Applications import the two packages directly,
|
|
9
9
|
which keeps refinement and evaluation authority visibly separate.
|
|
10
10
|
|
|
11
|
+
The `@openpond/evals/preferences` subpath adds a bounded, artifact-backed
|
|
12
|
+
comparison protocol: two to four attempts can be ranked by a human or model
|
|
13
|
+
reviewer, calibrated against held-out human receipts, then projected into the
|
|
14
|
+
existing reward-component boundary without encoding a specific visual domain.
|
|
15
|
+
|
|
11
16
|
```ts
|
|
12
17
|
import {
|
|
13
18
|
AttemptReceiptSchema,
|
|
@@ -29,7 +34,7 @@ import {
|
|
|
29
34
|
```
|
|
30
35
|
|
|
31
36
|
Subpath exports are available at `/harness`, `/tasksets`, `/benchmarks`, `/graders`, `/runs`,
|
|
32
|
-
`/conformance`, `/evidence`, `/review`, and
|
|
37
|
+
`/conformance`, `/evidence`, `/preferences`, `/review`, and
|
|
33
38
|
`/model-improvement-qualification`. The package is an evaluation protocol library,
|
|
34
39
|
not a hosted client. It does not execute OpenPond Desktop or Sandbox sessions,
|
|
35
40
|
resolve credentials, or persist artifacts.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { ArtifactManifestEntrySchema, RewardComponentReceiptSchema, } from "./execution-contracts.js";
|
|
2
|
+
import { createArtifactManifest } from "./execution-receipts.js";
|
|
3
|
+
export function buildArtifactManifest(input) {
|
|
4
|
+
const byPath = new Map();
|
|
5
|
+
for (const artifact of input.collectedArtifacts) {
|
|
6
|
+
const matches = byPath.get(artifact.path) ?? [];
|
|
7
|
+
matches.push(artifact);
|
|
8
|
+
byPath.set(artifact.path, matches);
|
|
9
|
+
}
|
|
10
|
+
const consumed = new Set();
|
|
11
|
+
const entries = input.requiredOutputs.map((required) => {
|
|
12
|
+
const matches = byPath.get(required.path) ?? [];
|
|
13
|
+
if (matches.length === 0) {
|
|
14
|
+
return ArtifactManifestEntrySchema.parse({
|
|
15
|
+
requiredOutputPath: required.path,
|
|
16
|
+
collectedPath: null,
|
|
17
|
+
declaredMediaType: required.mediaType,
|
|
18
|
+
detectedMediaType: null,
|
|
19
|
+
artifact: null,
|
|
20
|
+
status: "missing",
|
|
21
|
+
parseStatus: "not_requested",
|
|
22
|
+
schemaStatus: "not_requested",
|
|
23
|
+
errorCode: "required_output_missing",
|
|
24
|
+
failureOwner: "policy",
|
|
25
|
+
evidenceRefs: [],
|
|
26
|
+
metadata: { maxBytes: required.maxBytes, schemaRef: required.schemaRef },
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if (matches.length > 1) {
|
|
30
|
+
for (const match of matches)
|
|
31
|
+
consumed.add(match);
|
|
32
|
+
return ArtifactManifestEntrySchema.parse({
|
|
33
|
+
requiredOutputPath: required.path,
|
|
34
|
+
collectedPath: required.path,
|
|
35
|
+
declaredMediaType: required.mediaType,
|
|
36
|
+
detectedMediaType: null,
|
|
37
|
+
artifact: null,
|
|
38
|
+
status: "failed",
|
|
39
|
+
parseStatus: "not_requested",
|
|
40
|
+
schemaStatus: "not_requested",
|
|
41
|
+
errorCode: "artifact_collection_ambiguous",
|
|
42
|
+
failureOwner: "collector",
|
|
43
|
+
evidenceRefs: matches.flatMap((match) => match.evidenceRefs ?? []),
|
|
44
|
+
metadata: { duplicateCount: matches.length },
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const [collected] = matches;
|
|
48
|
+
consumed.add(collected);
|
|
49
|
+
return manifestEntry(required, collected);
|
|
50
|
+
});
|
|
51
|
+
for (const collected of input.collectedArtifacts) {
|
|
52
|
+
if (consumed.has(collected))
|
|
53
|
+
continue;
|
|
54
|
+
entries.push(ArtifactManifestEntrySchema.parse({
|
|
55
|
+
requiredOutputPath: null,
|
|
56
|
+
collectedPath: collected.path,
|
|
57
|
+
declaredMediaType: null,
|
|
58
|
+
detectedMediaType: collected.detectedMediaType,
|
|
59
|
+
artifact: collected.artifact,
|
|
60
|
+
status: collected.status,
|
|
61
|
+
parseStatus: collected.parseStatus ?? "not_requested",
|
|
62
|
+
schemaStatus: collected.schemaStatus ?? "not_requested",
|
|
63
|
+
errorCode: collected.errorCode ?? null,
|
|
64
|
+
failureOwner: collected.failureOwner ?? null,
|
|
65
|
+
evidenceRefs: collected.evidenceRefs ?? [],
|
|
66
|
+
metadata: collected.metadata ?? {},
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
return createArtifactManifest({
|
|
70
|
+
schemaVersion: "openpond.artifactManifest.v1",
|
|
71
|
+
id: input.id,
|
|
72
|
+
attemptRef: input.attemptRef,
|
|
73
|
+
entries,
|
|
74
|
+
createdAt: input.createdAt,
|
|
75
|
+
metadata: input.metadata ?? {},
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
export function verifyRequiredOutputs(input) {
|
|
79
|
+
return input.requiredOutputs.map((required) => {
|
|
80
|
+
const entry = input.manifest.entries.find((candidate) => candidate.requiredOutputPath === required.path);
|
|
81
|
+
if (!entry || entry.status === "missing") {
|
|
82
|
+
return requiredOutputComponent(required, entry ?? null, {
|
|
83
|
+
status: "scored",
|
|
84
|
+
score: 0,
|
|
85
|
+
passed: false,
|
|
86
|
+
rewardEligible: true,
|
|
87
|
+
failureOwner: "policy",
|
|
88
|
+
feedback: `Required output ${required.path} was not collected.`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
if (entry.status === "failed" && entry.failureOwner !== "policy") {
|
|
92
|
+
return requiredOutputComponent(required, entry, {
|
|
93
|
+
status: "unscorable",
|
|
94
|
+
score: null,
|
|
95
|
+
passed: false,
|
|
96
|
+
rewardEligible: false,
|
|
97
|
+
failureOwner: entry.failureOwner ?? "collector",
|
|
98
|
+
feedback: `Required output ${required.path} could not be collected reliably.`,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const failures = structuralFailures(required, entry);
|
|
102
|
+
return requiredOutputComponent(required, entry, {
|
|
103
|
+
status: "scored",
|
|
104
|
+
score: failures.length === 0 ? 1 : 0,
|
|
105
|
+
passed: failures.length === 0,
|
|
106
|
+
rewardEligible: true,
|
|
107
|
+
failureOwner: failures.length === 0 ? null : "policy",
|
|
108
|
+
feedback: failures.length === 0
|
|
109
|
+
? `Required output ${required.path} passed structural verification.`
|
|
110
|
+
: failures.join(" "),
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
function manifestEntry(required, collected) {
|
|
115
|
+
return ArtifactManifestEntrySchema.parse({
|
|
116
|
+
requiredOutputPath: required.path,
|
|
117
|
+
collectedPath: collected.path,
|
|
118
|
+
declaredMediaType: required.mediaType,
|
|
119
|
+
detectedMediaType: collected.detectedMediaType,
|
|
120
|
+
artifact: collected.artifact,
|
|
121
|
+
status: collected.status,
|
|
122
|
+
parseStatus: collected.parseStatus ?? "not_requested",
|
|
123
|
+
schemaStatus: collected.schemaStatus ?? "not_requested",
|
|
124
|
+
errorCode: collected.errorCode ?? null,
|
|
125
|
+
failureOwner: collected.failureOwner ?? null,
|
|
126
|
+
evidenceRefs: collected.evidenceRefs ?? [],
|
|
127
|
+
metadata: {
|
|
128
|
+
...collected.metadata,
|
|
129
|
+
maxBytes: required.maxBytes,
|
|
130
|
+
schemaRef: required.schemaRef,
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
function structuralFailures(required, entry) {
|
|
135
|
+
const failures = [];
|
|
136
|
+
if (!entry.artifact)
|
|
137
|
+
failures.push(`Required output ${required.path} has no immutable artifact reference.`);
|
|
138
|
+
if (entry.detectedMediaType !== required.mediaType) {
|
|
139
|
+
failures.push(`Required output ${required.path} has media type ${entry.detectedMediaType ?? "unknown"}; expected ${required.mediaType}.`);
|
|
140
|
+
}
|
|
141
|
+
if (required.maxBytes !== null && entry.artifact?.sizeBytes !== null && entry.artifact && entry.artifact.sizeBytes > required.maxBytes) {
|
|
142
|
+
failures.push(`Required output ${required.path} exceeds ${required.maxBytes} bytes.`);
|
|
143
|
+
}
|
|
144
|
+
if (entry.parseStatus === "failed")
|
|
145
|
+
failures.push(`Required output ${required.path} could not be parsed.`);
|
|
146
|
+
if (entry.schemaStatus === "failed")
|
|
147
|
+
failures.push(`Required output ${required.path} failed schema validation.`);
|
|
148
|
+
return failures;
|
|
149
|
+
}
|
|
150
|
+
function requiredOutputComponent(required, entry, result) {
|
|
151
|
+
const evidenceRefs = [
|
|
152
|
+
...(entry?.evidenceRefs ?? []),
|
|
153
|
+
...(entry?.artifact ? [entry.artifact] : []),
|
|
154
|
+
];
|
|
155
|
+
return RewardComponentReceiptSchema.parse({
|
|
156
|
+
verifierId: `required-output:${required.path}`,
|
|
157
|
+
verifierVersion: "1",
|
|
158
|
+
status: result.status,
|
|
159
|
+
rawScore: result.score,
|
|
160
|
+
normalizedScore: result.score,
|
|
161
|
+
weight: 1,
|
|
162
|
+
passed: result.passed,
|
|
163
|
+
hardGate: true,
|
|
164
|
+
rewardEligible: result.rewardEligible,
|
|
165
|
+
rewardContribution: result.rewardEligible ? result.score : null,
|
|
166
|
+
failureOwner: result.failureOwner,
|
|
167
|
+
feedback: [result.feedback],
|
|
168
|
+
visibleEvidenceRefs: evidenceRefs,
|
|
169
|
+
privilegedEvidenceRefs: [],
|
|
170
|
+
metadata: { requiredOutputPath: required.path },
|
|
171
|
+
});
|
|
172
|
+
}
|