Files
reverse-engineering-anything/tests/boundary/mcp/processCaptureCleanupSchema.test.ts
T
672e214963 fix(process)!: retain observed cleanup intervention (#10481)
* fix(process)!: retain observed cleanup intervention

Process capture derived `settlement.cleanup_outcome` from the settlement
state alone in three places, so a quiesced capture reported
`not_required` even after final owned-process cleanup SIGKILLed a live
token-owned descendant. `cleanupOwnedProcessGroup` already knew it had
signaled, but the capture lifecycle discarded that fact.

Carry the observed signal out of ownership cleanup (also on failure
paths), accumulate it across cleanup retries as true/false/unknown, and
derive settlement and the intervention residual unknown once in
`processCaptureCleanupFacts` for full, partial and harness results.

BREAKING CHANGE: a quiesced settlement may now report
`cleanup_outcome: "cleaned"`. Saved captures stay valid; readers that
accepted only `not_required` for quiesced settlements must accept
`cleaned`.

Fixes #8032

Squashed from #8043 and rebased onto main (adapted to the resource-scope
release API and the inspection-failure cleanup path).

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(process): keep a sent signal when cleanup throws an inspection failure

Final ownership verification can rethrow a typed inspection failure (for
example cancellation) after SIGKILL succeeded. The capture owner then
recorded the attempt as unknown and dropped the intervention fact.

cleanupOwnedProcessGroup now marks a failure it throws after signaling,
without changing the failure's identity, and the capture owner keeps
the signal for such failures.

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: wunianze666-netizen <wunianze666@gmail.com>
Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 08:48:13 +01:00

79 lines
2.9 KiB
TypeScript

import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
import { afterAll, expect, it, onTestFinished } from "vitest";
import { createServer } from "../../../src/server/createServer.js";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
import { advertisedMcpToolSchemas } from "../../fixtures/advertisedMcpTool.js";
import { createMcpSchemaValidation } from "../../fixtures/mcpSchemaValidation.js";
import { emptyProcessCapture } from "../../../src/domain/process/processCapture.fixture.js";
import { parseProcessCapture } from "../../../src/domain/process/processCaptureParsing.js";
import { createProcessCaptureEvidence } from "../../../src/application/process/ProcessEvidence.js";
import { processScenarioSchema } from "../../../src/domain/process/processScenario.js";
const validation = createMcpSchemaValidation();
afterAll(() => validation.clear());
it.each(["full", "compact"] as const)(
"advertises quiesced cleanup intervention without rejecting saved captures (%s)",
async (profile) => {
const session = createTestBinarySession(() => {
throw new Error("Schema discovery must not start a provider");
});
const server = createServer(
{ kind: "session", session },
{
environment: {
...process.env,
REA_MCP_INPUT_SCHEMA_PROFILE: profile,
REA_MCP_OUTPUT_SCHEMA_PROFILE: "full",
},
},
);
const client = new Client(
{ name: "capture-cleanup-schema", version: "1" },
{ jsonSchemaValidator: validation },
);
onTestFinished(async () => {
await client.close();
await server.close();
await session.close();
});
const [clientTransport, serverTransport] =
InMemoryTransport.createLinkedPair();
await server.connect(serverTransport);
await client.connect(clientTransport);
const schemas = await advertisedMcpToolSchemas(
client,
"capture_process_scenario",
validation.assertions,
);
const saved = emptyProcessCapture();
const scenario = processScenarioSchema.parse({
executable: "fixture-program",
});
const intervened = parseProcessCapture({
...saved,
settlement: { ...saved.settlement, cleanup_outcome: "cleaned" },
residual_unknowns: [
{ scope: "process", reason: "Fixture cleanup intervention" },
],
});
for (const capture of [saved, intervened]) {
const evidence = createProcessCaptureEvidence(scenario, capture);
expect(
schemas.ajv.validate(schemas.outputSchema, evidence),
JSON.stringify(schemas.ajv.errors),
).toBe(true);
}
const evidence = createProcessCaptureEvidence(scenario, intervened);
expect(
schemas.ajv.validate(schemas.outputSchema, {
...evidence,
normalized_result: {
...intervened,
settlement: { ...intervened.settlement, cleanup_outcome: "invented" },
},
}),
).toBe(false);
},
);