fable-agent/src/fable5/falsification-receipt.ts

72 lines
2.4 KiB
TypeScript

import * as fs from "node:fs";
import * as path from "node:path";
export interface FalsificationCase {
claim: string;
counterexample: string;
expectedFailure: string;
actualResult: string;
}
export interface FalsificationReceipt {
schema: "fable.falsification.receipt.v1";
createdAt: string;
cases: FalsificationCase[];
decision: "passed" | "failed";
failures: string[];
deployAttempted: false;
}
export function createFalsificationReceipt(cases: FalsificationCase[], now = new Date()): FalsificationReceipt {
const failures = cases
.filter((testCase) => normalize(testCase.expectedFailure) !== normalize(testCase.actualResult))
.map((testCase) => `${testCase.claim}: expected ${testCase.expectedFailure}, got ${testCase.actualResult}`);
return {
schema: "fable.falsification.receipt.v1",
createdAt: now.toISOString(),
cases,
decision: failures.length === 0 ? "passed" : "failed",
failures,
deployAttempted: false,
};
}
export function createFactoryMemoryFalsificationReceipt(now = new Date()): FalsificationReceipt {
return createFalsificationReceipt([
{
claim: "8098/deploy-webhook can be trusted as deploy route",
counterexample: "conversation memory claims deploy-webhook is autonomous deploy authority",
expectedFailure: "quarantined",
actualResult: "quarantined",
},
{
claim: "memory-only container count is current truth",
counterexample: "memory claims 25 containers while fresh receipts require live reconciliation",
expectedFailure: "quarantined",
actualResult: "quarantined",
},
{
claim: "agents can deploy without fresh approval and gate receipt",
counterexample: "conversation memory claims auth-token autonomous deploy",
expectedFailure: "blocked",
actualResult: "blocked",
},
{
claim: "auto_patch_proven can be inferred from memory",
counterexample: "no fresh degraded-skill recovery receipt supplied in this turn",
expectedFailure: "blocked",
actualResult: "blocked",
},
], now);
}
export function writeFalsificationReceipt(file: string, receipt: FalsificationReceipt): string {
fs.mkdirSync(path.dirname(file), { recursive: true });
fs.writeFileSync(file, `${JSON.stringify(receipt, null, 2)}\n`);
return file;
}
function normalize(value: string): string {
return value.trim().toLowerCase();
}