Skip to content

Commit 5ee3e53

Browse files
committed
fix(evals): fail closed when the route baseline is missing
1 parent 169c487 commit 5ee3e53

2 files changed

Lines changed: 51 additions & 3 deletions

File tree

‎scripts/eval-prompts-dispatch.test.ts‎

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
1+
import { access, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
22
import { tmpdir } from "node:os";
33
import { join } from "node:path";
44
import { describe, expect, test } from "bun:test";
@@ -218,4 +218,32 @@ describe("drop baseline", () => {
218218
await rm(dir, { recursive: true, force: true });
219219
}
220220
});
221+
222+
test("a missing baseline fails closed and is not created", async () => {
223+
const dir = await mkdtemp(join(tmpdir(), "dispatch-routing-"));
224+
const baselinePath = join(dir, "baseline.json");
225+
const lastPath = join(dir, "last.json");
226+
const run = async () => "reviewer\nI refuse.";
227+
try {
228+
const first = await evaluateRouting({
229+
cases: [coderCase],
230+
run,
231+
lastPath,
232+
baselinePath,
233+
});
234+
expect(first).not.toBe(0);
235+
await expect(access(baselinePath)).rejects.toThrow();
236+
237+
const second = await evaluateRouting({
238+
cases: [coderCase],
239+
run,
240+
lastPath,
241+
baselinePath,
242+
});
243+
expect(second).not.toBe(0);
244+
await expect(access(baselinePath)).rejects.toThrow();
245+
} finally {
246+
await rm(dir, { recursive: true, force: true });
247+
}
248+
});
221249
});

‎scripts/eval-prompts-dispatch.ts‎

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env bun
2-
import { copyFile, readFile } from "node:fs/promises";
2+
import { access, copyFile, readFile } from "node:fs/promises";
33
import { dirname, join } from "node:path";
44
import { fileURLToPath } from "node:url";
55
import { systemPrompt } from "@corbits/code-agent-dispatch";
@@ -195,13 +195,23 @@ type DispatchEvaluate = (
195195
options: EvaluateOptions<string, string, RoutingExpect>,
196196
) => Promise<Report<string, string, RoutingExpect>>;
197197

198+
async function baselinePresent(path: string): Promise<boolean> {
199+
try {
200+
await access(path);
201+
return true;
202+
} catch {
203+
return false;
204+
}
205+
}
206+
198207
export async function evaluateRouting(args: {
199208
cases: readonly Case<string, RoutingExpect>[];
200209
run: (input: string, signal: AbortSignal) => Promise<string>;
201210
lastPath: string;
202211
baselinePath: string;
203212
evaluateFn?: DispatchEvaluate;
204213
}): Promise<number> {
214+
const hadBaseline = await baselinePresent(args.baselinePath);
205215
const evaluateFn: DispatchEvaluate =
206216
args.evaluateFn ?? ((name, options) => evaluate(name, options));
207217
try {
@@ -227,8 +237,18 @@ export async function evaluateRouting(args: {
227237
ollamaUrl: OLLAMA_URL,
228238
},
229239
});
230-
await copyFile(args.lastPath, args.baselinePath);
231240
console.log(report.markdown());
241+
const routeMisses = report.checks["routes"]?.missed;
242+
if (!hadBaseline) {
243+
console.error(
244+
`eval "${DISPATCH_EVAL}" failed: no baseline at ${args.baselinePath}`,
245+
);
246+
return 1;
247+
}
248+
if (routeMisses !== 0) {
249+
return 0;
250+
}
251+
await copyFile(args.lastPath, args.baselinePath);
232252
return 0;
233253
} catch (err: unknown) {
234254
if (err instanceof EvalFailure) {

0 commit comments

Comments
 (0)