test(mcp): verify retained Interface Builder limits

Verify retained hierarchy limits and summary identity through the production artifact-only composition and real MCP SDK, alongside compiled CLI controls. Deep-provider selection is a separate lane.

Co-authored-by: Aliciawque <166712943+Aliciawque@users.noreply.github.com>
This commit is contained in:
morluto
2026-10-14 15:20:09 +08:00
parent 7777abf473
commit 11d38cbc00
3 changed files with 66 additions and 3 deletions
@@ -2,13 +2,50 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { build } from "plist";
import { expect } from "vitest";
import { expect, onTestFinished } from "vitest";
import { interfaceBuilderAnalysisSchema } from "../../../src/domain/apple/interfaceBuilderGraph.js";
import { thinMach } from "../../../src/domain/binaryTarget.fixture.js";
import { parseEvidence } from "../../../src/domain/evidence.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
import { createTestMcp } from "../../support/mcp/mcpFixture.js";
import { openArtifactTarget } from "../../support/mcp/artifactSession.js";
const verifyMcpParity = async (
app: string,
expected: ReturnType<typeof interfaceBuilderAnalysisSchema.parse>,
): Promise<void> => {
const mcp = createTestMcp();
onTestFinished(async () => mcp.close());
const client = await openArtifactTarget(mcp, onTestFinished, app);
const complete = await client.callTool({
name: "decode_interface_builder",
arguments: { max_objects: 2 },
});
expect(complete.isError, JSON.stringify(complete)).not.toBe(true);
const evidence = parseEvidence(complete.structuredContent);
expect(
interfaceBuilderAnalysisSchema.parse(evidence.normalized_result),
).toEqual(expected);
const summarized = await client.callTool({
name: "decode_interface_builder",
arguments: { max_objects: 2, detail: "summary" },
});
expect(summarized.isError, JSON.stringify(summarized)).not.toBe(true);
expect(
parseEvidence(summarized.structuredContent).normalized_result,
).toMatchObject({
kind: "summary",
parent_evidence_id: evidence.evidence_id,
summary: {
documents: expected.documents,
truncated: true,
coverage_statuses: { partial: expect.any(Number) },
},
});
};
const archive = (objects: readonly string[], hierarchy: readonly string[]) =>
build({
@@ -82,6 +119,7 @@ cliTest.for(cases)(
const report = interfaceBuilderAnalysisSchema.parse(
evidence.normalized_result,
);
await verifyMcpParity(app, report);
expect(
report.documents.map(({ hierarchy_complete }) => hierarchy_complete),
).toEqual(hierarchyComplete);
@@ -9,7 +9,7 @@ import { thinMach } from "../../../src/domain/binaryTarget.fixture.js";
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { mcpTest } from "../../support/mcp/mcpFixture.js";
import { openProductionTarget } from "../../support/mcp/productionSession.js";
import { openArtifactTarget } from "../../support/mcp/artifactSession.js";
const evidenceOf = <Schema extends z.ZodType>(schema: Schema) =>
z.object({
@@ -65,7 +65,7 @@ mcpTest(
"retains complete Interface Builder Evidence and pages one document's rows",
async ({ mcp, onTestFinished }) => {
const app = await fixtureApp();
const client = await openProductionTarget(mcp, onTestFinished, app);
const client = await openArtifactTarget(mcp, onTestFinished, app);
// Summary first: its own retained parent must serve every later page.
const summarized = await client.callTool({
+25
View File
@@ -0,0 +1,25 @@
import type { Client } from "@modelcontextprotocol/client";
import { expect, type OnTestFinishedHandler } from "vitest";
import { createArtifactBinarySession } from "../../../src/composition/binary.js";
import { createServer } from "../../../src/server/createServer.js";
import type { TestMcp } from "./mcpFixture.js";
/** Open a static artifact target in the production artifact-only MCP composition. */
export const openArtifactTarget = async (
mcp: TestMcp,
onTestFinished: (handler: OnTestFinishedHandler) => void,
path: string,
): Promise<Client> => {
const session = await createArtifactBinarySession(process.env);
onTestFinished(async () => {
await session.close();
});
const client = await mcp.connect(createServer({ kind: "session", session }));
const opened = await client.callTool({
name: "open_binary",
arguments: { path },
});
expect(opened.isError, JSON.stringify(opened.content)).not.toBe(true);
return client;
};