@openpond/evals 0.11.8 → 0.11.9

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/RELEASING.md CHANGED
@@ -20,3 +20,19 @@ Version `0.4.0` removes the retired Harness root barrel and
20
20
  `./harness-improvements` / `./harness-workspaces` compatibility subpaths.
21
21
  Consumers must import those public contracts from `@openpond/harness`; this is
22
22
  an intentional breaking package-boundary correction.
23
+
24
+ ## Version-only CI
25
+
26
+ Release preparation is shared across Evals, Harness, SDK, and Agent SDK. A stable
27
+ version increase in exactly one package manifest selects package checks on the
28
+ PR. All other manifest fields must be semantically identical. On merge, the
29
+ previous master SHA must have a successful latest `ci.yml` push run and `Checks`
30
+ job; missing, failed, pending, or ambiguous proof selects full CI. Publication
31
+ still waits for the new SHA's `Checks`.
32
+
33
+ Lockfile changes conservatively use ordinary CI, as do dependency, source, export,
34
+ workflow, and combined package changes. Pure workspace version bumps normally
35
+ leave the lockfile unchanged. The helper reports the selected path before commit.
36
+ A dry run requires clean, current master and prints the commands without changing
37
+ Git or package versions. Existing trusted publishing, registry verification,
38
+ package tags, and retry behavior are unchanged.
@@ -0,0 +1,84 @@
1
+ import { z } from "zod";
2
+ import { assertContentHash, contentHash, ImmutableReleaseRefSchema } from "@openpond/harness";
3
+ const Id = z.string().trim().min(1).max(240);
4
+ const Hash = z.string().regex(/^[a-f0-9]{64}$/);
5
+ export const AcceptanceCheckSchema = z.object({
6
+ id: Id, name: z.string().trim().min(1).max(200), required: z.boolean(),
7
+ dataset: ImmutableReleaseRefSchema, evaluator: ImmutableReleaseRefSchema,
8
+ executionHash: Hash, populationHash: Hash, metric: Id, direction: z.enum(["higher", "lower"]),
9
+ minimumCoverage: z.number().positive().max(1), threshold: z.number().finite(),
10
+ maximumRegression: z.number().finite().nonnegative(), maximumSpendUsd: z.number().finite().positive(),
11
+ }).strict();
12
+ export const AcceptancePlanContentSchema = z.object({
13
+ schemaVersion: z.literal("openpond.acceptancePlan.v1"), id: Id, revision: z.number().int().positive(),
14
+ checks: z.array(AcceptanceCheckSchema).min(1).max(100),
15
+ maximumSpendUsd: z.number().finite().positive(),
16
+ }).strict().superRefine((value, ctx) => {
17
+ if (new Set(value.checks.map(c => c.id)).size !== value.checks.length)
18
+ ctx.addIssue({ code: "custom", message: "Acceptance check IDs must be unique." });
19
+ if (!value.checks.some(c => c.required))
20
+ ctx.addIssue({ code: "custom", message: "An acceptance plan needs at least one required check." });
21
+ if (value.checks.reduce((total, c) => total + c.maximumSpendUsd, 0) > value.maximumSpendUsd + 1e-9)
22
+ ctx.addIssue({ code: "custom", message: "Check budgets exceed the total plan budget." });
23
+ });
24
+ export const AcceptancePlanSchema = AcceptancePlanContentSchema.safeExtend({ contentHash: Hash });
25
+ export function createAcceptancePlan(input) {
26
+ const value = AcceptancePlanContentSchema.parse(input);
27
+ return { ...value, contentHash: contentHash(value) };
28
+ }
29
+ export const AcceptanceMeasurementSchema = z.object({
30
+ runId: Id, artifact: ImmutableReleaseRefSchema, checkHash: Hash,
31
+ populationHash: Hash, scoredPopulationHash: Hash, executionHash: Hash, evaluator: ImmutableReleaseRefSchema,
32
+ metric: Id, expectedCount: z.number().int().positive(), scoredCount: z.number().int().nonnegative(),
33
+ score: z.number().finite().nullable(), status: z.enum(["pending", "running", "completed", "failed", "cancelled"]),
34
+ evidenceHash: Hash,
35
+ }).strict().superRefine((value, ctx) => {
36
+ if (value.scoredCount > value.expectedCount)
37
+ ctx.addIssue({ code: "custom", message: "Scored count exceeds declared population." });
38
+ if ((value.scoredCount === 0) !== (value.score === null))
39
+ ctx.addIssue({ code: "custom", message: "Scores require a nonempty scored population." });
40
+ });
41
+ /** Evaluates verified retained measurements, never browser-supplied scores.
42
+ * Hosts must load and verify the referenced receipts and authorize their scope. */
43
+ export function evaluateAcceptancePlan(input) {
44
+ const plan = AcceptancePlanSchema.parse(input.plan);
45
+ assertContentHash(plan, "Acceptance plan");
46
+ const baseline = ImmutableReleaseRefSchema.parse(input.baseline);
47
+ const candidate = ImmutableReleaseRefSchema.parse(input.candidate);
48
+ if (new Set(input.measurements.map(m => m.checkId)).size !== input.measurements.length || input.measurements.some(m => !plan.checks.some(c => c.id === m.checkId)))
49
+ throw new Error("Acceptance evidence has duplicate or unknown checks.");
50
+ const checks = plan.checks.map(check => {
51
+ const pair = input.measurements.find(m => m.checkId === check.id);
52
+ const reasons = [];
53
+ const expectedHash = contentHash(check);
54
+ const values = [pair?.baseline ?? null, pair?.candidate ?? null].map((raw, index) => {
55
+ if (!raw) {
56
+ reasons.push(index ? "candidate_missing" : "baseline_missing");
57
+ return null;
58
+ }
59
+ const value = AcceptanceMeasurementSchema.parse(raw);
60
+ if (contentHash(value.artifact) !== contentHash(index ? candidate : baseline))
61
+ reasons.push("artifact_mismatch");
62
+ if (value.checkHash !== expectedHash || value.populationHash !== check.populationHash || value.executionHash !== check.executionHash || contentHash(value.evaluator) !== contentHash(check.evaluator) || value.metric !== check.metric)
63
+ reasons.push("configuration_mismatch");
64
+ if (value.status !== "completed")
65
+ reasons.push(`execution_${value.status}`);
66
+ if (value.score === null || value.scoredCount / value.expectedCount < check.minimumCoverage)
67
+ reasons.push("coverage_incomplete");
68
+ return value;
69
+ });
70
+ if (values[0] && values[1] && (values[0].expectedCount !== values[1].expectedCount || values[0].scoredCount !== values[1].scoredCount || values[0].scoredPopulationHash !== values[1].scoredPopulationHash))
71
+ reasons.push("population_count_mismatch");
72
+ if (reasons.length)
73
+ return { id: check.id, required: check.required, state: "blocked", reasons: [...new Set(reasons)], delta: null };
74
+ const before = values[0].score;
75
+ const after = values[1].score;
76
+ const delta = (after - before) * (check.direction === "higher" ? 1 : -1);
77
+ if (check.direction === "higher" ? after < check.threshold : after > check.threshold)
78
+ reasons.push("threshold_failed");
79
+ if (delta < -check.maximumRegression)
80
+ reasons.push("regression_failed");
81
+ return { id: check.id, required: check.required, state: reasons.length ? "failed" : "passed", reasons, delta };
82
+ });
83
+ return { passed: checks.filter(c => c.required).every(c => c.state === "passed"), checks };
84
+ }
@@ -32,3 +32,4 @@ export * from "./schedule-worker.js";
32
32
  export * from "./nightly-schedule.js";
33
33
  export * from "./policy-inspection.js";
34
34
  export * from "./task-queue-inspection.js";
35
+ export * from "./acceptance-plan.js";
@@ -0,0 +1,140 @@
1
+ import { z } from "zod";
2
+ import { ImmutableReleaseRefSchema } from "@openpond/harness";
3
+ export declare const AcceptanceCheckSchema: z.ZodObject<{
4
+ id: z.ZodString;
5
+ name: z.ZodString;
6
+ required: z.ZodBoolean;
7
+ dataset: z.ZodObject<{
8
+ id: z.ZodString;
9
+ contentHash: z.ZodString;
10
+ }, z.core.$strict>;
11
+ evaluator: z.ZodObject<{
12
+ id: z.ZodString;
13
+ contentHash: z.ZodString;
14
+ }, z.core.$strict>;
15
+ executionHash: z.ZodString;
16
+ populationHash: z.ZodString;
17
+ metric: z.ZodString;
18
+ direction: z.ZodEnum<{
19
+ higher: "higher";
20
+ lower: "lower";
21
+ }>;
22
+ minimumCoverage: z.ZodNumber;
23
+ threshold: z.ZodNumber;
24
+ maximumRegression: z.ZodNumber;
25
+ maximumSpendUsd: z.ZodNumber;
26
+ }, z.core.$strict>;
27
+ export declare const AcceptancePlanContentSchema: z.ZodObject<{
28
+ schemaVersion: z.ZodLiteral<"openpond.acceptancePlan.v1">;
29
+ id: z.ZodString;
30
+ revision: z.ZodNumber;
31
+ checks: z.ZodArray<z.ZodObject<{
32
+ id: z.ZodString;
33
+ name: z.ZodString;
34
+ required: z.ZodBoolean;
35
+ dataset: z.ZodObject<{
36
+ id: z.ZodString;
37
+ contentHash: z.ZodString;
38
+ }, z.core.$strict>;
39
+ evaluator: z.ZodObject<{
40
+ id: z.ZodString;
41
+ contentHash: z.ZodString;
42
+ }, z.core.$strict>;
43
+ executionHash: z.ZodString;
44
+ populationHash: z.ZodString;
45
+ metric: z.ZodString;
46
+ direction: z.ZodEnum<{
47
+ higher: "higher";
48
+ lower: "lower";
49
+ }>;
50
+ minimumCoverage: z.ZodNumber;
51
+ threshold: z.ZodNumber;
52
+ maximumRegression: z.ZodNumber;
53
+ maximumSpendUsd: z.ZodNumber;
54
+ }, z.core.$strict>>;
55
+ maximumSpendUsd: z.ZodNumber;
56
+ }, z.core.$strict>;
57
+ export declare const AcceptancePlanSchema: z.ZodObject<{
58
+ schemaVersion: z.ZodLiteral<"openpond.acceptancePlan.v1">;
59
+ id: z.ZodString;
60
+ revision: z.ZodNumber;
61
+ checks: z.ZodArray<z.ZodObject<{
62
+ id: z.ZodString;
63
+ name: z.ZodString;
64
+ required: z.ZodBoolean;
65
+ dataset: z.ZodObject<{
66
+ id: z.ZodString;
67
+ contentHash: z.ZodString;
68
+ }, z.core.$strict>;
69
+ evaluator: z.ZodObject<{
70
+ id: z.ZodString;
71
+ contentHash: z.ZodString;
72
+ }, z.core.$strict>;
73
+ executionHash: z.ZodString;
74
+ populationHash: z.ZodString;
75
+ metric: z.ZodString;
76
+ direction: z.ZodEnum<{
77
+ higher: "higher";
78
+ lower: "lower";
79
+ }>;
80
+ minimumCoverage: z.ZodNumber;
81
+ threshold: z.ZodNumber;
82
+ maximumRegression: z.ZodNumber;
83
+ maximumSpendUsd: z.ZodNumber;
84
+ }, z.core.$strict>>;
85
+ maximumSpendUsd: z.ZodNumber;
86
+ contentHash: z.ZodString;
87
+ }, z.core.$strict>;
88
+ export type AcceptancePlan = z.infer<typeof AcceptancePlanSchema>;
89
+ export declare function createAcceptancePlan(input: z.input<typeof AcceptancePlanContentSchema>): AcceptancePlan;
90
+ export declare const AcceptanceMeasurementSchema: z.ZodObject<{
91
+ runId: z.ZodString;
92
+ artifact: z.ZodObject<{
93
+ id: z.ZodString;
94
+ contentHash: z.ZodString;
95
+ }, z.core.$strict>;
96
+ checkHash: z.ZodString;
97
+ populationHash: z.ZodString;
98
+ scoredPopulationHash: z.ZodString;
99
+ executionHash: z.ZodString;
100
+ evaluator: z.ZodObject<{
101
+ id: z.ZodString;
102
+ contentHash: z.ZodString;
103
+ }, z.core.$strict>;
104
+ metric: z.ZodString;
105
+ expectedCount: z.ZodNumber;
106
+ scoredCount: z.ZodNumber;
107
+ score: z.ZodNullable<z.ZodNumber>;
108
+ status: z.ZodEnum<{
109
+ pending: "pending";
110
+ failed: "failed";
111
+ completed: "completed";
112
+ cancelled: "cancelled";
113
+ running: "running";
114
+ }>;
115
+ evidenceHash: z.ZodString;
116
+ }, z.core.$strict>;
117
+ export type AcceptanceMeasurement = z.infer<typeof AcceptanceMeasurementSchema>;
118
+ export type AcceptanceVerdict = {
119
+ passed: boolean;
120
+ checks: Array<{
121
+ id: string;
122
+ required: boolean;
123
+ state: "passed" | "failed" | "blocked";
124
+ reasons: string[];
125
+ delta: number | null;
126
+ }>;
127
+ };
128
+ /** Evaluates verified retained measurements, never browser-supplied scores.
129
+ * Hosts must load and verify the referenced receipts and authorize their scope. */
130
+ export declare function evaluateAcceptancePlan(input: {
131
+ plan: AcceptancePlan;
132
+ baseline: z.infer<typeof ImmutableReleaseRefSchema>;
133
+ candidate: z.infer<typeof ImmutableReleaseRefSchema>;
134
+ measurements: Array<{
135
+ checkId: string;
136
+ baseline: AcceptanceMeasurement | null;
137
+ candidate: AcceptanceMeasurement | null;
138
+ }>;
139
+ }): AcceptanceVerdict;
140
+ //# sourceMappingURL=acceptance-plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acceptance-plan.d.ts","sourceRoot":"","sources":["../../../../../src/learning/acceptance-plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAkC,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAI9F,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;kBAMvB,CAAC;AACZ,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAQtC,CAAC;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAgE,CAAC;AAClG,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,GAAG,cAAc,CAGvG;AACD,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;kBAStC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAChF,MAAM,MAAM,iBAAiB,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC;AAEvL;mFACmF;AACnF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE;IAC5C,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;IAAC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;IAChI,YAAY,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,qBAAqB,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,qBAAqB,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CAC3H,GAAG,iBAAiB,CA6BpB"}
@@ -32,4 +32,5 @@ export * from "./schedule-worker.js";
32
32
  export * from "./nightly-schedule.js";
33
33
  export * from "./policy-inspection.js";
34
34
  export * from "./task-queue-inspection.js";
35
+ export * from "./acceptance-plan.js";
35
36
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/learning/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/learning/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAE3C,cAAc,sBAAsB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openpond/evals",
3
- "version": "0.11.8",
3
+ "version": "0.11.9",
4
4
  "description": "Portable Tasksets, graders, evaluation runs, receipts, conformance fixtures, and Work evidence for OpenPond Harnesses",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -147,7 +147,7 @@
147
147
  "test": "vitest run --root ../.. --config vitest.config.ts --project evals",
148
148
  "check:api": "tsx scripts/check-public-package.ts",
149
149
  "check:consumer": "tsx scripts/verify-packed-consumer.ts",
150
- "check": "pnpm run typecheck && pnpm run test && pnpm run build && pnpm run check:api && pnpm run check:consumer && npm pack --dry-run",
150
+ "check": "pnpm run build && pnpm run typecheck && pnpm run test && pnpm run check:api && pnpm run check:consumer && npm pack --dry-run",
151
151
  "publish:check": "pnpm run build && pnpm run check:api && pnpm run check:consumer && npm pack --dry-run"
152
152
  },
153
153
  "dependencies": {