Files
PaperClipAI/tests/runner-e2e/eval-gateway.test.ts
T
DottaandPaperclip b6e690044a feat(evals): allow reviewed bounded provisional accounting (#17365)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Product E2E campaigns include model, setup, storage and
observability costs.
> - Some billing windows close after the tests and reports finish.
> - Requiring settled receipts for retained storage can block a good
campaign for weeks.
> - A reservation alone does not prove that a pending charge has an
upper bound.
> - This change permits provisional completion only with reviewed
evidence for the exact cost configuration.
> - Reports preserve unknown amounts and holds until later
reconciliation.

## Linked Issues or Issue Description

Refs: #17360, #17354

**What existing behavior does this improve?**

The Product E2E scheduled accounting gate and its retained cost reports.

**Current behavior**

Every pending receipt fails finalization. A completed test can wait
through the retained-storage billing window. The journal has dollar
reservations but no explicit qualification of their bounds.

**Proposed behavior**

Permit provisional completion when all pending charges have reviewed
full-lifecycle bounds, no requests remain in flight, no receipts
conflict, and known costs plus held amounts fit the campaign limit. Keep
all existing holds and receipt-finality rules. Missing evidence still
fails.

**Reason and benefit**

An operator can distinguish delayed but bounded billing from unbounded
or missing costs. The campaign can finish without claiming that its
invoice is settled.

**Breaking changes**

The journal accepts optional bound metadata and an invalidation record.
New reports add an optional bounded-pending count. Current readers
retain old journals and reports without granting them bounds. Older code
must not read new bound-bearing journals. The existing daily/weekly
enable gates and budget amounts stay unchanged.

**Additional context**

This implements the operator-approved provisional-cost policy for the
existing eval harness. It does not change product budgets or the
agent-eval roadmap. A targeted GitHub search found no duplicate open PR.

## What Changed

- Accounting owns a narrow evidence contract: a reviewed audit hash,
exact configuration hash and full-lifecycle scope.
- Gateway reservations retain that evidence before dispatch. Changed
limits or rates fail before dispatch. Unexpected routing, model identity
or excessive usage invalidates a bound durably.
- Operating allowances can carry separately reviewed bounds for each
cost component, including its full storage lifetime. No existing
allowance becomes qualified by default.
- Reports and Braintrust experiment metadata distinguish provisional
accounting, complete receipts, blocked accounting and unavailable
evidence. Public output omits private audit hashes.
- Scheduled finalization allows qualified provisional costs and
explicitly rejects spending overruns, including overruns with complete
receipts.
- Add regressions for legacy data, restarts, late reconciliation,
conflicts, malformed evidence, routing uncertainty and exceeded limits.
Document the evidence and migration boundaries.

## Verification

- Full offline eval-support suite: 4,062 Vitest tests passed, two
existing tests skipped; 137 Node tests passed.
- `pnpm test:e2e:runner:typecheck`: passed.
- `git diff --check`: passed.
- Read the retained hosted qualification journal with the new policy.
All six legacy pending charges remain unqualified. Known cost
`$0.421245200`, held `$19.327680000`, and committed `$19.748925200`
remain unchanged. The journal's SHA-256 is unchanged. The original
failed workflow remains failed.
- No paid models, network provider calls, receipt imports or reservation
releases were used for this verification.
- Rebased onto master `4d90634f74`; 142 targeted tests and typecheck
passed.
- Review reproduced a lost OpenAI input-total limit check when cache
details were missing (1 failed, 47 passed). Fix
`5fef9ba7c149951a51eae468614a4b89f0b3d6db` preserves unpriced provider
usage bounds. Then 178 focused tests, full offline support and typecheck
passed.
- Current-head hosted CI passed:
https://github.com/paperclipai/paperclip/actions/runs/40020746585
(attempt 2). Typecheck, build, all general/Runner/serialized tests and
browser gates are green.
- CI attempt 1 hit a PostgreSQL deadlock in unchanged chat-test cleanup;
its skipped flag restoration caused a second assertion failure. One
failed-jobs-only retry passed. Original failure evidence is preserved in
attempt 1. No paid eval campaign was rerun.
- Greptile reviewed exact head
`5fef9ba7c149951a51eae468614a4b89f0b3d6db` at 5/5; its one finding is
fixed and resolved. The optional Paperclip review is paused and supplied
no assessment.

## Risks

- Evidence hashes bind an audit to a configuration; they do not prove
the audit is true. Operators must review real provider limits, all price
tiers, full resource lifetimes and enforceable infrastructure limits
before configuring bounds.
- Provisional completion is not invoice settlement. Later billing can
reveal overruns, which must be reconciled and inspected. The ledger
cannot stop external billing.
- Existing pilot journals, configured allowances and price cards have no
new bound approval. This PR alone does not qualify or enable recurring
paid work.
- The gateway cannot qualify a canceled Braintrust request without route
confirmation. It preserves that unknown hold.
- No new dependency, secret, repository variable, workflow, schedule or
cloud resource changes.

## Model Used

OpenAI Codex, GPT-6 family. The exact deployment ID and context-window
size are not exposed in this session. Used reasoning, repository tools
and code execution. No paid evaluation model calls were made for this
change.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-23 13:57:57 -07:00

404 lines
31 KiB
TypeScript

import { costBoundConfigurationSha256 } from "./cost-bound-evidence.js";
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { connect } from "node:net";
import { afterEach, expect, it, vi } from "vitest";
import { openEvalCostLedger, readEvalCostLedger } from "./cost-ledger.js";
import { beginEvalAgentPhase, createEvalAttemptPhase, readEvalAttemptPhase } from "./attempt-phase.js";
import { evalRequestReservation, EvalUsageStream, forwardEvalRequest, startEvalGateway, type EvalGatewayRoute, type EvalGatewayReceipt } from "./eval-gateway.js";
const directories: string[] = [], closes: Array<() => Promise<void>> = [];
afterEach(async () => { for (const close of closes.splice(0).reverse()) await close(); for (const dir of directories.splice(0)) await rm(dir, { recursive: true, force: true }); });
const identity = { executionId: "hello", attemptId: "attempt", phase: "agent" as const };
const route: EvalGatewayRoute = { provider: "openai", mode: "braintrust", apiKey: "private-upstream-fixture", projectId: "11111111-1111-4111-8111-111111111111", endpointName: "OPENAI_API_KEY",
maximumInputTokens: 1000, maximumOutputTokens: 100, timeoutMs: 2000,
price: { provider: "openai", model: "fixture", version: "fixture-1", sourceUrl: "https://provider.invalid/prices", inputUsdPerMillion: "2", cachedReadUsdPerMillion: "1", outputUsdPerMillion: "10", cacheWrite30mUsdPerMillion: "2", cacheWrite12hUsdPerMillion: "2" } };
const usage = { object: "response", status: "completed", id: "provider-response", model: "fixture", usage: { input_tokens: 10, input_tokens_details: { cache_write_tokens: 0, cached_tokens: 2 }, output_tokens: 5, output_tokens_details: { reasoning_tokens: 3 } } };
const response = () => Response.json(usage, { headers: { "x-bt-used-endpoint": "OPENAI_API_KEY", "x-bt-cached": "MISS", "x-bt-request-id": "gateway-request", "x-bt-span-id": "gateway-span" } });
async function fixture(maxUsd = "1", maxConcurrent = 2) {
const dir = await mkdtemp(path.join(tmpdir(), "eval-forward-test-")); directories.push(dir);
const file = path.join(dir, "ledger.jsonl"), deadlineAt = Date.now() + 30_000;
const ledger = await openEvalCostLedger(file, { campaignId: "campaign", maxUsd, deadlineAt: new Date(deadlineAt).toISOString(), maxRequests: 10, maxConcurrent });
closes.push(() => ledger.close());
const receipts: EvalGatewayReceipt[] = [];
return { ledger, file, deadlineAt, identity, route, receipts, payload: { model: "fixture", input: "hello", max_output_tokens: 500 },
persist: async (receipt: EvalGatewayReceipt) => { receipts.push(structuredClone(receipt)); }, onHeaders: vi.fn(), onChunk: vi.fn(async () => {}) };
}
it("fsyncs reservation before dispatch, pins gateway routing, and replaces reservation with one estimate", async () => {
const f = await fixture();
let captured: RequestInit | undefined;
let reservedBeforeDispatch = false;
const transport = vi.fn<typeof fetch>(async (_url, init) => { captured = init; reservedBeforeDispatch = (await readEvalCostLedger(f.file)).state.snapshot().inflight === 1; return response(); });
const result = await forwardEvalRequest({ ...f, transport });
expect(reservedBeforeDispatch).toBe(true);
expect(transport.mock.calls[0]![0]).toBe("https://gateway.braintrust.dev/responses");
expect(captured).toMatchObject({ redirect: "error", headers: { authorization: `Bearer ${route.apiKey}`, "x-bt-use-cache": "never", "cache-control": "no-cache, no-store", "x-bt-project-id": route.projectId, "x-bt-endpoint-name": route.endpointName, "x-bt-parent": result.braintrustParent } });
expect(JSON.parse(captured!.body as string)).toMatchObject({ max_output_tokens: 100, service_tier: "default" });
expect(result).toMatchObject({ outcome: "succeeded", costUsd: "0.000068000", final: true, usageComplete: true, gatewaySpanId: "gateway-span" });
expect(f.ledger.snapshot()).toMatchObject({ knownUsd: "0.000068000", heldUsd: "0.000000000", inflight: 0 });
expect(await readFile(f.file, "utf8")).not.toContain(route.apiKey);
});
it.each(["openai", "anthropic"] as const)("correlates %s gateway logs before response headers even when the client cancels", async provider => {
const f = await fixture();
const selectedRoute: EvalGatewayRoute = provider === "openai" ? route : { ...route, provider, endpointName: "ANTHROPIC_API_KEY",
price: { ...route.price, provider, cacheWrite5mUsdPerMillion: "2", cacheWrite1hUsdPerMillion: "4" } };
const parents: string[] = [];
const initialReceipts: EvalGatewayReceipt[] = [];
for (let attempt = 0; attempt < 2; attempt++) {
const controller = new AbortController();
const receipt = await forwardEvalRequest({ ...f, route: selectedRoute, signal: controller.signal,
transport: async (_url, init) => {
parents.push(new Headers(init?.headers).get("x-bt-parent")!);
initialReceipts.push(structuredClone(f.receipts.at(-1)!));
controller.abort();
throw new DOMException("client disconnected", "AbortError");
},
});
expect(receipt).toMatchObject({ outcome: "cancelled", errorCode: "request_cancelled", costUsd: null, final: false });
expect(receipt.gatewaySpanId).toBeUndefined();
}
expect(parents[0]).not.toBe(parents[1]);
for (const [index, encoded] of parents.entries()) {
const bytes = Buffer.from(encoded, "base64");
expect([...bytes.subarray(0, 3)]).toEqual([4, 2, 0]);
expect(JSON.parse(bytes.subarray(3).toString())).toEqual({ object_id: route.projectId, propagated_event: { metadata: {
paperclip_eval_request_id: initialReceipts[index]!.requestId, paperclip_eval_campaign_id: "campaign",
paperclip_eval_execution_id: identity.executionId, paperclip_eval_attempt_id: identity.attemptId, paperclip_eval_phase: "agent",
} } });
expect(initialReceipts[index]).toMatchObject({ braintrustParent: encoded, final: false, costUsd: null });
}
expect(f.ledger.snapshot()).toMatchObject({ inflight: 0, unknownRequests: 2, knownUsd: "0.000000000" });
expect(f.ledger.snapshot().heldUsd).not.toBe("0.000000000");
expect(JSON.stringify(initialReceipts)).not.toContain(route.apiKey);
});
it("keeps Braintrust request metadata out of direct provider requests", async () => {
const f = await fixture();
let headers: Headers | undefined;
const receipt = await forwardEvalRequest({ ...f, route: { ...route, mode: "direct" }, transport: async (_url, init) => {
headers = new Headers(init?.headers); return response();
} });
expect(headers!.has("x-bt-parent")).toBe(false);
expect(receipt).not.toHaveProperty("braintrustParent");
});
it("stops at the campaign cap before any upstream request", async () => {
const f = await fixture("0.002"), transport = vi.fn<typeof fetch>();
expect(evalRequestReservation(route)).toBe("0.003000000");
await expect(forwardEvalRequest({ ...f, transport })).rejects.toThrow("spending cap");
expect(transport).not.toHaveBeenCalled();
});
it.each(["direct", "braintrust"] as const)("retains request-policy cost provenance without changing the %s cache policy", async mode => {
const f = await fixture();
const pricedRoute = { ...route, mode, price: { ...route.price, model: "gpt-5.6-sol", inputUsdPerMillion: "4", cachedReadUsdPerMillion: "0.4",
outputUsdPerMillion: "20", cacheWrite30mUsdPerMillion: "5", cacheWrite12hUsdPerMillion: "10" } };
const payload = { ...f.payload, model: pricedRoute.price.model, prompt_cache_retention: "24h", stream: true };
const body = { ...usage, model: pricedRoute.price.model, usage: { ...usage.usage, input_tokens_details: { cache_write_tokens: 6, cached_tokens: 2 } } };
const transport = vi.fn<typeof fetch>(async () => new Response(`data: ${JSON.stringify({ type: "response.completed", response: body })}\n\n`, {
headers: { "content-type": "text/event-stream", "x-bt-used-endpoint": "OPENAI_API_KEY", "x-bt-cached": "MISS" },
}));
const receipt = await forwardEvalRequest({ ...f, route: pricedRoute, payload, transport });
expect(JSON.parse(transport.mock.calls[0]![1]!.body as string)).toEqual({ ...payload, max_output_tokens: 100, service_tier: "default" });
expect(receipt).toMatchObject({ outcome: "succeeded", final: true, costUsd: "0.000138800", usage: { cacheWrite30m: 6, cacheWrite12h: 0,
cacheWriteAttribution: { source: "request_policy", version: "openai-prompt-cache-2026-10-20", ttl: "30m" } } });
expect(f.receipts.at(-1)).toEqual(receipt);
expect(f.ledger.snapshot()).toMatchObject({ knownUsd: "0.000138800", heldUsd: "0.000000000", inflight: 0 });
});
it("retains cancelled and provider-error requests as unknown, including repeated retries", async () => {
const f = await fixture();
const first = await forwardEvalRequest({ ...f, transport: async () => { throw new Error(route.apiKey); } });
const second = await forwardEvalRequest({ ...f, transport: async () => Response.json({ error: "private-provider-message" }, { status: 429 }) });
expect(first).toMatchObject({ outcome: "failed", errorCode: "request_failed", costUsd: null });
expect(second).toMatchObject({ outcome: "failed", errorCode: "upstream_rejected", costUsd: null });
expect(first.requestId).not.toBe(second.requestId);
expect(f.ledger.snapshot()).toMatchObject({ heldUsd: "0.006000000", knownUsd: "0.000000000", unknownRequests: 2 });
expect(JSON.stringify(f.receipts)).not.toMatch(/private-upstream|private-provider-message/);
});
it.each([
{ model: "other" }, { model: "fixture", background: true }, { model: "fixture", service_tier: "priority" },
{ model: "fixture", tools: [{ type: "web_search" }] }, { model: "fixture", input: [{ type: "input_image", image_url: "https://image.invalid" }] },
{ model: "fixture", speed: "fast" }, { model: "fixture", inference_geo: "us" },
])("rejects unpriced request shapes before admission", async payload => {
const f = await fixture(), transport = vi.fn<typeof fetch>();
await expect(forwardEvalRequest({ ...f, payload, transport })).rejects.toThrow();
expect(transport).not.toHaveBeenCalled(); expect(f.ledger.snapshot().requests).toHaveLength(0);
});
it("does not dispatch when the private pre-request receipt cannot be persisted", async () => {
const f = await fixture(), transport = vi.fn<typeof fetch>();
await expect(forwardEvalRequest({ ...f, persist: async () => { throw new Error("disk unavailable"); }, transport })).rejects.toThrow("disk unavailable");
expect(transport).not.toHaveBeenCalled();
expect(f.ledger.snapshot()).toMatchObject({ unknownRequests: 1, heldUsd: "0.003000000" });
});
it("parses actual fragmented SSE without summing cumulative counters", async () => {
const f = await fixture();
const wire = `data: ${JSON.stringify({ type: "response.output_text.delta", delta: "hello 👋" })}\r\n\r\ndata: ${JSON.stringify({ type: "response.completed", response: usage })}\r\n\r\ndata: [DONE]\r\n\r\n`;
const bytes = Buffer.from(wire);
const body = new ReadableStream<Uint8Array>({ start(controller) { for (let i = 0; i < bytes.length; i += 3) controller.enqueue(bytes.subarray(i, i + 3)); controller.close(); } });
const result = await forwardEvalRequest({ ...f, transport: async () => new Response(body, { headers: { "content-type": "text/event-stream", "x-bt-used-endpoint": "OPENAI_API_KEY" } }) });
expect(result).toMatchObject({ costUsd: "0.000068000", final: true });
expect(f.onChunk.mock.calls.length).toBeGreaterThan(1);
const truncated = new EvalUsageStream(() => {});
expect(() => truncated.push(Buffer.from('data: {"type":"response.completed"}'), true)).toThrow("incomplete_usage_stream");
});
it.each([{ "x-bt-cached": "HIT" }, { "x-bt-used-endpoint": "FOREIGN" }, { "x-bt-failover-to": "fixture/FOREIGN" }])("rejects cached/failover/foreign route evidence without releasing the reservation", async headers => {
const f = await fixture();
const result = await forwardEvalRequest({ ...f, transport: async () => Response.json(usage, { headers: Object.fromEntries(Object.entries({ "x-bt-used-endpoint": "OPENAI_API_KEY", ...headers }).filter((pair): pair is [string, string] => pair[1] !== undefined)) }) });
expect(result).toMatchObject({ outcome: "failed", errorCode: "gateway_route_not_qualified", costUsd: null });
expect(f.onChunk).not.toHaveBeenCalled();
expect(f.ledger.snapshot().heldUsd).toBe("0.003000000");
});
it("uses the loopback gateway through real HTTP while withholding upstream credentials from the client", async () => {
const f = await fixture();
const transport = vi.fn<typeof fetch>(async () => response());
const gateway = await startEvalGateway({ ...f, transport }); closes.push(() => gateway.close());
const denied = await fetch(`${gateway.baseUrl}/v1/responses`, { method: "POST", body: "{}" });
expect(denied.status).toBe(401); expect(transport).not.toHaveBeenCalled();
const accepted = await fetch(`${gateway.baseUrl}/v1/responses`, { method: "POST", headers: { authorization: `Bearer ${gateway.token}`, "content-type": "application/json" }, body: JSON.stringify(f.payload) });
expect(accepted.status).toBe(200); expect(await accepted.json()).toEqual(usage);
expect(gateway.token).not.toBe(route.apiKey);
expect(accepted.headers.get("x-paperclip-eval-request-id")).toBeTruthy();
expect([...accepted.headers.values()].join(" ")).not.toContain(route.apiKey);
});
it.each([
{ status: 400, type: "text/plain", body: "private fixture rejection" },
{ status: 503, type: "text/html", body: "<html>private fixture rejection</html>" },
{ status: 400, type: "application/json", body: "invalid JSON fixture rejection" },
])("finishes non-JSON upstream errors without truncating the client response: $status $type", async error => {
const f = await fixture();
const transport = vi.fn<typeof fetch>().mockResolvedValueOnce(new Response(error.body, { status: error.status, headers: { "content-type": error.type } }))
.mockImplementation(async () => response());
const gateway = await startEvalGateway({ ...f, transport }); closes.push(() => gateway.close());
const request = () => fetch(`${gateway.baseUrl}/responses`, { method: "POST", headers: { authorization: `Bearer ${gateway.token}` }, body: JSON.stringify(f.payload) });
const rejected = await request();
expect(rejected.status).toBe(error.status);
expect(await rejected.text()).toBe(error.body);
expect(f.receipts.at(-1)).toMatchObject({ outcome: "failed", errorCode: "upstream_rejected", costUsd: null, usageComplete: false });
expect(f.ledger.snapshot()).toMatchObject({ heldUsd: "0.003000000", unknownRequests: 1, inflight: 0 });
expect(JSON.stringify(f.receipts)).not.toContain(error.body);
expect(await (await request()).json()).toEqual(usage);
expect(transport).toHaveBeenCalledTimes(2);
});
it("still fails successful responses with invalid usage JSON and holds their reservation", async () => {
const f = await fixture();
const result = await forwardEvalRequest({ ...f, transport: async () => new Response("invalid successful response", {
headers: { "content-type": "application/json", "x-bt-used-endpoint": "OPENAI_API_KEY" },
}) });
expect(result).toMatchObject({ outcome: "failed", errorCode: "request_failed", costUsd: null });
expect(f.ledger.snapshot()).toMatchObject({ heldUsd: "0.003000000", unknownRequests: 1, inflight: 0 });
});
it("reserves the highest cache-write and long-context rates before dispatch", () => {
expect(evalRequestReservation({ ...route, price: { ...route.price, cacheWrite12hUsdPerMillion: "5",
longContext: { aboveInputTokens: 100, rates: { inputUsdPerMillion: "4", cachedReadUsdPerMillion: "2", cacheWrite30mUsdPerMillion: "5", cacheWrite12hUsdPerMillion: "10", outputUsdPerMillion: "15" } } } })).toBe("0.011500000");
expect(() => evalRequestReservation({ ...route, price: { ...route.price, cacheWrite12hUsdPerMillion: undefined } })).toThrow("both provider cache-write");
});
it("propagates cancellation to an in-flight upstream request and retains its reservation", async () => {
const f = await fixture(), controller = new AbortController();
const transport = vi.fn<typeof fetch>(async (_url, init) => {
controller.abort();
init!.signal!.throwIfAborted();
throw new Error("unreachable");
});
const receipt = await forwardEvalRequest({ ...f, signal: controller.signal, transport });
expect(receipt).toMatchObject({ outcome: "cancelled", errorCode: "request_cancelled", final: false, costUsd: null });
expect(transport).toHaveBeenCalledOnce();
expect(f.ledger.snapshot()).toMatchObject({ heldUsd: "0.003000000", unknownRequests: 1, inflight: 0 });
});
it("does not release a reservation for an otherwise final response missing cache-write usage", async () => {
const f = await fixture(), body = structuredClone(usage);
delete (body.usage.input_tokens_details as any).cache_write_tokens;
const receipt = await forwardEvalRequest({ ...f, transport: async () => Response.json(body, { headers: { "x-bt-used-endpoint": "OPENAI_API_KEY" } }) });
expect(receipt).toMatchObject({ outcome: "succeeded", usageComplete: false, final: true, costUsd: null });
expect(f.ledger.snapshot()).toMatchObject({ heldUsd: "0.003000000", unknownRequests: 1 });
});
it.each([{ version: "prices with spaces" }, { model: "model with spaces" }])("rejects invalid ledger price identities before reserving or dispatching", async invalid => {
const f = await fixture(), transport = vi.fn<typeof fetch>();
const price = { ...route.price, ...invalid };
await expect(forwardEvalRequest({ ...f, route: { ...route, price }, payload: { model: price.model }, transport })).rejects.toThrow("price identity");
expect(transport).not.toHaveBeenCalled();
expect(f.ledger.snapshot().requests).toHaveLength(0);
});
it("retains invalid reasoning counters privately and finishes an unknown charge", async () => {
const f = await fixture(), body = structuredClone(usage);
body.usage.output_tokens_details.reasoning_tokens = 6;
const receipt = await forwardEvalRequest({ ...f, transport: async () => Response.json(body, { headers: { "x-bt-used-endpoint": "OPENAI_API_KEY" } }) });
expect(receipt).toMatchObject({ outcome: "succeeded", errorCode: "invalid_usage", usageComplete: false, final: true, costUsd: null,
usage: { tokens: { output: 5, reasoning: 6 } } });
expect(f.receipts.at(-1)).toEqual(receipt);
expect(f.ledger.snapshot()).toMatchObject({ heldUsd: "0.003000000", unknownRequests: 1, inflight: 0 });
const journal = await readFile(f.file, "utf8");
expect(journal).not.toContain('"reasoning":6');
expect(journal).toContain('"type":"finish"');
});
it("retains malformed provider identifiers without losing the final receipt or ledger finish", async () => {
const f = await fixture();
const receipt = await forwardEvalRequest({ ...f, transport: async () => Response.json({ ...usage, model: "unexpected model name" },
{ headers: { "x-bt-used-endpoint": "OPENAI_API_KEY", "x-request-id": "request with spaces" } }) });
expect(receipt).toMatchObject({ providerRequestId: "request with spaces", usage: { model: "unexpected model name" }, final: true, costUsd: null });
expect(f.receipts.at(-1)).toEqual(receipt);
expect(f.ledger.snapshot()).toMatchObject({ heldUsd: "0.003000000", unknownRequests: 1, inflight: 0 });
});
it("admits later HTTP requests after temporary concurrency exhaustion", async () => {
const f = await fixture("1", 1);
let admitted!: () => void, release!: () => void;
const started = new Promise<void>(resolve => { admitted = resolve; });
const blocked = new Promise<void>(resolve => { release = resolve; });
const transport = vi.fn<typeof fetch>(async () => { admitted(); await blocked; return response(); });
const gateway = await startEvalGateway({ ...f, transport }); closes.push(() => gateway.close());
const request = () => fetch(`${gateway.baseUrl}/responses`, { method: "POST", headers: { authorization: `Bearer ${gateway.token}` }, body: JSON.stringify(f.payload) });
const first = request(); await started;
try {
const denied = await request();
expect(denied.status).toBe(429); expect(transport).toHaveBeenCalledOnce();
} finally { release(); }
expect(await (await first).json()).toEqual(usage);
const later = await request();
expect(later.status).toBe(200); expect(await later.json()).toEqual(usage);
expect(transport).toHaveBeenCalledTimes(2);
expect(f.ledger.snapshot()).toMatchObject({ inflight: 0, unknownRequests: 0 });
});
it("rejects malformed, interrupted and unqualified uploads without disabling later valid requests", async () => {
const f = await fixture(), transport = vi.fn<typeof fetch>(async () => response());
const gateway = await startEvalGateway({ ...f, transport }); closes.push(() => gateway.close());
const headers = { authorization: `Bearer ${gateway.token}` };
for (const body of ["{", JSON.stringify({ model: "other" }), JSON.stringify({ model: "fixture", tools: [{ type: "web_search" }] })]) {
const rejected = await fetch(`${gateway.baseUrl}/responses`, { method: "POST", headers, body });
expect(rejected.status).toBe(400); await rejected.text();
}
await new Promise<void>((resolve, reject) => {
const socket = connect(Number(new URL(gateway.baseUrl).port), "127.0.0.1");
socket.on("error", reject); socket.on("close", () => resolve()); socket.resume();
socket.on("connect", () => socket.end(`POST /responses HTTP/1.1\r\nHost: localhost\r\nAuthorization: Bearer ${gateway.token}\r\nContent-Length: 100\r\n\r\n{`));
});
expect(transport).not.toHaveBeenCalled(); expect(f.ledger.snapshot().requests).toHaveLength(0);
const valid = await fetch(`${gateway.baseUrl}/responses`, { method: "POST", headers, body: JSON.stringify(f.payload) });
expect(valid.status).toBe(200); expect(await valid.json()).toEqual(usage);
expect(transport).toHaveBeenCalledOnce(); expect(f.ledger.snapshot().requests).toHaveLength(1);
});
it("still disables the HTTP gateway after a receipt persistence failure", async () => {
const f = await fixture(), transport = vi.fn<typeof fetch>(async () => response());
const gateway = await startEvalGateway({ ...f, transport, persist: async () => { throw new Error("storage failure"); } }); closes.push(() => gateway.close());
for (let i = 0; i < 2; i++) {
const denied = await fetch(`${gateway.baseUrl}/responses`, { method: "POST", headers: { authorization: `Bearer ${gateway.token}` }, body: JSON.stringify(f.payload) });
expect(denied.status).toBe(503); await denied.text();
}
expect(transport).not.toHaveBeenCalled(); expect(f.ledger.snapshot().requests).toHaveLength(1);
});
it("applies the request deadline while waiting for downstream backpressure", async () => {
const f = await fixture();
const receipt = await forwardEvalRequest({ ...f, route: { ...f.route, timeoutMs: 50 }, transport: async () => response(),
onChunk: async (_chunk, signal) => {
signal.throwIfAborted();
await new Promise<void>((_resolve, reject) => signal.addEventListener("abort", () => reject(signal.reason), { once: true }));
},
});
expect(receipt).toMatchObject({ outcome: "cancelled", errorCode: "request_cancelled" });
expect(f.ledger.snapshot()).toMatchObject({ inflight: 0, unknownRequests: 1, heldUsd: "0.003000000" });
});
it("forwards Claude's Messages beta query without admitting unrelated endpoints or queries", async () => {
const f = await fixture();
const anthropicRoute: EvalGatewayRoute = { ...route, provider: "anthropic", mode: "direct", price: { provider: "anthropic", model: "fixture",
version: "fixture", sourceUrl: "https://provider.invalid/prices", inputUsdPerMillion: "2", cachedReadUsdPerMillion: "1", outputUsdPerMillion: "10",
cacheWrite5mUsdPerMillion: "2.5", cacheWrite1hUsdPerMillion: "4" } };
const body = { type: "message", model: "fixture", usage: { input_tokens: 2, output_tokens: 3, cache_creation_input_tokens: 0, cache_read_input_tokens: 0 } };
const transport = vi.fn<typeof fetch>(async () => Response.json(body));
const gateway = await startEvalGateway({ ...f, route: anthropicRoute, transport }); closes.push(() => gateway.close());
const request = (pathname: string) => fetch(gateway.baseUrl + pathname, { method: "POST", headers: { "x-api-key": gateway.token, "anthropic-beta": "fixture-beta" }, body: JSON.stringify({ model: "fixture", messages: [] }) });
expect((await request("/v1/messages?beta=true&extra=true")).status).toBe(404);
const accepted = await request("/v1/messages?beta=true");
expect(accepted.status).toBe(200); expect(await accepted.json()).toEqual(body);
expect(transport).toHaveBeenCalledOnce();
expect(transport.mock.calls[0]![0]).toBe("https://api.anthropic.com/v1/messages?beta=true");
expect(transport.mock.calls[0]![1]!.headers).toMatchObject({ "anthropic-beta": "fixture-beta" });
expect(f.ledger.snapshot()).toMatchObject({ unknownRequests: 0, inflight: 0 });
});
it("attributes setup at admission, preserves it during execution, and blocks missing phase evidence", async () => {
const f = await fixture();
const phasePath = path.join(path.dirname(f.file), "phase.json");
await createEvalAttemptPhase(phasePath, identity);
const env = { PAPERCLIP_E2E_GATEWAY_PHASE_PATH: phasePath, PAPERCLIP_E2E_ACCOUNTING_ATTEMPT_ID: identity.attemptId };
let started!: () => void, release!: () => void, calls = 0;
const firstStarted = new Promise<void>(resolve => { started = resolve; });
const continuation = new Promise<void>(resolve => { release = resolve; });
const gateway = await startEvalGateway({ ...f, resolveIdentity: () => readEvalAttemptPhase(phasePath, identity),
transport: async () => {
calls++;
if (calls === 1) { started(); await continuation; }
return Response.json({ ...usage, id: `provider-${calls}` }, { headers: { "x-bt-used-endpoint": "OPENAI_API_KEY" } });
},
});
closes.push(() => gateway.close());
const send = () => fetch(`${gateway.baseUrl}/responses`, { method: "POST", headers: { authorization: `Bearer ${gateway.token}` }, body: JSON.stringify(f.payload) });
const first = send();
await firstStarted;
await beginEvalAgentPhase(identity.executionId, env);
release();
expect((await first).status).toBe(200);
expect((await send()).status).toBe(200);
expect(f.ledger.snapshot().requests.map(request => request.phase)).toEqual(["setup", "agent"]);
await writeFile(phasePath, JSON.stringify({ version: 1, ...identity, attemptId: "foreign-attempt" }));
expect((await send()).status).toBe(503);
expect(calls).toBe(2);
expect((await readEvalCostLedger(f.file)).state.snapshot().requests.map(request => request.phase)).toEqual(["setup", "agent"]);
});
it("refuses missing or unreviewed attribution checkpoints before request dispatch", async () => {
const f = await fixture(), transport = vi.fn<typeof fetch>();
const phasePath = path.join(path.dirname(f.file), "missing-phase.json");
const gateway = await startEvalGateway({ ...f, transport, resolveIdentity: () => readEvalAttemptPhase(phasePath, identity) });
closes.push(() => gateway.close());
const response = await fetch(`${gateway.baseUrl}/responses`, { method: "POST", headers: { authorization: `Bearer ${gateway.token}` }, body: JSON.stringify(f.payload) });
expect(response.status).toBe(503);
expect(transport).not.toHaveBeenCalled();
expect(f.ledger.snapshot().requests).toEqual([]);
await expect(beginEvalAgentPhase(identity.executionId, { PAPERCLIP_E2E_GATEWAY_BASE_URL: gateway.baseUrl })).rejects.toThrow("Missing eval phase");
await createEvalAttemptPhase(phasePath, identity);
await expect(createEvalAttemptPhase(phasePath, identity)).rejects.toThrow();
await writeFile(phasePath, JSON.stringify({ version: 1, ...identity, providerResponse: "private" }));
await expect(readEvalAttemptPhase(phasePath, identity)).rejects.toThrow("Invalid eval phase");
});
const provisionalBound = { version: 1 as const, scope: "full_lifecycle" as const, evidenceSha256: "a".repeat(64),
configurationSha256: costBoundConfigurationSha256({ provider: route.provider, mode: route.mode, price: route.price,
maximumInputTokens: route.maximumInputTokens, maximumOutputTokens: route.maximumOutputTokens, reservation: evalRequestReservation(route) }) };
it("retains a reviewed model bound through a partial response and durable reload without releasing the hold", async () => {
const f = await fixture();
const receipt = await forwardEvalRequest({ ...f, route: { ...route, provisionalBound }, transport: async () => {
expect((await readEvalCostLedger(f.file)).state.requests.values().next().value?.bound?.evidence).toEqual(provisionalBound);
return Response.json({ object: "response", status: "in_progress", model: "fixture" },
{ headers: { "x-bt-used-endpoint": route.endpointName! } });
} });
expect(receipt).toMatchObject({ costUsd: null, final: false });
expect((await readEvalCostLedger(f.file)).state.snapshot()).toMatchObject({ boundedUnresolvedRequests: 1, heldUsd: "0.003000000" });
});
it.each(["no-headers", "route", "failover", "model", "input-limit", "output-limit"])("disqualifies a model bound on %s evidence", async reason => {
const f = await fixture();
await forwardEvalRequest({ ...f, route: { ...route, provisionalBound }, transport: async () => {
if (reason === "no-headers") throw new Error("No response headers");
return Response.json({ object: "response", status: "in_progress", model: reason === "model" ? "other" : "fixture",
usage: { input_tokens: reason === "input-limit" ? 1001 : 10, input_tokens_details: { cache_write_tokens: 0, cached_tokens: 0 },
output_tokens: reason === "output-limit" ? 101 : 0 } },
{ headers: { "x-bt-used-endpoint": reason === "route" ? "OTHER" : route.endpointName!,
...(reason === "failover" ? { "x-bt-failover-to": "OTHER" } : {}) } });
} });
const replay = (await readEvalCostLedger(f.file)).state;
expect(replay.snapshot()).toMatchObject({ boundedUnresolvedRequests: 0, unknownRequests: 1, inflight: 0 });
expect([...replay.requests.values()][0]!.boundInvalidated).toBe(true);
});
it("refuses a changed model limit or rate with a stale reviewed bound before dispatch", async () => {
const f = await fixture(), transport = vi.fn<typeof fetch>();
for (const changed of [{ ...route, maximumInputTokens: 500 }, { ...route, price: { ...route.price, inputUsdPerMillion: "20" } }]) {
await expect(forwardEvalRequest({ ...f, route: { ...changed, provisionalBound }, transport })).rejects.toThrow("configuration changed");
}
expect(transport).not.toHaveBeenCalled();
expect(f.ledger.snapshot().requests).toHaveLength(0);
});
it("disqualifies excessive reported input even when missing cache details prevent pricing", async () => {
const f = await fixture();
await forwardEvalRequest({ ...f, route: { ...route, provisionalBound }, transport: async () => Response.json({
object: "response", status: "completed", model: "fixture", usage: { input_tokens: 1001, output_tokens: 1 },
}, { headers: { "x-bt-used-endpoint": route.endpointName! } }) });
expect((await readEvalCostLedger(f.file)).state.snapshot()).toMatchObject({ boundedUnresolvedRequests: 0, unknownRequests: 1, heldUsd: "0.003000000" });
});