Files
reverse-engineering-anything/tests/boundary/mcp/batchSourcePublicationRecovery.test.ts
T
morlutoandCursor Agent 88cf498036 fix!: preserve results when source publication fails (#8444)
* fix: retain address context cleanup failures

* fix!: preserve address context input errors

BREAKING CHANGE: Strict clients that cached the previous full inspect_address_context output schema must refresh tools/list and accept the typed error field on unavailable facets.

* test: use session contract for address context

* fix!: preserve address context resource recovery

BREAKING CHANGE: Clients validating unavailable context facets against a cached strict full output schema must refresh tools/list to accept resource_constraint errors.

* fix: expose authenticated records refused by the evidence ledger (#8426)

* fix: preserve completed evidence on retention refusal

* fix: preserve context when unretained evidence exceeds delivery limits

* fix(mcp): recover oversized context from session evidence

* fix(evidence): preserve completed atomic write results

* fix: retain completed results when source publication fails

* test: cover bounded recovery with unknown retention

* fix(evidence): preserve recovery identity and finalization facts

* fix(evidence): clarify retention of omitted observations

* test(evidence): compare omission guidance with its owner

* fix(evidence): preserve completed composed workflows

* fix(evidence): clarify unretained recovery export

* test(evidence): cover mixed recovery guidance

* fix(evidence): preserve caller scope in secondary failures

* refactor(evidence): remove superseded cleanup projection

* test(evidence): align recovery checks with owners

* fix: preserve cleanup on partial recovery limits

* test: use owners for diagnostic wording

* fix: admit completed analysis before evidence construction

* fix: preserve selected paths when reusing evidence

* fix(cli): preserve caller path in unretained evidence

* fix(evidence): preserve recovery metadata and admission bounds

* refactor: consolidate evidence closure imports

* style(test): format CLI help default annotations (#9280)

* test(mcp): keep recovery checks focused on contract facts

* fix(evidence): preserve feature trace replay revision

* test: align evidence recovery checks with ownership

* test: align partial recovery and cleanup diagnostics

* fix(evidence): preserve nested partials during cleanup

* fix(evidence): respect outer recovery ownership

* fix(capture): discard rejected nested observations

* test(frida): assert inline evidence recovery

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-11-09 02:41:54 +08:00

135 lines
4.9 KiB
TypeScript

import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
import pino from "pino";
import { expect, it, onTestFinished } from "vitest";
import {
createAnalysisExecution,
type AnalysisOperationPort,
} from "../../../src/application/AnalysisProvider.js";
import { EvidenceLedger } from "../../../src/application/investigation/EvidenceLedger.js";
import { createEvidence } from "../../../src/domain/evidence.js";
import { AnalysisResourceConstraintError } from "../../../src/domain/analysisErrorCore.js";
import { err, ok } from "../../../src/domain/result.js";
import { EvidenceMcpServer } from "../../../src/server/EvidenceMcpServer.js";
import { registerEnhancedTools } from "../../../src/server/registerEnhancedTools.js";
import { withAdmittedAnalysis } from "../../../src/server/analysisAdmission.js";
import { createToolResultDelivery } from "../../../src/server/toolResult.js";
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
const provider = { id: "fixture", name: "Fixture", version: "1" };
const source = createEvidence(undefined, provider, {
operation: "health",
parameters: {},
result: "source",
});
it.each([
{ size: 100, denyAdmission: false, ownerKnown: true },
{ size: 100_000, denyAdmission: false, ownerKnown: true },
{ size: 100, denyAdmission: true, ownerKnown: true },
{ size: 100, denyAdmission: false, ownerKnown: false },
])(
"preserves capacity error with size $size, denied admission $denyAdmission, and known owner $ownerKnown",
async ({ size, denyAdmission, ownerKnown }) => {
const ledger = new EvidenceLedger({ maximumRepresentationBytes: 0 });
const record = (evidence: typeof source) => ledger.record(evidence);
const analysis: AnalysisOperationPort = {
execute: async (operation) => {
return ok(
createAnalysisExecution(
operation === "procedure_address"
? "0x1000"
: operation === "address_name"
? "example"
: "x".repeat(size),
provider,
operation === "procedure_pseudo_code"
? { sourceEvidence: [source] }
: {},
),
);
},
};
const server = new EvidenceMcpServer(
{ name: "batch-overflow", version: "1" },
{},
record,
createToolResultDelivery(10 * 1024),
);
registerEnhancedTools(server, {
withAdmittedAnalysis: withAdmittedAnalysis({ kind: "fixed", analysis }),
logger: pino({ enabled: false }),
activeTarget: () => undefined,
analysisProfile: undefined,
recordEvidence: record,
...(ownerKnown
? { evidenceForAnalysis: (id: string) => ledger.forAnalysis(id) }
: {}),
...(denyAdmission
? {
admitRecovery: () =>
err(
new AnalysisResourceConstraintError(
"batch_decompile",
"memory",
"no headroom",
null,
),
),
}
: {}),
evidenceById: ownerKnown ? (id) => ledger.forAnalysis(id) : () => source,
recordUnknown: undefined,
allowsSnapshotReplay: undefined,
recordWorkflowSnapshot: undefined,
});
const client = new Client({ name: "batch-overflow-test", version: "1" });
onTestFinished(async () => {
await client.close();
await server.close();
});
const [ct, st] = InMemoryTransport.createLinkedPair();
await server.connect(st);
await client.connect(ct);
const response = await client.callTool({
name: "batch_decompile",
arguments: { addresses: ["example"] },
});
expect(response.isError).toBe(true);
const error = parseMcpToolError(response).error;
expect(error).toMatchObject({
code: "resource_constraint",
details: { partial_observation: { kind: "unretained-evidence" } },
});
if (denyAdmission)
expect(error.details).toMatchObject({
completed_observation_omitted: {
reason: "insufficient-authentication-headroom",
source_closure: "not-established",
},
});
else if (!ownerKnown)
expect(error.details).toMatchObject({
completed_observation: {
kind: "inline-evidence",
retention: "unknown",
source_closure: "not-established",
evidence: { operation: "batch_decompile" },
},
});
else if (size === 100)
expect(error.details).toMatchObject({
completed_observation: {
kind: "unretained-evidence",
source_closure: "not-established",
evidence: { operation: "batch_decompile" },
},
});
else
expect(error.details).toMatchObject({
completed_observation_omitted: {
reason: "mcp-response-limit",
source_closure: "not-established",
},
});
expect(ledger.statistics().evidenceRecords).toBe(0);
},
);