fix(mcp): return complete inline Evidence records (#585)

Return complete canonical Evidence records inline, including normalized_result, and preserve direct comparison and retained bundle identity.

Verified full deterministic gate, real Linux Ghidra CLI/MCP and independently installed artifact, generic package acceptance, private local samples, and targeted updates after syncing main.

Closes #551

Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
This commit is contained in:
N0zoM1z0
2026-10-06 00:10:31 +08:00
committed by GitHub
parent 205a977777
commit ea9c3dab6b
12 changed files with 253 additions and 31 deletions
+70 -6
View File
@@ -9,7 +9,7 @@ import { parseEvidence } from "../../dist/domain/evidence.js";
import { analysisProfileSchema } from "../../dist/domain/analysisProfile.js";
import { nativeValueTraceSchema } from "../../dist/domain/nativeValueTrace.js";
const entrypoint = fileURLToPath(new URL("../rea.mjs", import.meta.url));
const defaultEntrypoint = fileURLToPath(new URL("../rea.mjs", import.meta.url));
const environment = () => ({
PATH: process.env.PATH ?? "/usr/bin:/bin",
REA_LOG_LEVEL: "silent",
@@ -67,7 +67,12 @@ const verifyGraph = (input, target, procedure, globalAddress) => {
};
/** Verify real Ghidra dependency composition through production CLI and stdio MCP. */
export async function verifyNativeValueE2e(target, procedure, globalAddress) {
export async function verifyNativeValueE2e(
target,
procedure,
globalAddress,
{ entrypoint = defaultEntrypoint } = {},
) {
const { stdout } = await promisify(execFile)(
process.execPath,
[
@@ -142,10 +147,7 @@ export async function verifyNativeValueE2e(target, procedure, globalAddress) {
{ timeout: 180000 },
);
assert.notEqual(result.isError, true, JSON.stringify(result));
const mcpEvidence = parseEvidence({
...result.structuredContent?.evidence,
normalized_result: result.structuredContent?.result,
});
const mcpEvidence = parseEvidence(result.structuredContent?.evidence);
assert.equal(mcpEvidence.operation, "trace_native_values");
assert.equal(mcpEvidence.provider.id, "rea-workflow");
assert.deepEqual(mcpEvidence.analysis_profile, workflowProfile);
@@ -157,6 +159,66 @@ export async function verifyNativeValueE2e(target, procedure, globalAddress) {
);
assert.deepEqual(mcpEvidence.normalized_result, mcpGraph);
assert.deepEqual(mcpGraph, cliGraph);
const analyzed = await client.callTool(
{ name: "analyze_function", arguments: { procedure } },
{ timeout: 180000 },
);
assert.notEqual(analyzed.isError, true, JSON.stringify(analyzed));
const functionEvidence = parseEvidence(
analyzed.structuredContent?.evidence,
);
assert.equal(functionEvidence.operation, "analyze_function");
assert.equal(functionEvidence.provider.id, "rea-workflow");
const functionProfile = analysisProfileSchema.parse(
functionEvidence.analysis_profile,
);
assert.deepEqual(
functionProfile.parameters.upstream_analysis_profile,
upstreamProfile,
);
assert.deepEqual(
functionEvidence.normalized_result,
analyzed.structuredContent?.result,
);
const comparison = await client.callTool(
{
name: "compare_functions",
arguments: {
left: analyzed.structuredContent.evidence,
right: analyzed.structuredContent.evidence,
},
},
{ timeout: 180000 },
);
assert.notEqual(comparison.isError, true, JSON.stringify(comparison));
const comparisonEvidence = parseEvidence(
comparison.structuredContent?.evidence,
);
assert.equal(comparisonEvidence.normalized_result.status, "unchanged");
assert.deepEqual(
comparisonEvidence.normalized_result,
comparison.structuredContent?.result,
);
assert.ok(
comparisonEvidence.evidence_links.includes(functionEvidence.evidence_id),
);
const bundle = await client.callTool({
name: "get_evidence_bundle",
arguments: {},
});
assert.notEqual(bundle.isError, true, JSON.stringify(bundle));
for (const evidence of [
mcpEvidence,
functionEvidence,
comparisonEvidence,
]) {
assert.deepEqual(
bundle.structuredContent?.result?.records.find(
(record) => record.evidence_id === evidence.evidence_id,
),
evidence,
);
}
const closed = await client.callTool({
name: "close_binary",
arguments: {},
@@ -175,6 +237,8 @@ export async function verifyNativeValueE2e(target, procedure, globalAddress) {
mocked: false,
cli: true,
stdio_mcp: true,
inline_evidence: true,
direct_function_comparison: true,
nodes: cliGraph.total_nodes,
edges: cliGraph.total_edges,
decompilations: cliGraph.decompilations,
+74 -2
View File
@@ -1,3 +1,4 @@
import assert from "node:assert/strict";
import { join } from "node:path";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
@@ -5,6 +6,7 @@ import { promisify } from "node:util";
import { Client } from "@modelcontextprotocol/client";
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
import { MCP_STARTUP_POLICY } from "../dist/mcpStartupPolicy.js";
import { parseEvidence } from "../dist/domain/evidence.js";
import * as prompts from "./verify-package-prompts.mjs";
import { json, verifyCompleteToolCatalog } from "./lib/verify-package-core.mjs";
@@ -155,8 +157,77 @@ const verifyMcpEvidenceBundle = async (client, mcpOptions, evidenceRoot) => {
throw new Error("packaged MCP evidence import failed");
};
/** Connect to the packaged MCP server and exercise the target-free catalog. */
export async function verifyPackageMcp({ cli, environment, evidenceRoot }) {
const verifyMcpInlineArtifactEvidence = async (
client,
mcpOptions,
artifactArchive,
) => {
const opened = await client.callTool(
{ name: "open_binary", arguments: { path: artifactArchive } },
mcpOptions,
);
assert.notEqual(opened.isError, true, JSON.stringify(opened));
try {
const inspected = await client.callTool(
{ name: "inspect_artifact", arguments: {} },
mcpOptions,
);
assert.notEqual(inspected.isError, true, JSON.stringify(inspected));
const source = parseEvidence(inspected.structuredContent?.evidence);
assert.deepEqual(
source.normalized_result,
inspected.structuredContent?.result,
);
assert.deepEqual(
json(prompts.mcpText(inspected)),
inspected.structuredContent,
);
const compared = await client.callTool(
{
name: "compare_artifacts",
arguments: {
left: inspected.structuredContent.evidence,
right: inspected.structuredContent.evidence,
},
},
mcpOptions,
);
assert.notEqual(compared.isError, true, JSON.stringify(compared));
const comparison = parseEvidence(compared.structuredContent?.evidence);
assert.deepEqual(
comparison.normalized_result,
compared.structuredContent?.result,
);
assert.ok(comparison.evidence_links.includes(source.evidence_id));
const bundle = await client.callTool(
{ name: "get_evidence_bundle", arguments: {} },
mcpOptions,
);
assert.notEqual(bundle.isError, true, JSON.stringify(bundle));
for (const evidence of [source, comparison]) {
assert.deepEqual(
bundle.structuredContent?.result?.records.find(
(record) => record.evidence_id === evidence.evidence_id,
),
evidence,
);
}
} finally {
const closed = await client.callTool(
{ name: "close_binary", arguments: {} },
mcpOptions,
);
assert.notEqual(closed.isError, true, JSON.stringify(closed));
}
};
/** Connect to the packaged MCP server and verify catalog and Evidence composition. */
export async function verifyPackageMcp({
cli,
environment,
evidenceRoot,
artifactArchive,
}) {
const diagnosed = json(
(
await execute(cli, ["mcp", "doctor", "--json"], {
@@ -191,6 +262,7 @@ export async function verifyPackageMcp({ cli, environment, evidenceRoot }) {
await verifyMcpTargetFree(client, mcpOptions);
await verifyMcpUnknownProvider(client, mcpOptions);
await verifyMcpBinaryLifecycle(client, mcpOptions);
await verifyMcpInlineArtifactEvidence(client, mcpOptions, artifactArchive);
await verifyMcpEvidenceBundle(client, mcpOptions, evidenceRoot);
} catch (cause) {
throw new Error(`packaged MCP smoke failed: ${mcpStderr}`, { cause });
+2 -1
View File
@@ -84,7 +84,7 @@ try {
cli,
environment: environmentData.environment,
});
await verifyPackageArtifactAndElectron({
const { artifactArchive } = await verifyPackageArtifactAndElectron({
cli,
workspace,
environment: environmentData.environment,
@@ -131,6 +131,7 @@ try {
cli,
environment: environmentData.environment,
evidenceRoot,
artifactArchive,
});
process.stdout.write(
`${JSON.stringify({ verifier_run: await completeVerifierRun(verifierRun), cli: true, analysisCli: true, artifactCli: true, managedCli: true, managedReconstructionCli: true, managedNativeVerificationCli: true, managedApplicationGraphCli: true, evidenceCli: true, incurMcpCommand: PRODUCT_IDENTITY.mcpCommand, lifecycleScriptsRequired: false, doctor: "platform-appropriate", setup: supportedSetupHost ? "planned-then-idempotent" : "unsupported-host-rejected", setupPlanReadOnly: supportedSetupHost, existingHopperPreserved: supportedSetupHost, clients: supportedSetupHost ? 4 : 0, backupReadback: supportedSetupHost, failureRecovery: supportedSetupHost, configSymlinkLifecycle: supportedSetupHost, skill: supportedSetupHost, skillReferences: supportedSetupHost, mcpTools: TOOL_CONTRACTS.length, mcpPrompts: prompts.names.length, promptCompletion: true, promptCompletionLifecycle: true, evidenceMcp: true, targetFree: true, targetLifecycle: true, boundedRegexBridge: true, update, mcpStartup, mcpModuleLoading })}\n`,