@agentsfleet/orly 0.12.0 → 0.13.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.
@@ -0,0 +1,134 @@
1
+ import { expect, test } from "bun:test";
2
+ import { resolve } from "node:path";
3
+
4
+ import { loadCases } from "../evals/judgments/comparison/corpus";
5
+ import { corpusJevExamples, evaluateJev, JEV_PREFLIGHT_ERROR, MAX_JEV_REQUESTS, type JevAttempt, type JevExample } from "../evals/judgments/comparison/jev";
6
+ import { CANDIDATE, labelsSchema } from "../evals/judgments/comparison/types";
7
+ import { validateCatalog } from "../evals/judgments/comparison/validate";
8
+ import { ANSWER_KIND, MAX_REQUEST_BYTES, MAX_STATE_BYTES, MODEL, REPLY_KEY } from "./judgments/constants";
9
+ import type { Reply } from "./judgments/wire";
10
+ import { OrlyError } from "./model";
11
+
12
+ const ROOT = resolve(import.meta.dir, "..");
13
+ const CREDENTIAL = "test-credential";
14
+ const PRIVATE_DETAIL = "private-provider-detail";
15
+ const FAILURE = "retention write failed";
16
+ const SCAN = "scan:";
17
+ const REQUEST = "request:";
18
+
19
+ async function examples(): Promise<JevExample[]> {
20
+ const catalog = validateCatalog(await Bun.file(resolve(ROOT, "evals/judgments/comparison/catalog.json")).json());
21
+ const cases = await loadCases(ROOT);
22
+ const labels = labelsSchema.parse(await Bun.file(resolve(ROOT, "evals/judgments/comparison/labels.json")).json());
23
+ const all = corpusJevExamples(catalog, cases, labels);
24
+ return [all.find((entry) => entry.question === "document.claim"), all.find((entry) => entry.question === "verify.assertion"),
25
+ all.find((entry) => entry.question === CANDIDATE.wiring)].filter((entry) => entry !== undefined);
26
+ }
27
+
28
+ function response(entry: JevExample): Reply {
29
+ const question = entry.input.definition.question;
30
+ const answer = question.type === ANSWER_KIND.noul ? { type: question.type, noul: 1 } : {
31
+ type: question.type, choice: entry.expected, confidence: 1,
32
+ probabilities: Object.fromEntries(Object.keys(question.criteria).map((key) => [key, key === entry.expected ? 1 : 0])),
33
+ };
34
+ return { model: MODEL, answers: { [REPLY_KEY]: answer }, usage: { input_tokens: 100, output_tokens: 20 } };
35
+ }
36
+
37
+ test("jev_requests_preserve_actual_native_answers_and_failures", async () => {
38
+ const selected = await examples();
39
+ const order: string[] = [];
40
+ const retained: JevAttempt[] = [];
41
+ let ordinal = 0;
42
+ using server = Bun.serve({ port: 0, async fetch(request) {
43
+ const entry = selected[ordinal++];
44
+ if (!entry) throw new Error("Unexpected request.");
45
+ order.push(REQUEST + entry.id);
46
+ expect(await request.text()).toBe(entry.input.request);
47
+ expect(request.headers.get("authorization")).toBe(`Bearer ${CREDENTIAL}`);
48
+ expect(retained.at(-1)).toMatchObject({ id: entry.id, requests: 1, reply: null });
49
+ return ordinal === 2 ? new Response(PRIVATE_DETAIL, { status: 429 }) : Response.json(response(entry));
50
+ } });
51
+ const actual = await evaluateJev(selected, CREDENTIAL, {
52
+ scan: async (input) => { order.push(SCAN + selected.find((entry) => entry.input.request === input)?.id); },
53
+ fetch: (request) => fetch(new Request(server.url, request)),
54
+ }, async (attempt) => { retained.push(attempt); });
55
+ expect(ordinal).toBe(3);
56
+ expect(order.slice(0, 3)).toEqual(selected.map((entry) => SCAN + entry.id));
57
+ expect(actual.map((entry) => entry.requests)).toEqual([1, 1, 1]);
58
+ expect(actual.map((entry) => entry.reply !== null)).toEqual([true, false, true]);
59
+ expect(actual[1]?.failure).toContain("HTTP 429; no automatic retry");
60
+ expect(JSON.stringify(actual)).not.toContain(PRIVATE_DETAIL);
61
+ expect(JSON.stringify(actual)).not.toContain(CREDENTIAL);
62
+ expect(retained).toHaveLength(6);
63
+ const first = selected[0];
64
+ if (!first) throw new Error("Missing input.");
65
+ expect(actual[0]?.reply).toEqual(response(first));
66
+ });
67
+
68
+ test("jev_missing_credentials_and_each_scanner_failure_prevent_every_upload", async () => {
69
+ const selected = await examples();
70
+ for (const failAt of [0, 1, 2, 3]) {
71
+ let scans = 0;
72
+ let uploads = 0;
73
+ const attempts = await evaluateJev(selected, failAt === 0 ? undefined : CREDENTIAL, {
74
+ scan: async () => { if (++scans === failAt) throw new OrlyError("Secret scanner failed; nothing was uploaded."); },
75
+ fetch: async () => { uploads++; throw new Error(PRIVATE_DETAIL); },
76
+ });
77
+ expect(scans).toBe(failAt);
78
+ expect(uploads).toBe(0);
79
+ expect(attempts).toHaveLength(3);
80
+ expect(attempts.every((entry) => entry.requests === 0 && entry.reply === null && entry.failure !== null)).toBe(true);
81
+ }
82
+ });
83
+
84
+ test("jev_invalid_schedule_and_forged_upload_refuse_before_scanning", async () => {
85
+ const selected = await examples();
86
+ const entry = selected[0];
87
+ if (!entry) throw new Error("Missing input.");
88
+ let touched = 0;
89
+ const dependencies = { scan: async () => { touched++; }, fetch: async () => { touched++; return Response.json({}); } };
90
+ const badInputs = ["{", "x".repeat(MAX_REQUEST_BYTES + 1), JSON.stringify({ ...JSON.parse(entry.input.request), model: "unpinned" }),
91
+ JSON.stringify({ ...JSON.parse(entry.input.request), state: { requirement: "bounded", evidence: [{ role: "spec", text: "x".repeat(MAX_STATE_BYTES + 1) }] } })];
92
+ const invalid = [[], [entry, entry], Array.from({ length: MAX_JEV_REQUESTS + 1 }, (_, id) => ({ ...entry, id: String(id) })),
93
+ ...badInputs.map((request) => [{ ...entry, input: { ...entry.input, request } }])];
94
+ for (const schedule of invalid) await expect(evaluateJev(schedule, CREDENTIAL, dependencies)).rejects.toThrow(JEV_PREFLIGHT_ERROR);
95
+ expect(touched).toBe(0);
96
+ });
97
+
98
+ test("jev_malformed_native_reply_and_transport_failure_remain_missing_and_continue", async () => {
99
+ const selected = await examples();
100
+ let ordinal = 0;
101
+ const attempts = await evaluateJev(selected, CREDENTIAL, { scan: async () => {}, fetch: async () => {
102
+ ordinal++;
103
+ if (ordinal === 1) return Response.json({ model: "wrong-model", answers: {}, usage: {} });
104
+ if (ordinal === 2) throw new Error(CREDENTIAL + PRIVATE_DETAIL);
105
+ return new Response("{");
106
+ } });
107
+ expect(ordinal).toBe(3);
108
+ expect(attempts.every((entry) => entry.reply === null && entry.requests === 1 && entry.failure !== null)).toBe(true);
109
+ expect(attempts[0]?.failure).toContain("pinned model and answer schema");
110
+ expect(attempts[1]?.failure).toContain("Provider transport failed");
111
+ expect(attempts[2]?.failure).toContain("not valid JSON");
112
+ expect(JSON.stringify(attempts)).not.toContain(CREDENTIAL);
113
+ expect(JSON.stringify(attempts)).not.toContain(PRIVATE_DETAIL);
114
+ });
115
+
116
+ test("jev_retention_failure_at_each_ordered_write_prevents_the_next_upload", async () => {
117
+ const selected = await examples();
118
+ for (const failAt of [1, 2, 3, 4, 5, 6]) {
119
+ let writes = 0;
120
+ let uploads = 0;
121
+ const durable: JevAttempt[] = [];
122
+ await expect(evaluateJev(selected, CREDENTIAL, { scan: async () => {}, fetch: async () => {
123
+ const entry = selected[uploads++];
124
+ if (!entry) throw new Error("Unexpected upload.");
125
+ return Response.json(response(entry));
126
+ } }, async (attempt) => {
127
+ if (++writes === failAt) throw new Error(FAILURE);
128
+ durable.push(attempt);
129
+ })).rejects.toThrow(FAILURE);
130
+ expect(uploads).toBe(Math.floor(failAt / 2));
131
+ expect(durable).toHaveLength(failAt - 1);
132
+ if (failAt % 2 === 0) expect(durable.at(-1)).toMatchObject({ requests: 1, reply: null });
133
+ }
134
+ });
@@ -0,0 +1,144 @@
1
+ import { expect, test } from "bun:test";
2
+ import { mkdirSync, mkdtempSync, realpathSync, rmSync, symlinkSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { dirname, join, resolve } from "node:path";
5
+
6
+ import { CONSUMER_SCENARIOS, CONSUMER_SOURCE, CONSUMER_TEST, OWNER_FILES, consumerProbe, mutateConsumer } from "../evals/judgments/comparison/consumer-checks";
7
+ import { consumerJevExamples, consumerReceiptSchema, CONSUMER_JEV_ERROR } from "../evals/judgments/comparison/jev-consumer";
8
+ import { MAX_JEV_REPORT_BYTES } from "../evals/judgments/comparison/jev-report";
9
+ import { CANDIDATE, CLASSIFICATION } from "../evals/judgments/comparison/types";
10
+ import { validateCatalog } from "../evals/judgments/comparison/validate";
11
+ import { MAX_SOURCE_BYTES } from "./judgments/constants";
12
+ import { digest, readBounded } from "./judgments/files";
13
+
14
+ const ROOT = resolve(import.meta.dir, "..");
15
+ const FIXTURE_ROOT = join(ROOT, "evals/judgments/comparison/fixtures");
16
+ const RECEIPT = join(ROOT, "evals/judgments/comparison/receipts/consumer-final.json");
17
+ const CLI = join(ROOT, "evals/judgments/comparison/jev-run.ts");
18
+ const PRIVATE_OWNER = "Owner bytes preserved in this isolated test.";
19
+ const TIMEOUT = 30_000;
20
+
21
+ class ConsumerFixture {
22
+ readonly parent = realpathSync(mkdtempSync(join(tmpdir(), "orly-jev-consumer-")));
23
+ readonly root = join(this.parent, "consumer");
24
+ readonly receipt = join(this.parent, "consumer.json");
25
+
26
+ async setup() {
27
+ const source = await readBounded(join(FIXTURE_ROOT, "consumer-source.txt"), MAX_SOURCE_BYTES);
28
+ const tests = await readBounded(join(FIXTURE_ROOT, "consumer-tests.txt"), MAX_SOURCE_BYTES);
29
+ for (const file of [CONSUMER_SOURCE, ...OWNER_FILES]) {
30
+ const path = join(this.root, file);
31
+ mkdirSync(dirname(path), { recursive: true });
32
+ await Bun.write(path, file === CONSUMER_SOURCE ? source : file === CONSUMER_TEST ? tests : PRIVATE_OWNER);
33
+ }
34
+ const report = consumerReceiptSchema.parse(JSON.parse(await readBounded(RECEIPT, MAX_SOURCE_BYTES)));
35
+ report.metadata.owner_files = Object.fromEntries(OWNER_FILES.map((file) => [file, digest(file === CONSUMER_TEST ? tests : PRIVATE_OWNER)]));
36
+ for (const scenario of CONSUMER_SCENARIOS) for (const suffix of ["submitted", "hidden", "repaired"]) {
37
+ const text = suffix === "repaired" ? source : mutateConsumer(source, scenario);
38
+ const identity = digest(JSON.stringify([{ path: "consumer-source.txt", digest: digest(text) },
39
+ { path: "probe.ts", digest: digest(consumerProbe(this.root, suffix !== "submitted")) }]));
40
+ const entry = report.attempts.find((item) => item.label === `${scenario}:${suffix}`);
41
+ if (!entry) throw new Error("Missing recorded example.");
42
+ entry.receipt.source_before = identity;
43
+ entry.receipt.source_after = identity;
44
+ }
45
+ await Bun.write(this.receipt, JSON.stringify(report));
46
+ return report;
47
+ }
48
+
49
+ async examples() {
50
+ const catalog = validateCatalog(await Bun.file(join(ROOT, "evals/judgments/comparison/catalog.json")).json());
51
+ return consumerJevExamples(this.root, this.receipt, catalog);
52
+ }
53
+
54
+ [Symbol.dispose]() { rmSync(this.parent, { recursive: true, force: true }); }
55
+ }
56
+
57
+ test("jev_inputs_exclude_expected_labels_and_validate_consumer_receipts", async () => {
58
+ using fixture = new ConsumerFixture();
59
+ await fixture.setup();
60
+ const examples = await fixture.examples();
61
+ expect(examples).toHaveLength(12);
62
+ expect(examples.find((entry) => entry.id === "consumer-context-known-gap")).toMatchObject({ question: CANDIDATE.evidence, expected: CLASSIFICATION.defective });
63
+ expect(examples.find((entry) => entry.id === "consumer-context-unknown-dependencies")).toMatchObject({ question: CANDIDATE.evidence, expected: CLASSIFICATION.insufficient });
64
+ for (const entry of examples) {
65
+ const state = JSON.parse(entry.input.request).state;
66
+ expect(Object.keys(state).sort()).toEqual(["evidence", "requirement"]);
67
+ expect(entry.input.request).not.toContain(entry.id);
68
+ }
69
+ });
70
+
71
+ test("jev_consumer_refuses_each_tampered_probe_missing_outcome_and_duplicate", async () => {
72
+ using fixture = new ConsumerFixture();
73
+ const original = await fixture.setup();
74
+ for (const scenario of CONSUMER_SCENARIOS) for (const suffix of ["submitted", "hidden", "repaired"]) {
75
+ const changed = structuredClone(original);
76
+ const entry = changed.attempts.find((item: { label: string }) => item.label === `${scenario}:${suffix}`);
77
+ if (!entry) throw new Error("Missing attempt.");
78
+ entry.receipt.source_after = digest("unrelated source");
79
+ await Bun.write(fixture.receipt, JSON.stringify(changed));
80
+ await expect(fixture.examples()).rejects.toThrow(CONSUMER_JEV_ERROR);
81
+ }
82
+ for (const mutate of [
83
+ (report: typeof original) => { const entry = report.attempts.find((item) => item.label.endsWith(":submitted")); if (!entry) throw new Error("Missing attempt."); entry.label = "unrelated-attempt"; },
84
+ (report: typeof original) => { const entry = report.attempts.find((item) => item.label.endsWith(":hidden")); if (!entry) throw new Error("Missing attempt."); entry.receipt.result.exit_code = 0; },
85
+ (report: typeof original) => { const entry = report.attempts.find((item) => item.label.endsWith(":repaired")); if (!entry) throw new Error("Missing attempt."); entry.receipt.result.failure = "injected failure"; },
86
+ (report: typeof original) => { const entry = report.attempts[1]; if (!entry) throw new Error("Missing attempt."); report.attempts[0] = entry; },
87
+ (report: typeof original) => { const entry = report.attempts.find((item) => item.label.endsWith(":hidden")); if (!entry) throw new Error("Missing attempt."); entry.receipt.stdout = "[]"; },
88
+ (report: typeof original) => { report.metadata.restored_source = digest("not restored"); },
89
+ (report: typeof original) => { const owner = OWNER_FILES[0]; if (!owner) throw new Error("Missing owner."); report.metadata.owner_files[owner] = digest("changed owner"); },
90
+ ]) {
91
+ const changed = structuredClone(original);
92
+ mutate(changed);
93
+ await Bun.write(fixture.receipt, JSON.stringify(changed));
94
+ await expect(fixture.examples()).rejects.toThrow(CONSUMER_JEV_ERROR);
95
+ }
96
+ });
97
+
98
+ test("jev_cli_without_credentials_retains_every_scheduled_attempt_and_preserves_output", async () => {
99
+ using fixture = new ConsumerFixture();
100
+ await fixture.setup();
101
+ const output = join(fixture.parent, "results");
102
+ const invoke = (destination: string) => Bun.spawnSync([process.execPath, CLI, "--live", fixture.root, fixture.receipt, destination], {
103
+ env: { PATH: Bun.env.PATH ?? "", TYPESAFE_API_KEY: "" }, stdout: "pipe", stderr: "pipe", timeout: TIMEOUT,
104
+ });
105
+ const first = invoke(output);
106
+ if (first.exitCode !== 0) throw new Error(first.stderr.toString());
107
+ expect(first.exitCode).toBe(0);
108
+ const file = Bun.file(join(output, "report.json"));
109
+ const bytes = await file.text();
110
+ const report = JSON.parse(bytes);
111
+ expect(report.completed).toBe(true);
112
+ expect(report.requests).toBe(0);
113
+ expect(report.attempts).toHaveLength(188);
114
+ expect(report.results.every((entry: { status: string }) => entry.status === "unavailable")).toBe(true);
115
+ expect(invoke(output).exitCode).not.toBe(0);
116
+ expect(await file.text()).toBe(bytes);
117
+ const inside = invoke(join(fixture.root, "results"));
118
+ expect(inside.exitCode).toBe(2);
119
+ expect(inside.stderr.toString()).toContain("outside the authoring and consumer worktrees");
120
+ expect(await Bun.file(join(fixture.root, "results/report.json")).exists()).toBe(false);
121
+ }, TIMEOUT);
122
+
123
+ test("jev_cli_refuses_symlink_outputs_authoring_outputs_and_oversized_replay", async () => {
124
+ using fixture = new ConsumerFixture();
125
+ await fixture.setup();
126
+ const alias = join(fixture.parent, "consumer-alias");
127
+ symlinkSync(fixture.root, alias);
128
+ const oversized = join(fixture.parent, "oversized.json");
129
+ await Bun.write(oversized, " ".repeat(MAX_JEV_REPORT_BYTES + 1));
130
+ for (const [destination, mode, saved] of [
131
+ [join(alias, "results"), "--live", []],
132
+ [join(ROOT, "forbidden-jev-test-output"), "--live", []],
133
+ [alias, "--live", []],
134
+ [join(fixture.parent, "replay"), "--replay", [oversized]],
135
+ ] as const) {
136
+ const result = Bun.spawnSync([process.execPath, CLI, mode, fixture.root, fixture.receipt, destination, ...saved], {
137
+ env: { PATH: Bun.env.PATH ?? "", TYPESAFE_API_KEY: "" }, stdout: "pipe", stderr: "pipe", timeout: TIMEOUT,
138
+ });
139
+ expect(result.exitCode).toBe(2);
140
+ expect(result.stdout.toString()).toBe("");
141
+ }
142
+ expect(await Bun.file(join(fixture.root, "results/report.json")).exists()).toBe(false);
143
+ expect(await Bun.file(join(ROOT, "forbidden-jev-test-output/report.json")).exists()).toBe(false);
144
+ }, TIMEOUT);
@@ -0,0 +1,167 @@
1
+ import { expect, test } from "bun:test";
2
+ import { resolve } from "node:path";
3
+
4
+ import { loadCases } from "../evals/judgments/comparison/corpus";
5
+ import { corpusJevExamples, gradeJev, jevInput, JEV_PREFLIGHT_ERROR, type JevAttempt, type JevExample } from "../evals/judgments/comparison/jev";
6
+ import { JEV_MODE, jevReport, renderJevReport, replayJev } from "../evals/judgments/comparison/jev-report";
7
+ import { CANDIDATE, CASE_CLASS, CLASSIFICATION, labelsSchema, MEASUREMENT, NATIVE, OBSERVATION } from "../evals/judgments/comparison/types";
8
+ import { validateCatalog } from "../evals/judgments/comparison/validate";
9
+ import { ANSWER_KIND, MODEL, REPLY_KEY } from "./judgments/constants";
10
+ import { digest } from "./judgments/files";
11
+ import type { Reply } from "./judgments/wire";
12
+
13
+ const ROOT = resolve(import.meta.dir, "..");
14
+ const MISSING = "Request failed before a usable reply.";
15
+
16
+ async function inputs() {
17
+ const catalog = validateCatalog(await Bun.file(resolve(ROOT, "evals/judgments/comparison/catalog.json")).json());
18
+ const cases = await loadCases(ROOT);
19
+ const labels = labelsSchema.parse(await Bun.file(resolve(ROOT, "evals/judgments/comparison/labels.json")).json());
20
+ return { catalog, cases, labels, examples: corpusJevExamples(catalog, cases, labels) };
21
+ }
22
+
23
+ function attempt(entry: JevExample, reply: Reply | null = null): JevAttempt {
24
+ return { id: entry.id, question: entry.question, identity: entry.identity, request_digest: digest(entry.input.request),
25
+ requests: reply === null ? 0 : 1, elapsed_ms: 0, reply, failure: reply === null ? MISSING : null };
26
+ }
27
+
28
+ function reply(entry: JevExample, decision: string, strength = 1): Reply {
29
+ const question = entry.input.definition.question;
30
+ const keys = Object.keys(question.criteria);
31
+ return { model: MODEL, answers: { [REPLY_KEY]: question.type === ANSWER_KIND.noul ? { type: question.type, noul: strength } : {
32
+ type: question.type, choice: decision, confidence: strength,
33
+ probabilities: Object.fromEntries(keys.map((key) => [key, key === decision ? strength : (1 - strength) / (keys.length - 1)])),
34
+ } }, usage: { input_tokens: 100, output_tokens: 20 } };
35
+ }
36
+
37
+ test("jev_inputs_exclude_expected_labels_and_freeze_native_questions", async () => {
38
+ const { catalog, cases, labels, examples } = await inputs();
39
+ for (const entry of examples) {
40
+ const request = JSON.parse(entry.input.request);
41
+ expect(request.model).toBe(MODEL);
42
+ expect(Object.keys(request.questions)).toEqual([REPLY_KEY]);
43
+ expect(request.questions[REPLY_KEY]).toEqual(entry.input.definition.question);
44
+ expect(Object.keys(request.state).sort()).toEqual(["evidence", "requirement"]);
45
+ expect(request.state.evidence.every((item: Record<string, unknown>) => JSON.stringify(Object.keys(item).sort()) === JSON.stringify(["role", "text"]))).toBe(true);
46
+ }
47
+ const first = cases[0];
48
+ const original = examples[0];
49
+ if (!first || !original) throw new Error("Missing cases.");
50
+ const changed = corpusJevExamples(catalog, [{ ...first, classification: CASE_CLASS.defective, author: "different-author", id: first.id }], labels)[0];
51
+ expect(changed?.input.request).toBe(original.input.request);
52
+ expect(changed?.identity).not.toBe(original.identity);
53
+ expect(() => jevInput(original.input.definition.question, { ...JSON.parse(original.input.request).state, expected: NATIVE.yes })).toThrow();
54
+ });
55
+
56
+ test("jev_report_grades_actual_answers_without_model_accuracy_substitution", async () => {
57
+ const { cases, labels, examples } = await inputs();
58
+ const attempts = examples.map((entry) => attempt(entry));
59
+ const yesIndex = examples.findIndex((entry) => entry.expected === NATIVE.yes);
60
+ const noIndex = examples.findIndex((entry) => entry.expected === NATIVE.no);
61
+ const candidateIndex = examples.findIndex((entry) => entry.question === CANDIDATE.wiring && entry.expected === CLASSIFICATION.defective);
62
+ const uncertainIndex = examples.findIndex((entry) => entry.question === CANDIDATE.wiring && entry.expected === CLASSIFICATION.supported);
63
+ for (const [index, choice, strength] of [[yesIndex, NATIVE.yes, 1], [noIndex, NATIVE.yes, 1],
64
+ [candidateIndex, CLASSIFICATION.supported, 1], [uncertainIndex, CLASSIFICATION.supported, 0.4]] as const) {
65
+ const entry = examples[index];
66
+ if (!entry) throw new Error("Missing selected case.");
67
+ attempts[index] = attempt(entry, reply(entry, choice, strength));
68
+ }
69
+ const report = jevReport(examples, attempts, cases, labels, [], JEV_MODE.live, true);
70
+ expect(report.results[yesIndex]?.status).toBe("pass");
71
+ expect(report.results[noIndex]?.status).toBe("fail");
72
+ expect(report.results[candidateIndex]?.actual).toBe(CLASSIFICATION.supported);
73
+ expect(report.results[candidateIndex]?.status).toBe("fail");
74
+ expect(report.results[uncertainIndex]).toMatchObject({ actual: CLASSIFICATION.supported, graded: NATIVE.abstain, uncertain: true, status: "fail" });
75
+ expect(report.observations[uncertainIndex]).toMatchObject({ status: OBSERVATION.valid, answer: { decision: CLASSIFICATION.supported, strength: 0.4 } });
76
+ expect(report.observations.every((entry) => entry.measurement === MEASUREMENT.live)).toBe(true);
77
+ expect(report.adoption.every((entry) => !entry.eligible && entry.decision === "retain")).toBe(true);
78
+ expect(report.requests).toBe(4);
79
+ expect(report.usage).toEqual({ input_tokens: 400, output_tokens: 80 });
80
+ expect(report.scores).toHaveLength(22);
81
+ expect(report.results.filter((entry) => entry.status === "unavailable")).toHaveLength(examples.length - 4);
82
+ const rendered = renderJevReport(report);
83
+ for (const glyph of ["✅", "❌", "⚪"]) expect(rendered).toContain(glyph);
84
+ expect(rendered).toContain("(uncertain)");
85
+ expect(rendered).toContain("not measured autonomous agent improvement");
86
+ });
87
+
88
+ test("jev_replay_preserves_original_answers_without_new_request_credit", async () => {
89
+ const { cases, labels, examples } = await inputs();
90
+ const attempts = examples.map((entry) => attempt(entry));
91
+ const first = examples[0];
92
+ if (!first) throw new Error("Missing case.");
93
+ attempts[0] = attempt(first, reply(first, NATIVE.yes));
94
+ const live = jevReport(examples, attempts, cases, labels, [], JEV_MODE.live, true);
95
+ const replay = jevReport(examples, replayJev(examples, live, []), cases, labels, [], JEV_MODE.replay, true);
96
+ expect(replay.results).toEqual(live.results);
97
+ expect(replay.attempts).toEqual(live.attempts);
98
+ expect(replay.requests).toBe(0);
99
+ expect(replay.original_requests).toBe(1);
100
+ expect(replay.observations.every((entry) => entry.measurement === MEASUREMENT.editable)).toBe(true);
101
+ expect(replay.adoption.every((entry) => !entry.eligible)).toBe(true);
102
+ });
103
+
104
+ test("jev_replay_rejects_changed_input_order_identity_reply_and_request_count", async () => {
105
+ const { cases, labels, examples } = await inputs();
106
+ const attempts = examples.map((entry) => attempt(entry));
107
+ const first = examples[0];
108
+ if (!first) throw new Error("Missing case.");
109
+ attempts[0] = attempt(first, reply(first, NATIVE.yes));
110
+ const report = jevReport(examples, attempts, cases, labels, [], JEV_MODE.live, true);
111
+ for (const field of ["id", "question", "identity", "request_digest"] as const) {
112
+ const changed = structuredClone(report);
113
+ const entry = changed.attempts[0];
114
+ if (!entry) throw new Error("Missing attempt.");
115
+ entry[field] = "altered";
116
+ expect(() => replayJev(examples, changed, [])).toThrow(JEV_PREFLIGHT_ERROR);
117
+ }
118
+ expect(() => replayJev([...examples].reverse(), report, [])).toThrow(JEV_PREFLIGHT_ERROR);
119
+ expect(() => replayJev(examples, { ...report, attempts: attempts.slice(1) }, [])).toThrow(JEV_PREFLIGHT_ERROR);
120
+ const firstAttempt = attempts[0];
121
+ if (!firstAttempt) throw new Error("Missing attempt.");
122
+ expect(() => gradeJev(first, { ...firstAttempt, requests: 0 })).toThrow(JEV_PREFLIGHT_ERROR);
123
+ });
124
+
125
+ test("jev_replay_rejects_wrong_native_types_and_invalid_probability_distributions", async () => {
126
+ const { cases, labels, examples } = await inputs();
127
+ const index = examples.findIndex((entry) => entry.question === CANDIDATE.wiring);
128
+ const entry = examples[index];
129
+ if (!entry) throw new Error("Missing Choice example.");
130
+ const attempts = examples.map((value) => attempt(value));
131
+ for (const answer of [
132
+ { type: ANSWER_KIND.noul, noul: 1 },
133
+ { type: ANSWER_KIND.choice, choice: CLASSIFICATION.supported, confidence: 1, probabilities: {} },
134
+ { type: ANSWER_KIND.choice, choice: CLASSIFICATION.supported, confidence: 2, probabilities: {} },
135
+ ]) {
136
+ const report = jevReport(examples, attempts, cases, labels, [], JEV_MODE.live, true);
137
+ const changed = { ...attempt(entry), requests: 1, failure: null,
138
+ reply: { model: MODEL, answers: { [REPLY_KEY]: answer }, usage: { input_tokens: 1, output_tokens: 1 } } };
139
+ expect(() => replayJev(examples, { ...report, attempts: report.attempts.map((value, position) => position === index ? changed : value) }, [])).toThrow();
140
+ }
141
+ });
142
+
143
+ test("jev_noul_uncertainty_preserves_native_probability_and_abstains", async () => {
144
+ const { examples } = await inputs();
145
+ const entry = examples.find((value) => value.input.definition.question.type === ANSWER_KIND.noul);
146
+ if (!entry) throw new Error("Missing Noul example.");
147
+ for (const probability of [0.49, 0.5, 0.51]) {
148
+ const native = reply(entry, NATIVE.yes, probability);
149
+ const result = gradeJev(entry, attempt(entry, native));
150
+ expect(result.actual).toBe(probability < 0.5 ? NATIVE.no : NATIVE.yes);
151
+ expect(result.graded).toBe(NATIVE.abstain);
152
+ expect(result.uncertain).toBe(true);
153
+ expect(native.answers[REPLY_KEY]).toEqual({ type: ANSWER_KIND.noul, noul: probability });
154
+ }
155
+ });
156
+
157
+ // Saved observations must retain the evaluator that produced them.
158
+ test("jev_replay_rejects_missing_changed_or_reordered_source_inventory", async () => {
159
+ const { cases, labels, examples } = await inputs();
160
+ const sources = [{ path: "score.ts", digest: digest("scorer") }, { path: "jev.ts", digest: digest("transport") }];
161
+ const live = jevReport(examples, examples.map((entry) => attempt(entry)), cases, labels, sources, JEV_MODE.live, true);
162
+ expect(replayJev(examples, live, sources)).toEqual(live.attempts);
163
+ for (const changed of [undefined, [], sources.slice(1), [...sources].reverse(), [...sources, sources[0]],
164
+ sources.map((entry) => ({ ...entry, digest: "0".repeat(64) })), sources.map((entry) => ({ ...entry, path: "other.ts" }))]) {
165
+ expect(() => replayJev(examples, { ...live, sources: changed }, sources)).toThrow();
166
+ }
167
+ });
@@ -0,0 +1,119 @@
1
+ import { afterEach, expect, test } from "bun:test";
2
+ import { join } from "node:path";
3
+
4
+ import catalogInput from "../evals/judgments/comparison/catalog.json";
5
+ import { validateLabels } from "../evals/judgments/comparison/labels";
6
+ import { validateCatalog } from "../evals/judgments/comparison/validate";
7
+ import { ADJUDICATION, CANDIDATE, CASE_CLASS, CHECK_ERROR, CLASSIFICATION, LABEL_AUTHORITY, MIN_RESOLVED_PER_GROUP, NATIVE, SPLIT,
8
+ type ComparisonCase, type IndependentLabel, type LabelOracle } from "../evals/judgments/comparison/types";
9
+ import { cleanupTemporaryDirectories, temporaryDirectory } from "./gates_test_support";
10
+ import { CHOICE, QUESTIONS } from "./judgments/constants";
11
+ import { digest } from "./judgments/files";
12
+
13
+ const FIXTURE_AUTHOR = "label-fixture-author";
14
+ const ORACLE_NAME = "independent-test-boundary";
15
+ const SOURCE_PATH = "reference.md";
16
+ const SOURCE_CONTENT = "An independently sourced expected value is compared with the selected result.\n";
17
+ const REVISION_LENGTH = 40;
18
+ const REVISION = "1".repeat(REVISION_LENGTH);
19
+ const catalog = validateCatalog(catalogInput);
20
+
21
+ afterEach(cleanupTemporaryDirectories);
22
+
23
+ function nativeAnswer(question: string, classification: ComparisonCase["classification"]): IndependentLabel["expected_native"] {
24
+ if (question === QUESTIONS[2]) return classification === CASE_CLASS.healthy ? CHOICE.exact : classification === CASE_CLASS.defective ? CHOICE.weak
25
+ : classification === CASE_CLASS.ambiguous ? NATIVE.abstain : CHOICE.insufficient;
26
+ if (QUESTIONS.some((item) => item === question)) return classification === CASE_CLASS.healthy ? NATIVE.yes
27
+ : classification === CASE_CLASS.defective ? NATIVE.no : NATIVE.abstain;
28
+ return classification === CASE_CLASS.healthy ? CLASSIFICATION.supported : classification === CASE_CLASS.defective ? CLASSIFICATION.defective
29
+ : classification === CASE_CLASS.ambiguous ? CLASSIFICATION.ambiguous : CLASSIFICATION.insufficient;
30
+ }
31
+
32
+ async function fixture() {
33
+ const root = temporaryDirectory();
34
+ await Bun.write(join(root, SOURCE_PATH), SOURCE_CONTENT);
35
+ const cases: ComparisonCase[] = [];
36
+ const labels: IndependentLabel[] = [];
37
+ for (const question of [...QUESTIONS, ...Object.values(CANDIDATE)]) for (const classification of Object.values(CASE_CLASS)) {
38
+ for (const split of Object.values(SPLIT)) for (let index = 0; index < MIN_RESOLVED_PER_GROUP; index++) {
39
+ const id = `${question}-${classification}-${split}-${index}`;
40
+ cases.push({ id, question, classification, split, author: FIXTURE_AUTHOR, origin: `${question}-${split}`,
41
+ requirement: `Independent unit boundary ${id}`, evidence: [] });
42
+ labels.push({ case_id: id, classification, expected_native: nativeAnswer(question, classification), rationale: SOURCE_CONTENT.trim(),
43
+ author: FIXTURE_AUTHOR, adjudication: ADJUDICATION.resolved, authority: { kind: LABEL_AUTHORITY.oracle, name: ORACLE_NAME },
44
+ source: { path: SOURCE_PATH, digest: digest(SOURCE_CONTENT), revision: REVISION, selected: SOURCE_CONTENT.trim() } });
45
+ }
46
+ }
47
+ const oracle: LabelOracle = async (entry) => ({ classification: entry.classification, expected_native: nativeAnswer(entry.question, entry.classification),
48
+ source_digest: digest(SOURCE_CONTENT), revision: REVISION });
49
+ return { root, cases, labels, oracle };
50
+ }
51
+
52
+ test("labels_require_independent_evidence", async () => {
53
+ const { root, cases, labels, oracle } = await fixture();
54
+ expect(await validateLabels(root, catalog, cases, labels, oracle)).toEqual(labels);
55
+ const selfReviewed = labels.map((label) => ({ ...label, authority: { kind: LABEL_AUTHORITY.reviewer, name: FIXTURE_AUTHOR } }));
56
+ await expect(validateLabels(root, catalog, cases, selfReviewed, oracle)).rejects.toThrow(CHECK_ERROR.independence);
57
+ });
58
+
59
+ test("all_pending_and_all_disputed_labels_cannot_satisfy_minimums", async () => {
60
+ const { root, cases, labels, oracle } = await fixture();
61
+ for (const adjudication of [ADJUDICATION.pending, ADJUDICATION.disputed]) {
62
+ await expect(validateLabels(root, catalog, cases, labels.map((label) => ({ ...label, adjudication })), oracle)).rejects.toThrow(CHECK_ERROR.minimum);
63
+ }
64
+ });
65
+
66
+ test("a_missing_independent_source_and_invented_selected_text_refuse_labels", async () => {
67
+ const { root, cases, labels, oracle } = await fixture();
68
+ const absent = labels.map((label) => ({ ...label, source: { ...label.source, path: "absent-reference.md" } }));
69
+ await expect(validateLabels(root, catalog, cases, absent, oracle)).rejects.toThrow();
70
+ const fabricated = labels.map((label) => ({ ...label, source: { ...label.source, selected: "Invented label approval." } }));
71
+ await expect(validateLabels(root, catalog, cases, fabricated, oracle)).rejects.toThrow(CHECK_ERROR.independence);
72
+ });
73
+
74
+ test("an_independence_flag_cannot_replace_external_oracle_proof", async () => {
75
+ const { root, cases, labels, oracle } = await fixture();
76
+ await expect(validateLabels(root, catalog, cases, labels.map((label) => ({ ...label, independent: true })), oracle)).rejects.toThrow(CHECK_ERROR.labels);
77
+ const wrongOracle: LabelOracle = async (entry, label) => ({ ...(await oracle(entry, label)), expected_native: CLASSIFICATION.defective });
78
+ await expect(validateLabels(root, catalog, cases, labels, wrongOracle)).rejects.toThrow(CHECK_ERROR.independence);
79
+ });
80
+
81
+ test("stale_oracle_revision_and_changed_label_evidence_refuse_labels", async () => {
82
+ const { root, cases, labels, oracle } = await fixture();
83
+ const stale: LabelOracle = async (entry, label) => ({ ...(await oracle(entry, label)), revision: "2".repeat(REVISION_LENGTH) });
84
+ await expect(validateLabels(root, catalog, cases, labels, stale)).rejects.toThrow(CHECK_ERROR.independence);
85
+ await Bun.write(join(root, SOURCE_PATH), "Changed independent evidence.\n");
86
+ await expect(validateLabels(root, catalog, cases, labels, oracle)).rejects.toThrow(CHECK_ERROR.independence);
87
+ });
88
+
89
+ test("missing_duplicate_and_mismatched_labels_refuse_scoring", async () => {
90
+ const { root, cases, labels, oracle } = await fixture();
91
+ await expect(validateLabels(root, catalog, cases, labels.slice(1), oracle)).rejects.toThrow(CHECK_ERROR.labelIdentity);
92
+ await expect(validateLabels(root, catalog, cases, [...labels, labels[0]], oracle)).rejects.toThrow(CHECK_ERROR.labelIdentity);
93
+ await expect(validateLabels(root, catalog, cases, labels.map((label) => ({ ...label, author: "invented-author" })), oracle)).rejects.toThrow(CHECK_ERROR.labelIdentity);
94
+ });
95
+
96
+ test("labels_cannot_change_answer_types_or_relabel_case_health", async () => {
97
+ const { root, cases, labels, oracle } = await fixture();
98
+ await expect(validateLabels(root, catalog, cases, labels.map((label) => ({ ...label, expected_native: CHOICE.exact })), oracle)).rejects.toThrow(CHECK_ERROR.native);
99
+ await expect(validateLabels(root, catalog, cases, labels.map((label) => ({ ...label, classification: CASE_CLASS.defective })), oracle)).rejects.toThrow(CHECK_ERROR.labelIdentity);
100
+ });
101
+
102
+ test("frozen_reference_bytes_validate_without_git_history_and_reject_modified_sources", async () => {
103
+ const { resolve } = await import("node:path");
104
+ const { loadCases } = await import("../evals/judgments/comparison/corpus");
105
+ const { verifyCaseLabel } = await import("../evals/judgments/comparison/hidden/label-oracle");
106
+ const { labelsSchema } = await import("../evals/judgments/comparison/types");
107
+ const { default: input } = await import("../evals/judgments/comparison/labels.json");
108
+ const sourceRoot = resolve(import.meta.dir, "..");
109
+ const label = labelsSchema.parse(input)[0];
110
+ if (!label) throw new Error("Missing independent label.");
111
+ const entry = (await loadCases(sourceRoot)).find((entry) => entry.id === label.case_id);
112
+ if (!entry) throw new Error("Missing sourced case.");
113
+ const root = temporaryDirectory();
114
+ const source = join(root, label.source.path);
115
+ await Bun.write(source, Bun.file(join(sourceRoot, label.source.path)));
116
+ expect((await verifyCaseLabel(root, entry, label)).source_digest).toBe(label.source.digest);
117
+ await Bun.write(source, "Changed reference bytes.");
118
+ await expect(verifyCaseLabel(root, entry, label)).rejects.toThrow(CHECK_ERROR.independence);
119
+ });