Files
reverse-engineering-anything/tests/boundary/mcp/processComparisonVerificationMcp.test.ts

139 lines
5.2 KiB
TypeScript

import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it, onTestFinished } from "vitest";
import { createEvidence, parseEvidence } from "../../../src/domain/evidence.js";
import { createEvidenceBundle } from "../../../src/domain/evidenceBundle.js";
import { EMPTY_PROCESS_CAPTURE_EXAMPLE } from "../../../src/domain/process/processCaptureExample.js";
import { parseProcessCapture } from "../../../src/domain/process/processCaptureParsing.js";
import { compareProcessCaptures } from "../../../src/domain/process/processComparison.js";
import { PROCESS_PROVIDER } from "../../../src/domain/process/processEvidenceProvider.js";
import { reconstructionVerificationResultSchema } from "../../../src/domain/reconstructionVerificationSchemas.js";
import { createApplicationMcpHarness } from "../../fixtures/applicationMcpHarness.js";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
it("rejects an inconsistent imported process comparison while retaining its Evidence", async () => {
const dimension = "terminal" as const;
const source = (side: string) =>
createEvidence(undefined, PROCESS_PROVIDER, {
predicateType: "rea.process-capture",
operation: "capture_process_scenario",
parameters: { side },
result: EMPTY_PROCESS_CAPTURE_EXAMPLE,
confidence: "observed",
authority: "controlled-replay",
environment: {
id: "fixture",
platform: "fixture",
architecture: "fixture",
isolation: "process",
},
});
const left = source("left");
const right = source("right");
const nativeResult = compareProcessCaptures(
parseProcessCapture(left.normalized_result),
parseProcessCapture(right.normalized_result),
);
expect(nativeResult.status).toBe("unchanged");
const comparison = (status: "unchanged" | "contradiction") =>
createEvidence(undefined, PROCESS_PROVIDER, {
predicateType: "rea.process-comparison",
operation: "compare_process_captures",
parameters: {
left_evidence_id: left.evidence_id,
right_evidence_id: right.evidence_id,
},
result: {
...nativeResult,
[dimension]: "contradiction",
status,
},
confidence: "derived",
authority: "analyst-inference",
evidenceLinks: [left.evidence_id, right.evidence_id],
});
const inconsistent = comparison("unchanged");
const consistent = comparison("contradiction");
const root = await createTestTempDirectory("rea-process-verification-");
const path = join(root, "bundle.json");
await writeFile(
path,
JSON.stringify(
createEvidenceBundle([left, right, inconsistent, consistent]),
),
);
let providerLaunches = 0;
const session = createTestBinarySession(() => {
providerLaunches += 1;
throw new Error("Imported process verification must not launch a provider");
});
const harness = await createApplicationMcpHarness({ session });
onTestFinished(harness.close);
const imported = await harness.client.callTool({
name: "import_evidence_bundle",
arguments: { path },
});
expect(imported.isError).not.toBe(true);
const verify = (evidenceId: string, selected: "overall" | typeof dimension) =>
harness.client.callTool({
name: "verify_reconstruction",
arguments: {
specification: {
name: "Process comparison consistency",
claims: [
{
kind: "behavioral",
claim_id: selected,
title: "Process replay agrees",
comparison_evidence_id: evidenceId,
dimension: selected,
},
],
},
},
});
for (const selected of ["overall", dimension] as const) {
const rejected = await verify(inconsistent.evidence_id, selected);
expect(parseMcpToolError(rejected).error).toMatchObject({
code: "evidence_integrity_mismatch",
details: {
reason: expect.stringContaining(
"Process comparison status contradicts its dimensions",
),
},
});
const failed = await verify(consistent.evidence_id, selected);
expect(failed.isError).not.toBe(true);
expect(
reconstructionVerificationResultSchema.parse(
parseEvidence(failed.structuredContent).normalized_result,
),
).toMatchObject({
status: "fail",
claims: { items: [{ observed_status: "contradiction" }] },
});
}
for (const record of [left, right, inconsistent, consistent])
expect(session.evidenceById(record.evidence_id)).toEqual(record);
const recomputed = await harness.client.callTool({
name: "compare_process_captures",
arguments: { left, right },
});
expect(recomputed.isError).not.toBe(true);
const control = parseEvidence(recomputed.structuredContent);
const verified = await verify(control.evidence_id, "overall");
expect(verified.isError).not.toBe(true);
expect(
reconstructionVerificationResultSchema.parse(
parseEvidence(verified.structuredContent).normalized_result,
),
).toMatchObject({ status: "pass" });
expect(providerLaunches).toBe(0);
await harness.client.ping();
});