import { readFile, writeFile } from "node:fs/promises"; import { join } from "node:path"; import { expect } from "vitest"; import { cliTest, type TestCli } from "../../support/cli/cliFixture.js"; import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; import { connectLocalToolsMcp } from "../../fixtures/localToolsMcp.js"; import { parseMcpToolError } from "../../fixtures/mcpToolError.js"; import { nativeMatchingInventory, nativeMatchingDetails, nativeMatchingTarget, } from "../../fixtures/nativeFunctionMatching.js"; import { createEvidence, parseEvidence } from "../../../src/domain/evidence.js"; import { nativeMatchingProvider } from "../../fixtures/nativeFunctionMatching.js"; import { procedureInfoSchema } from "../../../src/domain/native/procedureInfo.js"; import { createEvidenceBundle, parseEvidenceBundle, } from "../../../src/domain/evidenceBundle.js"; import { nativeFunctionMatchingSchema } from "../../../src/domain/native/functionMatching.js"; const createMatchingFixture = async () => { const root = await createTestTempDirectory("rea-native-matching-"); const ancestor = createEvidence(undefined, nativeMatchingProvider, { operation: "fixture_provenance", parameters: {}, result: { source: "Synthetic ancestor" }, }); const unrelated = createEvidence(undefined, nativeMatchingProvider, { operation: "fixture_unrelated", parameters: {}, result: { source: "Unselected synthetic record" }, }); const dependency = createEvidence(undefined, nativeMatchingProvider, { operation: "fixture_dependency", parameters: {}, result: { source: "Synthetic dependency" }, evidenceLinks: [ancestor.evidence_id], }); const left = nativeMatchingInventory( "1", [ { address: "0x10", value: "main" }, { address: "0x20", value: "old_name" }, ], [dependency.evidence_id], ); const right = nativeMatchingInventory("2", [ { address: "0x30", value: "main" }, { address: "0x40", value: "new_name" }, ]); const leftDetails = [ ...nativeMatchingDetails("1", "0x10", "9000", true), ...nativeMatchingDetails("1", "0x20", "c3", true), ]; const rightDetails = [ ...nativeMatchingDetails("2", "0x30", "9001", true), ...nativeMatchingDetails("2", "0x40", "c3", true), ]; const ancestorsPath = join(root, "ancestors.json"); await writeFile( ancestorsPath, JSON.stringify(createEvidenceBundle([ancestor, unrelated])), ); const importedPath = join(root, "dependencies.json"); await writeFile( importedPath, JSON.stringify(createEvidenceBundle([ancestor, dependency])), ); return { root, ancestor, dependency, unrelated, left, right, leftDetails, rightDetails, ancestorsPath, importedPath, }; }; const verifyPortableCli = async ( cli: TestCli, fixture: Awaited>, input: Record, evidenceId: string, ) => { const { root, ancestor, dependency, unrelated, left, right, leftDetails, rightDetails, ancestorsPath, } = fixture; const bundlePath = join(root, "sources.json"), inputPath = join(root, "request.json"), outputPath = join(root, "result.json"); await writeFile( bundlePath, JSON.stringify( createEvidenceBundle([ left, right, ...leftDetails, ...rightDetails, dependency, ]), ), ); const original = await readFile(bundlePath); await writeFile(inputPath, JSON.stringify({ ...input, detail: "complete" })); const cliFull = await cli.run({ arguments: [ "match-native-functions", inputPath, "--source_bundle", ancestorsPath, "--source_bundle", bundlePath, "--json", ], }); expect(cliFull.exitCode, cliFull.stderr).toBe(0); expect(parseEvidence(cliFull.json).evidence_id).toBe(evidenceId); await writeFile(inputPath, JSON.stringify(input)); const cliSummary = await cli.run({ arguments: [ "match-native-functions", inputPath, "--source_bundle", ancestorsPath, "--source_bundle", bundlePath, "--evidence_output", outputPath, "--json", ], }); expect(cliSummary.exitCode, cliSummary.stderr).toBe(0); expect(cliSummary.json).toMatchObject({ summary: { normalized_result: { parent_evidence_id: evidenceId }, }, evidence_bundle: { path: outputPath }, }); const bundle = parseEvidenceBundle( JSON.parse(await readFile(outputPath, "utf8")), ); const ids = new Set(bundle.records.map((x) => x.evidence_id)); for (const record of bundle.records) for (const id of record.evidence_links) expect( ids.has(id), `Missing dependency ${id} of ${record.evidence_id}`, ).toBe(true); expect(ids.has(ancestor.evidence_id)).toBe(true); expect(ids.has(dependency.evidence_id)).toBe(true); expect(ids.has(unrelated.evidence_id)).toBe(false); expect(ids.has(evidenceId)).toBe(true); expect(await readFile(bundlePath)).toEqual(original); const incomplete = await cli.run({ arguments: [ "match-native-functions", inputPath, "--source_bundle", bundlePath, "--evidence_output", join(root, "incomplete.json"), "--json", ], }); expect(incomplete.json).toMatchObject({ code: "evidence_integrity_mismatch", }); }; cliTest.for([{ profile: "full" }, { profile: "compact" }] as const)( "shared public CLI/MCP matching retains sources, pages exact facts, and feeds selected dossier pairs directly to compare_functions ($profile)", { timeout: 60000 }, async ({ profile }, { cli }) => { const fixture = await createMatchingFixture(); const { left, right, leftDetails, rightDetails, importedPath } = fixture; const { call } = await connectLocalToolsMcp({ REA_MCP_INPUT_SCHEMA_PROFILE: profile, }); const imported = await call("import_evidence_bundle", { path: importedPath, }); expect(imported.isError, JSON.stringify(imported)).not.toBe(true); const full = await call("match_native_functions", { left, right, left_observations: leftDetails, right_observations: rightDetails, detail: "complete", }); expect(full.isError, JSON.stringify(full)).not.toBe(true); const evidence = parseEvidence(full.structuredContent), report = nativeFunctionMatchingSchema.parse(evidence.normalized_result); expect(report.summary).toEqual({ matched: 2, only_left: 0, only_right: 0, unresolved: 0, }); const reference = (evidence_id: string) => ({ kind: "retained-evidence", evidence_id, }); const input = { left: reference(left.evidence_id), right: reference(right.evidence_id), left_observations: leftDetails.map((x) => reference(x.evidence_id)), right_observations: rightDetails.map((x) => reference(x.evidence_id)), }; const summary = await call("match_native_functions", input); expect(summary.isError, JSON.stringify(summary)).not.toBe(true); expect( parseEvidence(summary.structuredContent).normalized_result, ).toMatchObject({ kind: "summary", artifact: null, parent_evidence_id: evidence.evidence_id, summary: { summary: report.summary }, }); expect(parseEvidence(summary.structuredContent).locations).not.toEqual( expect.arrayContaining([ expect.objectContaining({ kind: "artifact-path" }), ]), ); const page = await call("inspect_analysis_view", { source: reference(evidence.evidence_id), view: { kind: "function-matches", collection: "functions", sides: ["left"], fields: ["name", "body_sha256"], offset: 1, limit: 1, }, }); expect(page.isError, JSON.stringify(page)).not.toBe(true); expect( parseEvidence(page.structuredContent).normalized_result, ).toMatchObject({ artifact: null, coverage: { total: 2, next_offset: null }, items: [ { name: "old_name", function_id: `${left.evidence_id}/1`, address: "0x20", }, ], }); expect(parseEvidence(page.structuredContent).locations).not.toEqual( expect.arrayContaining([ expect.objectContaining({ kind: "artifact-path" }), ]), ); const compared = await call( "compare_functions", report.matches[0]!.compare_functions_input!, ); expect(compared.isError, JSON.stringify(compared)).not.toBe(true); expect(parseEvidence(compared.structuredContent).operation).toBe( "compare_functions", ); await verifyPortableCli(cli, fixture, input, evidence.evidence_id); const missing = await call("match_native_functions", { left: reference(`ev_${"a".repeat(64)}`), right: reference(right.evidence_id), }); expect(missing.isError).toBe(true); }, ); cliTest( "native matching rejects corrupt and misselected MCP sources without retaining them", async () => { const fixture = await createMatchingFixture(); const { left, right, leftDetails, root, importedPath } = fixture; const { call } = await connectLocalToolsMcp(); const importedSources = await call("import_evidence_bundle", { path: importedPath, }); expect(importedSources.isError, JSON.stringify(importedSources)).not.toBe( true, ); const before = await call("get_evidence_bundle", {}); const corruptEnvelope = { ...left, normalized_result: [] }; const badCoordinate = nativeMatchingInventory("1", [ { address: "not-an-address", value: "main" }, ]); const observationResult = procedureInfoSchema.parse( nativeMatchingDetails("1", "0x10", "c3")[0]!.normalized_result, ); const corruptObservation = createEvidence( nativeMatchingTarget("1"), nativeMatchingProvider, { operation: "procedure_info", parameters: { procedure: "0x10" }, result: { ...observationResult, entrypoint: "not-an-address", }, }, ); for (const { request, expected } of [ { request: { left: corruptEnvelope, right }, expected: { code: "evidence_integrity_mismatch" }, }, { request: { left: badCoordinate, right }, expected: { code: "evidence_integrity_mismatch" }, }, { request: { left, right, left_observations: [corruptObservation] }, expected: { code: "evidence_integrity_mismatch" }, }, { request: { left: leftDetails[0], right }, expected: { code: "invalid_request", details: { issues: [expect.objectContaining({ path: ["left"] })], }, }, }, ]) { const rejected = await call("match_native_functions", { ...request, detail: "complete", }); expect(parseMcpToolError(rejected).error).toMatchObject(expected); expect((await call("get_evidence_bundle", {})).structuredContent).toEqual( before.structuredContent, ); } const corruptBundlePath = join(root, "corrupt-source.json"); await writeFile( corruptBundlePath, JSON.stringify(createEvidenceBundle([badCoordinate, right])), ); const importedCorruptPayload = await call("import_evidence_bundle", { path: corruptBundlePath, }); expect( importedCorruptPayload.isError, JSON.stringify(importedCorruptPayload), ).not.toBe(true); const retainedBefore = await call("get_evidence_bundle", {}); const retainedFailure = await call("match_native_functions", { left: { kind: "retained-evidence", evidence_id: badCoordinate.evidence_id, }, right: { kind: "retained-evidence", evidence_id: right.evidence_id }, detail: "complete", }); expect(parseMcpToolError(retainedFailure).error).toMatchObject({ code: "evidence_integrity_mismatch", details: { reason: expect.stringContaining("Evidence validation failed"), }, }); expect((await call("get_evidence_bundle", {})).structuredContent).toEqual( retainedBefore.structuredContent, ); const malformedOuterRequest = await call("match_native_functions", { right, detail: "complete", }); expect(parseMcpToolError(malformedOuterRequest).error.code).toBe( "invalid_request", ); expect((await call("get_evidence_bundle", {})).structuredContent).toEqual( retainedBefore.structuredContent, ); }, 60000, ); cliTest( "native matching CLI inline and portable sources report the same validation errors", async ({ cli }) => { const fixture = await createMatchingFixture(); const { left, right, leftDetails, root } = fixture; const badCoordinate = nativeMatchingInventory("1", [ { address: "not-an-address", value: "main" }, ]); const corruptBundlePath = join(root, "corrupt-source.json"); await writeFile( corruptBundlePath, JSON.stringify(createEvidenceBundle([badCoordinate, right])), ); const requestPath = join(root, "wrong-role-request.json"); const portablePath = join(root, "wrong-role-sources.json"); const wrongRole = leftDetails[0]!; const inlineRequest = { left: wrongRole, right, detail: "complete" }; const portableRequest = { left: { kind: "retained-evidence", evidence_id: wrongRole.evidence_id }, right: { kind: "retained-evidence", evidence_id: right.evidence_id }, detail: "complete", }; await writeFile(requestPath, JSON.stringify(inlineRequest)); const inline = await cli.run({ arguments: ["match-native-functions", requestPath, "--json"], }); await writeFile( portablePath, JSON.stringify(createEvidenceBundle([wrongRole, right])), ); await writeFile(requestPath, JSON.stringify(portableRequest)); const portable = await cli.run({ arguments: [ "match-native-functions", requestPath, "--source_bundle", portablePath, "--json", ], }); expect(inline.exitCode).not.toBe(0); expect(portable.exitCode).toBe(inline.exitCode); const wrongRoleError = { code: "invalid_request", details: { issues: [expect.objectContaining({ path: ["left"] })], }, }; expect(inline.json).toMatchObject(wrongRoleError); expect(portable.json).toMatchObject(wrongRoleError); const corruptRequest = { left: badCoordinate, right, detail: "complete" }; await writeFile(requestPath, JSON.stringify(corruptRequest)); const corruptInline = await cli.run({ arguments: ["match-native-functions", requestPath, "--json"], }); const corruptPortableRequest = { left: { kind: "retained-evidence", evidence_id: badCoordinate.evidence_id, }, right: { kind: "retained-evidence", evidence_id: right.evidence_id }, detail: "complete", }; await writeFile(requestPath, JSON.stringify(corruptPortableRequest)); const corruptPortable = await cli.run({ arguments: [ "match-native-functions", requestPath, "--source_bundle", corruptBundlePath, "--json", ], }); expect(corruptInline.json).toMatchObject({ code: "evidence_integrity_mismatch", }); expect(corruptPortable.json).toMatchObject({ code: "evidence_integrity_mismatch", }); const malformedBundlePath = join(root, "malformed-outer-frame.json"); await writeFile(malformedBundlePath, JSON.stringify({ records: [left] })); const malformedBundle = await cli.run({ arguments: [ "match-native-functions", requestPath, "--source_bundle", malformedBundlePath, "--json", ], }); expect(malformedBundle.exitCode).not.toBe(0); expect(malformedBundle.json).toMatchObject({ code: "evidence_integrity_mismatch", }); }, 60000, ); cliTest( "native matching admits the request representation before authenticating observation carriers", async () => { const { call } = await connectLocalToolsMcp(); const left = nativeMatchingInventory("1", [ { address: "0x10", value: "main" }, ]); const right = nativeMatchingInventory("2", [ { address: "0x20", value: "main" }, ]); const before = await call("get_evidence_bundle", {}); const observations = Array.from({ length: 524288 }, () => ({})); const response = await call("match_native_functions", { left, right, left_observations: observations, detail: "complete", }); expect(parseMcpToolError(response).error).toMatchObject({ code: "resource_constraint", details: { operation: "match_native_functions", resource: "capacity", }, }); expect((await call("get_evidence_bundle", {})).structuredContent).toEqual( before.structuredContent, ); }, 60000, );