Files
openprose__prose/tools/cli/tests/evals/timeline-diffcache.test.ts
dan 8564d8a7d2 feat(evals): reactor harness evaluation suite (phase 1b) (#102)
* feat(cli): add evaluation runner core

* feat(cli): add eval suite loading and cost mapping

* feat(cli): add public harness eval adapters

* feat(cli): add eval suite registry and runner helper

* fix(cli): harden eval runner safety gates

* feat(cli): harden eval evidence and isolation

* feat(cli): add eval claim eligibility gates

* Harden reactor eval claim eligibility

* Harden eval claim eligibility gates

* feat(eval): add reactor timeline case contract

* feat(eval): add reactor proof verdict library

* feat(eval): add timeline baseline adapters

* feat(eval): add docker isolation substrate

* feat(eval): add phase 1b reactor-independent tier 1

* feat(eval): add phase 1b cost and canary lanes

* feat(eval): add phase 1b statistical pilot

* feat(eval): reconcile openrouter costs and containerize competitors

* feat(evals): run isolated competitor harnesses locally

* feat(evals): add phase 1b report pilot runner

* feat(evals): add phase 1b confidence intervals

* fix(evals): harden provider host matching against URL prefix spoofing

CodeQL flagged "Incomplete URL substring sanitization" in
providerFromUrl: host.endsWith("anthropic.com") also matches an
attacker-controlled host like "evilanthropic.com". Match the exact
host or a proper subdomain (".anthropic.com") instead, applied to all
three provider domains via a hostMatches helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-28 16:17:42 -07:00

128 lines
3.9 KiB
TypeScript

import { mkdtempSync, rmSync } from "node:fs";
import { readFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, test } from "vitest";
import {
REACTOR_ORACLE_SPEC_KIND,
REACTOR_TIMELINE_CASE_KIND,
runReactorTimelineCase,
type JsonObject,
type ReactorTimelineCase,
} from "../../src/evals/index.js";
import { createDiffcacheTimelineAdapter } from "../../src/evals/timeline-adapters/diffcache.js";
import { eventCanonicalKey } from "../../src/evals/timeline-adapters/baseline-utils.js";
const timelineCase: ReactorTimelineCase = {
kind: REACTOR_TIMELINE_CASE_KIND,
version: 1,
id: "diffcache-timeline",
title: "Diffcache timeline",
contract: {
source: {
path: "tests/evals/fixtures/quiet-drift-canary.prose.md",
responsibilityId: "quiet-drift-canary",
revision: "fixture-v1",
sha256: "939de0bacfc591264a67abf985f13ffa08d822ed96c3e47d0f279766553c7fe8",
signerTrustContext: "fixture-null-signer",
},
},
oracle: {
kind: REACTOR_ORACLE_SPEC_KIND,
cid: "a".repeat(64),
policyCid: "b".repeat(64),
forecastModelId: "fixture-forecast-v1",
recheckSchedule: ["2026-05-17T13:00:00.000Z"],
recheckTolerance: 60_000,
preconditionSet: ["c".repeat(64)],
},
events: [
{
id: "first-payload",
at: "2026-05-17T12:00:00.000Z",
label: "relevant-change",
trigger: "input",
type: "evidence.receipt",
payload: { amount: 42, status: "valid" },
payloadCid: "d".repeat(64),
},
{
id: "duplicate-payload",
at: "2026-05-17T12:01:00.000Z",
label: "relevant-change",
trigger: "input",
type: "evidence.receipt",
payload: { amount: 42, status: "valid" },
payloadCid: "d".repeat(64),
},
{
id: "new-payload",
at: "2026-05-17T12:02:00.000Z",
label: "relevant-change",
trigger: "input",
type: "evidence.receipt",
payload: { amount: 43, status: "valid" },
payloadCid: "e".repeat(64),
},
],
};
describe("diffcache timeline adapter", () => {
test("computes the first event, reuses duplicate payloads, and computes new payloads in one persistent cache", async () => {
const cacheRoot = mkdtempSync(join(tmpdir(), "prose-diffcache-timeline-"));
try {
const judgeCalls: string[] = [];
const adapter = createDiffcacheTimelineAdapter({
baselineJudge: ({ event, eventKey }) => {
judgeCalls.push(event.id);
return {
eventId: event.id,
eventKey,
call: judgeCalls.length,
};
},
});
const result = await runReactorTimelineCase(timelineCase, adapter, {
runId: "diffcache-run-1",
scenarioCacheRoot: cacheRoot,
now: () => new Date("2026-05-17T12:00:00.000Z"),
});
expect(result.status).toBe("passed");
expect(result.scenarioCacheDirectory).toBe(join(cacheRoot, timelineCase.id, "diffcache"));
expect(judgeCalls).toEqual(["first-payload", "new-payload"]);
expect(result.steps.map((step) => step.metadata?.decision)).toEqual(["compute", "reuse", "compute"]);
expect(result.steps.map((step) => step.metrics)).toEqual([
{ cacheHit: 0, modelCalls: 1 },
{ cacheHit: 1, modelCalls: 0 },
{ cacheHit: 0, modelCalls: 1 },
]);
expect(result.steps.map((step) => step.events?.[0]?.type)).toEqual([
"baseline.diffcache.compute",
"baseline.diffcache.reuse",
"baseline.diffcache.compute",
]);
const cacheFile = JSON.parse(await readFile(join(result.scenarioCacheDirectory, "diffcache.json"), "utf8")) as {
state: {
lastKey: string;
verdicts: JsonObject;
};
};
const firstKey = eventCanonicalKey(timelineCase.events[0]!);
const duplicateKey = eventCanonicalKey(timelineCase.events[1]!);
const newKey = eventCanonicalKey(timelineCase.events[2]!);
expect(duplicateKey).toBe(firstKey);
expect(newKey).not.toBe(firstKey);
expect(cacheFile.state.lastKey).toBe(newKey);
expect(Object.keys(cacheFile.state.verdicts).sort()).toEqual([firstKey, newKey].sort());
} finally {
rmSync(cacheRoot, { recursive: true, force: true });
}
});
});