Files
reverse-engineering-anything/src/application/ProviderOperationExecution.test.ts
T
morluto ccdeda7a27 fix(inputs): centralize admission and preserve caller selections
Move shared request parsing into its application owner, migrate all consumers, and remove six duplicated admission blocks while preserving cancellation and validation policy.

Keep operator-selected JavaScript paths in verifier parent Evidence while retaining canonical comparison guards. Validated with 204 passing tests, 3 Linux-x64-only skips, typecheck, lint, and test discovery.
2026-10-26 17:35:18 +08:00

181 lines
5.8 KiB
TypeScript

import { expect, it, vi } from "vitest";
import { z } from "zod";
import {
AnalysisCancelledError,
AnalysisInputError,
AnalysisOutputError,
} from "../domain/analysisErrorCore.js";
import { analysisErrorWithCleanupFailure } from "../domain/analysisErrorCleanup.js";
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
import { ProviderCleanupError } from "../domain/providerCleanupError.js";
import {
executeProviderOperation,
keepIncompleteObservation,
} from "./ProviderOperationExecution.js";
it("projects request-schema issues without exposing the request envelope", async () => {
const execute = vi.fn();
const result = await executeProviderOperation(
"list_jeb_units",
{ parent_unit_path: "" },
undefined,
z.strictObject({
operation: z.literal("list_jeb_units"),
input: z.strictObject({ parent_unit_path: z.string().min(1) }),
}),
{ execute },
"observed",
);
expect(result.ok).toBe(false);
if (result.ok || !(result.error instanceof AnalysisInputError))
throw new Error("Expected input error");
expect(result.error.issues).toEqual([
{
path: ["parent_unit_path"],
reason: "out_of_range",
minimum: 1,
},
]);
expect(result.error.cause).toBeInstanceOf(z.ZodError);
expect(execute).not.toHaveBeenCalled();
});
it("removes only the owned envelope prefix while preserving nested caller paths", async () => {
const execute = vi.fn();
const result = await executeProviderOperation(
"inspect",
{ input: "", rows: [{}], mode: "foreign", extra: "caller-only-marker" },
undefined,
z.strictObject({
operation: z.literal("inspect"),
input: z.strictObject({
input: z.string().min(1),
rows: z.array(z.strictObject({ name: z.string() })),
mode: z.enum(["first", "second"]),
}),
}),
{ execute },
"observed",
);
if (result.ok || !(result.error instanceof AnalysisInputError))
throw new Error("Expected input error");
expect(result.error.issues).toEqual([
{ path: ["input"], reason: "out_of_range", minimum: 1 },
{
path: ["rows", 0, "name"],
reason: "missing_argument",
expected: "string",
},
{ path: ["mode"], reason: "invalid_value", expected: ["first", "second"] },
{ path: ["extra"], reason: "unknown_argument" },
]);
expect(JSON.stringify(result.error.issues)).not.toContain(
"caller-only-marker",
);
expect(execute).not.toHaveBeenCalled();
});
it("preserves operation correction outside the input envelope", async () => {
const execute = vi.fn();
const result = await executeProviderOperation(
"unknown",
{},
undefined,
z.strictObject({
operation: z.literal("known"),
input: z.strictObject({}),
}),
{ execute },
"observed",
);
if (result.ok || !(result.error instanceof AnalysisInputError))
throw new Error("Expected input error");
expect(result.error.issues).toEqual([
{ path: ["operation"], reason: "invalid_value", expected: ["known"] },
]);
expect(execute).not.toHaveBeenCalled();
});
const cancelledScenario = (partial: unknown) =>
new AnalysisCancelledError("capture_browser_scenario", {
cause: { requested: "stop during capture" },
partialObservation: partial as never,
});
const wrapScenarioCleanup = (primary: AnalysisCancelledError) =>
analysisErrorWithCleanupFailure(
primary,
new ProviderCleanupError("fixture", ["browser"], {}),
"capture_browser_scenario",
);
it("clears a non-JSON partial from the cleanup primary projection returns after retry", () => {
const partial = { steps: [] as unknown[] };
const primary = cancelledScenario(partial);
const composed = wrapScenarioCleanup(primary);
partial.steps.push(undefined);
const reason =
"Browser scenario provider retained a non-JSON incomplete observation.";
const retained = keepIncompleteObservation(
composed,
"capture_browser_scenario",
reason,
);
expect(retained).toBe(composed);
expect(composed.partialObservation).toBeUndefined();
expect(primary.partialObservation).toBeUndefined();
expect(composed.secondaryFailures).toMatchObject([
{ _tag: "AnalysisOutputError", reason },
]);
expect(primary.secondaryFailures[0]).toBeInstanceOf(AnalysisOutputError);
expect(projectAnalysisError(composed).code).toBe("cleanup_incomplete");
composed.resolveCleanup();
expect(projectAnalysisError(composed)).toMatchObject({
code: "cancelled",
category: "cancelled",
});
expect(projectAnalysisError(composed).details).not.toHaveProperty(
"partial_observation",
);
});
it("freezes one shared snapshot for a cleanup wrapper and its primary", () => {
const partial = { steps: ["kept"] };
const primary = cancelledScenario(partial);
const composed = wrapScenarioCleanup(primary);
keepIncompleteObservation(
composed,
"capture_browser_scenario",
"unused because the partial is JSON",
);
expect(composed.partialObservation).toBe(primary.partialObservation);
expect(composed.partialObservation).toEqual({ steps: ["kept"] });
expect(Object.isFrozen(composed.partialObservation)).toBe(true);
expect(composed.secondaryFailures).toHaveLength(0);
expect(primary.secondaryFailures).toHaveLength(0);
});
it("freezes a retained partial so a later mutation cannot break projection", () => {
const partial = { steps: [] as unknown[] };
const primary = cancelledScenario(partial);
keepIncompleteObservation(
primary,
"capture_browser_scenario",
"unused because the partial is JSON",
);
partial.steps.push(undefined);
expect(primary.partialObservation).toEqual({ steps: [] });
expect(Object.isFrozen(primary.partialObservation)).toBe(true);
expect(primary.secondaryFailures).toHaveLength(0);
expect(projectAnalysisError(primary)).toMatchObject({
code: "cancelled",
details: { partial_observation: { steps: [] } },
});
});