evOo-local/packages/adapters/src/approval-effect.test.ts
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

536 lines
19 KiB
TypeScript

import { approvalEffectKey } from "@rakazo/core/node/approval-effect-key";
import { describe, expect, it, vi } from "vitest";
import {
approvalPausedToolResult,
approvalReplayPathError,
approvalReplayResourceError,
approvedCatalogReplay,
approvedReplayArgs,
boundDirectApprovalRequest,
catalogApprovalConnectorId,
catalogApprovalDetails,
catalogApprovalMatchesLiveRoute,
catalogApprovalRequest,
catalogExecuteToolName,
catalogToolPrefix,
claimApprovedEffect,
claimIntendedEffect,
completeExternalEffect,
createApprovedEffectReplayQueue,
isApprovalPausedResult,
isToolPauseResult,
replaceCompletedExternalEffectResult,
resolveDuplicateEffectGate,
settleUncertainEffect,
} from "./approval-effect.js";
describe("approved effect replay", () => {
it("replays persisted arguments instead of a changed model reconstruction", () => {
const approved = { title: "Approved title", body: "Approved body" };
const queue = createApprovedEffectReplayQueue([
{ kind: "destination.write", request: approved },
]);
expect(queue.take("destination.write")).toEqual(approved);
expect(queue.take("destination.write")).toBeUndefined();
});
it("keeps independently approved calls in creation order", () => {
const queue = createApprovedEffectReplayQueue([
{ kind: "destination.write", request: { sequence: 1 } },
{ kind: "destination.write", request: { sequence: 2 } },
]);
expect(queue.assertDrained).toThrow();
expect(queue.take("destination.write")).toEqual({ sequence: 1 });
expect(queue.assertDrained).toThrow();
expect(queue.take("destination.write")).toEqual({ sequence: 2 });
expect(queue.assertDrained).not.toThrow();
});
it("does not consume a later tool before the next approved request", () => {
const queue = createApprovedEffectReplayQueue([
{ kind: "first.write", request: { sequence: 1 } },
{ kind: "second.write", request: { sequence: 2 } },
]);
expect(queue.nextToolName()).toBe("first.write");
expect(queue.take("second.write")).toBeUndefined();
expect(queue.nextToolName()).toBe("first.write");
expect(queue.take("first.write")).toEqual({ sequence: 1 });
expect(queue.nextToolName()).toBe("second.write");
});
it("does not treat a direct-tool arg named like the catalog marker as a catalog replay", () => {
const marker = "__rakazoCatalogTool";
const approved = {
id: "row-1",
arguments: { mode: "strict" },
text: "approved exactly",
[marker]: "looks-like-a-wrapper-but-is-an-arg",
};
const reconstructed = {
id: "row-1",
arguments: { mode: "model-changed" },
text: "model reconstructed",
[marker]: "looks-like-a-wrapper-but-is-an-arg",
};
expect(catalogApprovalDetails(approved, marker)).toBeUndefined();
const queue = createApprovedEffectReplayQueue([{ kind: "notes.write", request: approved }]);
expect(approvedCatalogReplay(queue, "notes.write", marker)).toEqual({});
expect(approvedReplayArgs(queue.take("notes.write")!, reconstructed, marker)).toEqual(approved);
expect(queue.assertDrained).not.toThrow();
});
it("still recognizes the full catalog envelope as a catalog replay", () => {
const marker = "__rakazoCatalogTool";
const approved = catalogApprovalRequest(
"installed_execute_tool",
{ id: "install-A:notes.write", arguments: { text: "approved" } },
marker,
);
expect(catalogApprovalDetails(approved, marker)).toEqual({
toolName: "installed_execute_tool",
args: { id: "install-A:notes.write", arguments: { text: "approved" } },
});
expect(approvedReplayArgs(approved, { text: "approved", mode: "fast" }, marker)).toEqual({
text: "approved",
mode: "fast",
});
});
it("does not inject catalog envelope args onto a non-wrapper tool call", () => {
const marker = "__rakazoCatalogTool";
const catalog = catalogApprovalRequest(
"installed_execute_tool",
{ id: "install-A:installed_execute_tool", arguments: { text: "approved" } },
marker,
);
const queue = createApprovedEffectReplayQueue([
{ kind: "installed_execute_tool", request: catalog },
]);
// Direct invocation must not receive the wrapper {id,arguments} envelope.
expect(approvedCatalogReplay(queue, "installed_execute_tool", marker, false)).toEqual({});
expect(approvedCatalogReplay(queue, "installed_execute_tool", marker, true)).toEqual({
args: { id: "install-A:installed_execute_tool", arguments: { text: "approved" } },
});
});
it("rejects cross-path replay when a catalog approval is invoked as a direct tool", () => {
const marker = "__rakazoCatalogTool";
const direct = boundDirectApprovalRequest(
{ connectorId: "installed", resourceId: "install-A", toolName: "notes.write" },
{ text: "approved exactly" },
marker,
);
const catalog = catalogApprovalRequest(
"installed_execute_tool",
{ id: "install-A:notes.write", arguments: { text: "catalog" } },
marker,
);
const matching = {
connectorId: "installed",
resourceId: "install-A",
toolName: "notes.write",
};
const other = {
connectorId: "installed",
resourceId: "install-B",
toolName: "notes.write",
};
expect(approvalReplayPathError("notes.write", false, catalog, marker)).toMatch(
/must be replayed via its catalog execute tool/,
);
expect(approvalReplayPathError("notes.write", false, catalog, marker, other)).toMatch(
/must be replayed via its catalog execute tool/,
);
expect(
approvalReplayPathError("notes.write", false, catalog, marker, matching),
).toBeUndefined();
expect(
approvalReplayPathError("notes.write", false, catalog, marker, {
...matching,
resourceRevision: 2,
}),
).toMatch(/must be replayed via its catalog execute tool/);
const boundCatalog = catalogApprovalRequest(
"installed_execute_tool",
{ id: "install-A:notes.write", arguments: { text: "catalog" } },
marker,
{
connectorId: "installed",
resourceId: "install-A",
resourceRevision: 1,
toolName: "notes.write",
},
);
expect(
approvalReplayPathError("notes.write", false, boundCatalog, marker, {
...matching,
resourceRevision: 1,
}),
).toBeUndefined();
expect(
approvalReplayPathError("notes.write", false, boundCatalog, marker, {
...matching,
resourceRevision: 2,
}),
).toMatch(/must be replayed via its catalog execute tool/);
expect(approvalReplayPathError("notes.write", true, direct, marker)).toBeUndefined();
expect(approvalReplayPathError("notes.write", false, direct, marker)).toBeUndefined();
expect(approvalReplayPathError("notes.write", true, catalog, marker)).toBeUndefined();
});
it("replays a bound direct approval through catalog only on the same resource", () => {
const marker = "__rakazoCatalogTool";
const approved = boundDirectApprovalRequest(
{
connectorId: "installed",
resourceId: "install-A",
resourceRevision: 1,
toolName: "notes.write",
},
{ text: "approved exactly", mode: "fast" },
marker,
);
const same = {
connectorId: "installed",
resourceId: "install-A",
resourceRevision: 1,
toolName: "notes.write",
};
const other = {
connectorId: "installed",
resourceId: "install-B",
resourceRevision: 1,
toolName: "notes.write",
};
// Quiet token refresh keeps revision; OAuth reauth increments it.
const quietRefresh = {
connectorId: "installed",
resourceId: "install-A",
resourceRevision: 1,
toolName: "notes.write",
};
const reauthorized = {
connectorId: "installed",
resourceId: "install-A",
resourceRevision: 2,
toolName: "notes.write",
};
expect(
approvalReplayResourceError("notes.write", true, approved, same, marker),
).toBeUndefined();
expect(
approvalReplayResourceError("notes.write", false, approved, same, marker),
).toBeUndefined();
expect(approvalReplayResourceError("notes.write", true, approved, other, marker)).toMatch(
/different connector resource/,
);
expect(approvalReplayResourceError("notes.write", false, approved, other, marker)).toMatch(
/different connector resource/,
);
expect(
approvalReplayResourceError("notes.write", false, approved, quietRefresh, marker),
).toBeUndefined();
expect(
approvalReplayResourceError("notes.write", false, approved, reauthorized, marker),
).toMatch(/different connector resource/);
expect(
approvalReplayResourceError("notes.write", true, { text: "legacy" }, same, marker),
).toMatch(/must be replayed as a direct tool call/);
expect(
approvalReplayResourceError("notes.write", false, { text: "legacy" }, same, marker),
).toBeUndefined();
expect(approvedReplayArgs(approved, { text: "model" }, marker)).toEqual({
text: "approved exactly",
mode: "fast",
});
});
});
describe("approvalEffectKey", () => {
it("is stable across arg key order", () => {
const left = approvalEffectKey("run-1", "destination.write", {
collection: "notes",
title: "Result",
body: "hello",
});
const right = approvalEffectKey("run-1", "destination.write", {
body: "hello",
collection: "notes",
title: "Result",
});
expect(left).toBe(right);
});
it("differs when args change", () => {
const first = approvalEffectKey("run-1", "destination.write", { body: "one" });
const second = approvalEffectKey("run-1", "destination.write", { body: "two" });
expect(first).not.toBe(second);
});
});
describe("resolveDuplicateEffectGate", () => {
it("executes only after approval", () => {
expect(resolveDuplicateEffectGate({ status: "approved" }, "archive_bot")).toEqual({
action: "execute",
});
});
it("returns denial without executing", () => {
expect(resolveDuplicateEffectGate({ status: "denied" }, "destination.write")).toEqual({
action: "return",
result: { error: "User denied this action." },
});
});
it("returns paused for intended effects instead of executing", () => {
expect(resolveDuplicateEffectGate({ status: "intended" }, "archive_bot")).toEqual({
action: "paused",
});
expect(resolveDuplicateEffectGate({ status: "intended" }, "delete_bot")).toEqual({
action: "paused",
});
});
it("fails closed for executing effects", () => {
expect(resolveDuplicateEffectGate({ status: "executing" }, "destination.write")).toEqual({
action: "uncertain",
toolName: "destination.write",
});
});
it("returns a previously reconciled uncertain result", () => {
const result = { error: "outcome unknown", uncertain: true };
expect(
resolveDuplicateEffectGate({ status: "uncertain", result }, "destination.write"),
).toEqual({ action: "return", result });
});
});
describe("claimApprovedEffect", () => {
it("claims approved effects exactly once", async () => {
const store = {
externalEffect: {
updateMany: vi.fn().mockResolvedValueOnce({ count: 1 }).mockResolvedValueOnce({ count: 0 }),
},
};
await expect(claimApprovedEffect(store, "effect-1")).resolves.toBe(true);
await expect(claimApprovedEffect(store, "effect-1")).resolves.toBe(false);
expect(store.externalEffect.updateMany).toHaveBeenCalledWith({
where: { id: "effect-1", status: "approved" },
data: { status: "executing" },
});
});
});
describe("claimIntendedEffect", () => {
it("claims intended effects exactly once", async () => {
const store = {
externalEffect: {
updateMany: vi.fn().mockResolvedValueOnce({ count: 1 }).mockResolvedValueOnce({ count: 0 }),
},
};
await expect(claimIntendedEffect(store, "effect-1")).resolves.toBe(true);
await expect(claimIntendedEffect(store, "effect-1")).resolves.toBe(false);
expect(store.externalEffect.updateMany).toHaveBeenCalledWith({
where: { id: "effect-1", status: "intended" },
data: { status: "executing" },
});
});
});
describe("replaceCompletedExternalEffectResult", () => {
it("updates the stored result for a completed effect", async () => {
const store = {
externalEffect: {
updateMany: vi.fn().mockResolvedValue({ count: 1 }),
},
};
const result = { ok: true, submitted: true, connected: true };
await expect(replaceCompletedExternalEffectResult(store, "effect-1", result)).resolves.toBe(
true,
);
expect(store.externalEffect.updateMany).toHaveBeenCalledWith({
where: { id: "effect-1", status: "completed" },
data: { result },
});
});
});
describe("completeExternalEffect", () => {
it("does not let a stale worker overwrite a reconciled effect", async () => {
const store = {
externalEffect: {
updateMany: vi.fn().mockResolvedValue({ count: 0 }),
},
};
const result = { written: true };
await expect(completeExternalEffect(store, "effect-1", "executing", result)).resolves.toBe(
false,
);
expect(store.externalEffect.updateMany).toHaveBeenCalledWith({
where: { id: "effect-1", status: "executing" },
data: { status: "completed", result },
});
});
});
describe("approved effect resume", () => {
function createApprovedEffectStore(
initialStatus: "approved" | "executing" | "completed" = "approved",
) {
const effectId = "effect-1";
let status: "approved" | "executing" | "completed" | "uncertain" = initialStatus;
let destinationWrites = 0;
const storedResult = { ok: true, written: true };
let effectResult: unknown;
const store = {
externalEffect: {
updateMany: vi.fn(async ({ where, data }) => {
if (where.id === effectId && where.status === "approved" && status === "approved") {
status = data.status as typeof status;
return { count: 1 };
}
if (where.id === effectId && where.status === "executing" && status === "executing") {
status = data.status as typeof status;
effectResult = data.result;
return { count: 1 };
}
return { count: 0 };
}),
findUnique: vi.fn(async (_args: { where: { id: string } }) => ({
id: effectId,
status,
result: status === "completed" ? storedResult : effectResult,
})),
},
};
const resumeApprovedTool = async (toolName: string, options?: { complete?: boolean }) => {
const current = await store.externalEffect.findUnique({ where: { id: effectId } });
const effect = current ?? { id: effectId, status, result: undefined as unknown };
const gate = resolveDuplicateEffectGate(effect, toolName);
if (gate.action === "return") return { executed: false, result: gate.result };
if (gate.action === "uncertain") {
return {
executed: false,
result: await settleUncertainEffect(store, effectId, toolName),
};
}
if (!(await claimApprovedEffect(store, effectId))) {
const current = await store.externalEffect.findUnique({ where: { id: effectId } });
if (!current) {
throw new Error(`tool ${toolName} has an earlier execution with an uncertain outcome`);
}
const retryGate = resolveDuplicateEffectGate(current, toolName);
if (retryGate.action === "return") return { executed: false, result: retryGate.result };
if (retryGate.action === "uncertain") {
return {
executed: false,
result: await settleUncertainEffect(store, effectId, toolName),
};
}
throw new Error(`tool ${toolName} has an earlier execution with an uncertain outcome`);
}
destinationWrites += 1;
if (options?.complete !== false) {
status = "completed";
}
return { executed: true, result: storedResult };
};
return {
store,
resumeApprovedTool,
getDestinationWrites: () => destinationWrites,
getStatus: () => status,
};
}
it("records an unknown outcome without replaying after interruption", async () => {
const harness = createApprovedEffectStore();
const first = await harness.resumeApprovedTool("destination.write", { complete: false });
const second = await harness.resumeApprovedTool("destination.write");
expect(first).toEqual({ executed: true, result: { ok: true, written: true } });
expect(second).toEqual({
executed: false,
result: expect.objectContaining({ uncertain: true }),
});
expect(harness.getStatus()).toBe("uncertain");
expect(harness.getDestinationWrites()).toBe(1);
});
it("returns the stored result after the approved effect completed", async () => {
const harness = createApprovedEffectStore();
await harness.resumeApprovedTool("destination.write");
const second = await harness.resumeApprovedTool("destination.write");
expect(second).toEqual({ executed: false, result: { ok: true, written: true } });
expect(harness.getDestinationWrites()).toBe(1);
});
});
describe("isToolPauseResult", () => {
it("detects approval and secret pauses", () => {
expect(isToolPauseResult(approvalPausedToolResult())).toBe(true);
expect(
isToolPauseResult({
kind: "agent_tool_result",
terminate: true,
details: { secret: "paused" },
}),
).toBe(true);
expect(isToolPauseResult({ ok: true })).toBe(false);
});
});
describe("approvalPausedToolResult", () => {
it("returns a terminating agent tool result", () => {
const paused = approvalPausedToolResult();
expect(isApprovalPausedResult(paused)).toBe(true);
expect(paused).toMatchObject({
kind: "agent_tool_result",
terminate: true,
details: { approval: "paused" },
});
expect(isApprovalPausedResult({ ok: true })).toBe(false);
});
});
describe("catalog wrapper names", () => {
it("maps MCP to connectors and leaves other connector ids unchanged", () => {
expect(catalogToolPrefix("mcp")).toBe("connectors");
expect(catalogToolPrefix("installed")).toBe("installed");
expect(catalogExecuteToolName("mcp")).toBe("connectors_execute_tool");
expect(catalogExecuteToolName("installed")).toBe("installed_execute_tool");
expect(catalogApprovalConnectorId("connectors_execute_tool")).toBe("mcp");
expect(catalogApprovalConnectorId("mcp_execute_tool")).toBe("mcp");
expect(catalogApprovalConnectorId("installed_execute_tool")).toBe("installed");
});
it("matches a connectors_execute_tool approval to a live MCP route", () => {
expect(
catalogApprovalMatchesLiveRoute(
{
toolName: "connectors_execute_tool",
args: { id: "server-1:send_message", arguments: { text: "approved" } },
},
{ connectorId: "mcp", resourceId: "server-1", toolName: "send_message" },
),
).toBe(true);
});
});