fix(evals): retain annotated failed controller attempts

This commit is contained in:
Dotta committed 2026-10-24 13:04:11 -07:00
1 parent 4d6673d8ce
commit 7d4eeb5728
2 files changed
+22 -2

No files matched your search

@@ -143,7 +143,8 @@ export async function readAttemptControlledEvidence(directory, options) {
throw new Error('Invalid immutable controller retention failure');
}
delete actual.controllerEvidenceError;
if (!expected.accountingFailure) { delete actual.accountingFailure; delete actual.accountingError; }
if (expected.accountingFailure) { actual.accountingFailure = expected.accountingFailure; actual.accountingError = expected.accountingError; }
else { delete actual.accountingFailure; delete actual.accountingError; }
}
if (canonical(actual) !== canonical(expected)) throw new Error('Immutable result disagrees with its controller proof');
}
@@ -7,7 +7,7 @@ import { join } from 'node:path';
import { canonical, costRuntime, requestBindingSha256, sha256, validateManifest } from './manifest.mjs';
import { attemptDirectory, runControlledEval } from './run.mjs';
import { summarizeControlledCampaign } from './report.mjs';
import { decodeControlledEvidence, packControlledAttempt, readControlledEvidence, summarizeControlledEvidence } from './archive.mjs';
import { decodeControlledEvidence, packControlledAttempt, readControlledEvidence, readAttemptControlledEvidence, summarizeControlledEvidence } from './archive.mjs';
import { aggregateProtocolEvalCampaign, sanitizeProtocolEvalRuns } from '../runner-protocol-eval-campaign.mjs';
const childScript = options => `
@@ -378,6 +378,25 @@ test('configured credentials are excluded before encoding and after archive deco
await assert.rejects(readControlledEvidence(file, { environment }), /configured credential/);
});
test('retention annotations preserve an already-failed controller result and its known costs', async t => {
const f = await fixture(t, { requests: 1, missingRoute: true }); await f.run();
const bundle = await packControlledAttempt({ manifest: f.manifest, attemptId: 'attempt-0' });
const artifact = JSON.parse(await readFile(f.requests[0].outputPath, 'utf8'));
assert.equal(artifact.controllerAccounting.status, 'incomplete');
artifact.controllerEvidenceError = 'A later retention check failed';
artifact.accountingError = artifact.controllerEvidenceError;
const directory = join(f.root, 'runs', 'attempt-0'); await mkdir(directory, { recursive: true });
for (const [name, value] of Object.entries({ 'request.json': f.requests[0].request, 'artifact.json': artifact, 'controller-evidence.json': bundle })) {
await writeFile(join(directory, name), JSON.stringify(value));
}
const retained = await readAttemptControlledEvidence(directory);
const report = await summarizeControlledEvidence([retained]);
assert.equal(report.costStatus, 'incomplete');
assert.equal(report.knownUsd, '0.000068000');
assert.equal(report.committedUsd, '0.014000000');
assert.equal(JSON.parse(await readFile(join(directory, 'artifact.json'), 'utf8')).accountingError, artifact.controllerEvidenceError);
});
test('campaign collection retains and audits private archives, while public projection omits them', async t => {
const f = await fixture(t, { count: 2, requests: 1 }); await f.run();
const bundle = await packControlledAttempt({ manifest: f.manifest, attemptId: 'attempt-0' });