blob: 3da0f75b52fe1f439833bff1cde1b01dbf9094aa [file]
import assert from 'node:assert/strict';
import { test } from 'node:test';
import { mcpProxyToolName } from '@maka/runtime/mcp-tools';
import { type ClientCapabilityProvider, RuntimeHostOperationError } from '../client/index.js';
import {
connectClient,
requireStartedTurn,
waitForTerminalTurn,
withExecutionRoot,
} from './fixtures/execution-host-suite.js';
test('two Clients idempotently start one Host-owned safe-boundary continuation', async () => {
await withExecutionRoot(async (fixture) => {
const source = await fixture.seedSafeBoundaryContinuationSource();
const host = await fixture.startHost();
const first = await connectClient(fixture.root, 'desktop');
const second = await connectClient(fixture.root, 'tui');
const turnId = 'turn-safe-boundary-continuation';
let clientsClosed = false;
let hostStopped = false;
try {
const plan = await first.queryTurnResume({ sessionId: fixture.sessionId });
assert.deepEqual(plan, {
sessionId: fixture.sessionId,
disposition: 'ready',
sourceRunId: source.sourceRunId,
sourceTurnId: source.sourceTurnId,
sourceRuntimeEventHighWater: source.sourceRuntimeEventHighWater,
});
const input = {
sessionId: fixture.sessionId,
turnId,
sourceRunId: source.sourceRunId,
sourceRuntimeEventHighWater: source.sourceRuntimeEventHighWater,
};
const [firstStart, secondStart] = await Promise.all([
first.startTurnResume(input),
second.startTurnResume(input),
]);
assert.equal(firstStart.kind, 'started');
assert.equal(secondStart.kind, 'started');
if (firstStart.kind !== 'started' || secondStart.kind !== 'started') return;
assert.equal(firstStart.turn.runId, secondStart.turn.runId);
const terminal = await waitForTerminalTurn(first, fixture.sessionId, turnId);
assert.equal(terminal.status, 'completed');
const retry = await second.startTurnResume(input);
assert.deepEqual(retry, { kind: 'started', turn: terminal });
const settledPlan = await first.queryTurnResume({ sessionId: fixture.sessionId });
assert.deepEqual(settledPlan, {
sessionId: fixture.sessionId,
disposition: 'parked',
reason: 'continuation_already_exists',
});
await first.close();
await second.close();
clientsClosed = true;
await fixture.stopHost(host);
hostStopped = true;
const footprint = await fixture.readTurnFootprint(turnId);
assert.deepEqual(footprint, {
admitted: true,
runCount: 1,
userMessageCount: 0,
});
const admission = (await fixture.readAdmissionChain()).find(
(candidate) => candidate.turnId === turnId,
);
assert.equal(admission?.userMessageId, null);
assert.equal(admission?.execution.kind, 'safe_boundary_continuation');
if (admission?.execution.kind !== 'safe_boundary_continuation') return;
assert.equal(admission.execution.sourceRunId, source.sourceRunId);
assert.equal(admission.execution.sourceInvocationId, source.sourceInvocationId);
assert.equal(admission.execution.sourceRuntimeEventHighWater, 2);
const ledger = await fixture.readTurn(turnId);
assert.equal(ledger.runs.length, 1);
const run = ledger.runs[0];
assert.equal(run?.parentRunId, source.sourceRunId);
assert.equal(run?.parentTurnId, source.sourceTurnId);
assert.equal(run?.invocationId, admission.execution.targetInvocationId);
assert.equal(run?.continuationSource?.sourceRunId, source.sourceRunId);
assert.equal(
run?.continuationSource && 'protocol' in run.continuationSource
? run.continuationSource.claimId
: undefined,
admission.execution.claimId,
);
} finally {
if (!clientsClosed) {
await first.close();
await second.close();
}
if (!hostStopped) await fixture.stopHost(host);
}
});
});
test('startup repairs a continuation Run created before its durable start', async () => {
await withExecutionRoot(async (fixture) => {
const crash = await fixture.seedSafeBoundaryContinuationCrash('after_run_created');
const host = await fixture.startHost();
const client = await connectClient(fixture.root, 'desktop');
try {
const repaired = await client.queryTurn({
sessionId: fixture.sessionId,
turnId: crash.targetTurnId,
});
assert.equal(repaired.runId, crash.targetRunId);
assert.equal(repaired.status, 'failed');
assert.equal(repaired.failureClass, 'continuation_abandoned_before_provider_dispatch');
assert.deepEqual(
await client.queryTurnResume({
sessionId: fixture.sessionId,
sourceRunId: crash.sourceRunId,
expectedRuntimeEventHighWater: crash.sourceRuntimeEventHighWater,
}),
{
sessionId: fixture.sessionId,
disposition: 'parked',
reason: 'continuation_already_exists',
},
);
} finally {
await client.close();
await fixture.stopHost(host);
}
});
});
test('startup repairs a continuation claim committed before its target Run', async () => {
await withExecutionRoot(async (fixture) => {
const crash = await fixture.seedSafeBoundaryContinuationCrash(
'after_continuation_claim_committed',
);
const host = await fixture.startHost();
const client = await connectClient(fixture.root, 'desktop');
let clientClosed = false;
let hostStopped = false;
try {
const repaired = await client.queryTurn({
sessionId: fixture.sessionId,
turnId: crash.targetTurnId,
});
assert.equal(repaired.runId, crash.targetRunId);
assert.equal(repaired.status, 'failed');
assert.equal(repaired.failureClass, 'continuation_abandoned_before_provider_dispatch');
await client.close();
clientClosed = true;
await fixture.stopHost(host);
hostStopped = true;
const ledger = await fixture.readTurn(crash.targetTurnId);
assert.equal(ledger.runs.length, 1);
assert.equal(ledger.userMessages.length, 0);
} finally {
if (!clientClosed) await client.close();
if (!hostStopped) await fixture.stopHost(host);
}
});
});
test('startup parks a provider-indeterminate continuation without blocking the Host', async () => {
await withExecutionRoot(async (fixture) => {
const siblingSessionId = await fixture.seedSession();
const crash = await fixture.seedSafeBoundaryContinuationCrash(
'after_continuation_start_committed',
);
const host = await fixture.startHost();
const client = await connectClient(fixture.root, 'desktop');
try {
const indeterminate = await client.queryTurn({
sessionId: fixture.sessionId,
turnId: crash.targetTurnId,
});
assert.equal(indeterminate.runId, crash.targetRunId);
assert.equal(indeterminate.status === 'created' || indeterminate.status === 'running', true);
const plan = {
sessionId: fixture.sessionId,
disposition: 'parked' as const,
reason: 'continuation_started_indeterminate' as const,
};
assert.deepEqual(
await client.queryTurnResume({
sessionId: fixture.sessionId,
sourceRunId: crash.sourceRunId,
expectedRuntimeEventHighWater: crash.sourceRuntimeEventHighWater,
}),
plan,
);
assert.deepEqual(
await client.startTurnResume({
sessionId: fixture.sessionId,
turnId: crash.targetTurnId,
sourceRunId: crash.sourceRunId,
sourceRuntimeEventHighWater: crash.sourceRuntimeEventHighWater,
}),
{ kind: 'parked', plan },
);
await assert.rejects(
() =>
client.stopTurn({
sessionId: fixture.sessionId,
turnId: crash.targetTurnId,
runId: crash.targetRunId,
}),
(error) =>
error instanceof RuntimeHostOperationError && error.code === 'operation_conflict',
);
assert.deepEqual(
await client.queryTurnResume({
sessionId: fixture.sessionId,
sourceRunId: 'different-continuation-source',
expectedRuntimeEventHighWater: crash.sourceRuntimeEventHighWater,
}),
{
sessionId: fixture.sessionId,
disposition: 'parked',
reason: 'session_busy',
},
);
await assert.rejects(
() =>
client.startTurn({
sessionId: fixture.sessionId,
turnId: 'turn-after-indeterminate-continuation',
content: { text: 'Do not overtake the parked continuation.' },
}),
(error) => error instanceof RuntimeHostOperationError && error.code === 'session_busy',
);
const sibling = requireStartedTurn(
await client.startTurn({
sessionId: siblingSessionId,
turnId: 'turn-unrelated-to-indeterminate-continuation',
content: { text: 'Continue normally.' },
}),
);
assert.equal(sibling.sessionId, siblingSessionId);
} finally {
await client.close();
await fixture.stopHost(host);
}
});
});
test('startup parks a provider-indeterminate continuation when resume is disabled', async () => {
await withExecutionRoot(async (fixture) => {
const siblingSessionId = await fixture.seedSession();
const crash = await fixture.seedSafeBoundaryContinuationCrash(
'after_continuation_start_committed',
);
const host = await fixture.startHost(undefined, false);
const client = await connectClient(fixture.root, 'desktop');
try {
const indeterminate = await client.queryTurn({
sessionId: fixture.sessionId,
turnId: crash.targetTurnId,
});
assert.equal(indeterminate.runId, crash.targetRunId);
assert.equal(indeterminate.status === 'created' || indeterminate.status === 'running', true);
assert.deepEqual(
await client.queryTurnResume({
sessionId: fixture.sessionId,
sourceRunId: crash.sourceRunId,
expectedRuntimeEventHighWater: crash.sourceRuntimeEventHighWater,
}),
{
sessionId: fixture.sessionId,
disposition: 'parked',
reason: 'continuation_unavailable',
},
);
const sibling = requireStartedTurn(
await client.startTurn({
sessionId: siblingSessionId,
turnId: 'turn-unrelated-to-disabled-indeterminate-continuation',
content: { text: 'Continue normally.' },
}),
);
assert.equal(sibling.sessionId, siblingSessionId);
} finally {
await client.close();
await fixture.stopHost(host);
}
});
});
test('startup parks a pre-claim continuation whose Client Capability is absent', async () => {
await withExecutionRoot(async (fixture) => {
const requiredToolName = mcpProxyToolName('resume_fixture', 'inspect');
const pending = await fixture.seedPendingSafeBoundaryContinuation(requiredToolName);
const host = await fixture.startHost();
const client = await connectClient(fixture.root, 'desktop');
try {
assert.deepEqual(
await client.queryTurnResume({
sessionId: fixture.sessionId,
sourceRunId: pending.sourceRunId,
expectedRuntimeEventHighWater: pending.sourceRuntimeEventHighWater,
}),
{
sessionId: fixture.sessionId,
disposition: 'parked',
reason: 'safety_check_failed',
},
);
await assert.rejects(
() =>
client.startTurn({
sessionId: fixture.sessionId,
turnId: 'turn-overtaking-client-capability-continuation',
content: { text: 'Do not overtake the pending continuation.' },
}),
(error) => error instanceof RuntimeHostOperationError && error.code === 'session_busy',
);
assert.deepEqual(
await client.queryTurn({
sessionId: fixture.sessionId,
turnId: pending.targetTurnId,
}),
{
sessionId: fixture.sessionId,
turnId: pending.targetTurnId,
runId: pending.targetRunId,
status: 'admitted',
},
);
await assert.rejects(
() =>
client.stopTurn({
sessionId: fixture.sessionId,
turnId: pending.targetTurnId,
runId: pending.targetRunId,
}),
(error) =>
error instanceof RuntimeHostOperationError && error.code === 'operation_conflict',
);
assert.deepEqual(
await client.queryTurnResume({
sessionId: fixture.sessionId,
sourceRunId: pending.sourceRunId,
expectedRuntimeEventHighWater: pending.sourceRuntimeEventHighWater,
}),
{
sessionId: fixture.sessionId,
disposition: 'parked',
reason: 'safety_check_failed',
},
);
} finally {
await client.close();
await fixture.stopHost(host);
}
});
});
test('Runtime Host keeps safe-boundary continuation opt-in', async () => {
await withExecutionRoot(async (fixture) => {
const source = await fixture.seedSafeBoundaryContinuationSource();
const targetTurnId = 'turn-disabled-safe-boundary-continuation';
const host = await fixture.startHost(undefined, false);
const client = await connectClient(fixture.root, 'desktop');
let clientClosed = false;
let hostStopped = false;
try {
const plan = {
sessionId: fixture.sessionId,
disposition: 'parked' as const,
reason: 'continuation_unavailable' as const,
};
assert.deepEqual(
await client.queryTurnResume({
sessionId: fixture.sessionId,
sourceRunId: source.sourceRunId,
expectedRuntimeEventHighWater: source.sourceRuntimeEventHighWater,
}),
plan,
);
assert.deepEqual(
await client.startTurnResume({
sessionId: fixture.sessionId,
turnId: targetTurnId,
sourceRunId: source.sourceRunId,
sourceRuntimeEventHighWater: source.sourceRuntimeEventHighWater,
}),
{ kind: 'parked', plan },
);
await client.close();
clientClosed = true;
await fixture.stopHost(host);
hostStopped = true;
assert.deepEqual(await fixture.readTurnFootprint(targetTurnId), {
admitted: false,
runCount: 0,
userMessageCount: 0,
});
} finally {
if (!clientClosed) await client.close();
if (!hostStopped) await fixture.stopHost(host);
}
});
});
test('resume query previews the initiating Client Capability without binding it', async () => {
await withExecutionRoot(async (fixture) => {
const serverId = 'resume_fixture';
const toolName = 'inspect';
const requiredToolName = mcpProxyToolName(serverId, toolName);
const source = await fixture.seedSafeBoundaryContinuationSource(requiredToolName);
const host = await fixture.startHost();
const client = await connectClient(fixture.root, 'desktop');
const provider = resumeFixtureProvider(serverId, [toolName]);
try {
assert.deepEqual(await client.queryTurnResume({ sessionId: fixture.sessionId }), {
sessionId: fixture.sessionId,
disposition: 'parked',
reason: 'safety_check_failed',
});
await client.replaceClientCapabilities(provider);
assert.deepEqual(await client.queryTurnResume({ sessionId: fixture.sessionId }), {
sessionId: fixture.sessionId,
disposition: 'ready',
sourceRunId: source.sourceRunId,
sourceTurnId: source.sourceTurnId,
sourceRuntimeEventHighWater: source.sourceRuntimeEventHighWater,
});
} finally {
await client.close();
await fixture.stopHost(host);
}
});
});
function resumeFixtureProvider(
serverId: string,
toolNames: readonly string[],
): ClientCapabilityProvider {
return {
offers: () => [
{
offerId: 'resume_fixture',
version: '0',
affinity: 'session',
hostPathAccess: 'cwd',
label: 'Resume fixture',
tools: toolNames.map((name) => ({
serverId,
name,
inputSchema: { type: 'object', additionalProperties: false },
})),
},
],
call: async (_frame, { accept }) => {
await accept();
return { content: [{ type: 'text', text: 'ok' }] };
},
};
}