mirror of
https://github.com/morluto/rea
synced 2026-10-26 22:28:27 -04:00
63bf91405c
Deliver complete Evidence directly through MCP with required nullable analysis profiles and immutable per-server delivery settings. Bind selected environments at construction and require typed cleanup outcomes with retained retry ownership. Remove test-only routing, duplicate session and snapshot metadata, producer-field repairs, and ambiguous provider arguments. Separate artifact byte identity from occurrence classification and retain typed source-map and partial native facts across CLI, MCP, and verifier consumers. BREAKING CHANGE: obsolete Evidence envelopes, session aliases, incomplete snapshots, and missing normalized producer facts are no longer accepted.
152 lines
5.1 KiB
TypeScript
152 lines
5.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { WebModuleTraceService } from "./WebModuleTraceService.js";
|
|
import { ok } from "../domain/result.js";
|
|
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
|
|
import {
|
|
webModuleTraceResultSchema,
|
|
type WebModuleResolution,
|
|
} from "../domain/webModuleTrace.js";
|
|
import {
|
|
webModuleArtifactsFixture,
|
|
webModuleResolverFixture,
|
|
} from "../../tests/fixtures/webModuleTrace.js";
|
|
|
|
const args = { manifest_path: "/analysis/manifest.json", script_index: 0 };
|
|
it.each([
|
|
{ ...args, importer_url: "file:///tmp/main.js" },
|
|
{ ...args, import_map: { path: "/map.json", base_url: "file:///tmp/maps/" } },
|
|
])(
|
|
"distinguishes valid unsupported URL contexts from malformed input: %j",
|
|
async (input) => {
|
|
const result = await new WebModuleTraceService(
|
|
{
|
|
load: () => {
|
|
throw new Error("must not acquire artifacts");
|
|
},
|
|
},
|
|
webModuleResolverFixture,
|
|
).trace(input);
|
|
if (result.ok) throw new Error("expected unsupported context");
|
|
expect(projectAnalysisError(result.error)).toMatchObject({
|
|
code: "capability_unavailable",
|
|
message: expect.stringContaining("file:"),
|
|
});
|
|
},
|
|
);
|
|
it("rejects source text changed across the artifact port while retaining the original digest", async () => {
|
|
const artifacts = {
|
|
...webModuleArtifactsFixture("import(name)"),
|
|
source: "import(other)",
|
|
};
|
|
const result = await new WebModuleTraceService(
|
|
{ load: () => Promise.resolve(ok(artifacts)) },
|
|
{
|
|
resolve: () => {
|
|
throw new Error("must not acquire engine");
|
|
},
|
|
},
|
|
).trace(args);
|
|
expect(result.ok).toBe(false);
|
|
if (!result.ok) expect(result.error._tag).toBe("AnalysisOutputError");
|
|
});
|
|
it("rejects sparse resolver arrays rather than relabeling literal imports as computed unknowns", async () => {
|
|
const artifacts = webModuleArtifactsFixture('import "./dep.js";');
|
|
const resolutions: WebModuleResolution[] = [];
|
|
resolutions.length = 1;
|
|
const service = new WebModuleTraceService(
|
|
{ load: () => Promise.resolve(ok(artifacts)) },
|
|
{
|
|
resolve: () =>
|
|
Promise.resolve(
|
|
ok({
|
|
engine: { id: "fixture", version: "1" },
|
|
resolutions,
|
|
diagnostics: [],
|
|
rawResult: {},
|
|
}),
|
|
),
|
|
},
|
|
);
|
|
const result = await service.trace(args);
|
|
expect(result.ok).toBe(false);
|
|
if (!result.ok) expect(result.error._tag).toBe("AnalysisOutputError");
|
|
});
|
|
describe("selected module trace workflow", () => {
|
|
it.each([
|
|
{ ...args, manifest_path: "relative.json" },
|
|
{
|
|
...args,
|
|
import_map: { path: "relative.json", base_url: "https://app.test/" },
|
|
},
|
|
{ ...args, importer_url: "not a URL" },
|
|
{ ...args, import_map: { path: "/map.json", base_url: "relative" } },
|
|
])(
|
|
"rejects malformed context before acquiring artifacts: %j",
|
|
async (input) => {
|
|
const service = new WebModuleTraceService(
|
|
{
|
|
load: () => {
|
|
throw new Error("must not acquire");
|
|
},
|
|
},
|
|
webModuleResolverFixture,
|
|
);
|
|
const response = await service.trace(input);
|
|
if (response.ok) throw new Error("expected invalid input");
|
|
expect(projectAnalysisError(response.error)).toMatchObject({
|
|
code: "invalid_request",
|
|
details: {
|
|
issues: [expect.objectContaining({ reason: "invalid_format" })],
|
|
},
|
|
});
|
|
},
|
|
);
|
|
it("rejects incomplete resolution rather than fabricating unknown values", async () => {
|
|
const artifacts = webModuleArtifactsFixture();
|
|
const service = new WebModuleTraceService(
|
|
{ load: () => Promise.resolve(ok(artifacts)) },
|
|
{
|
|
resolve: () =>
|
|
Promise.resolve(
|
|
ok({
|
|
engine: { id: "fixture", version: "1" },
|
|
resolutions: [],
|
|
diagnostics: [],
|
|
rawResult: {},
|
|
}),
|
|
),
|
|
},
|
|
);
|
|
const response = await service.trace(args);
|
|
expect(response.ok).toBe(false);
|
|
if (!response.ok) expect(response.error._tag).toBe("AnalysisOutputError");
|
|
});
|
|
it("preserves an explicit selected importer context", async () => {
|
|
const artifacts = webModuleArtifactsFixture();
|
|
const result = await new WebModuleTraceService(
|
|
{ load: () => Promise.resolve(ok(artifacts)) },
|
|
webModuleResolverFixture,
|
|
).trace({ ...args, importer_url: "https://selected.test/base/main.js" });
|
|
if (!result.ok) throw result.error;
|
|
expect(
|
|
webModuleTraceResultSchema.parse(result.value.normalized_result)
|
|
.imports[0]?.resolution,
|
|
).toEqual({ state: "resolved", url: "https://selected.test/base/dep.js" });
|
|
});
|
|
it("honors cancellation before any artifacts are acquired", async () => {
|
|
const controller = new AbortController();
|
|
controller.abort();
|
|
const service = new WebModuleTraceService(
|
|
{
|
|
load: () => {
|
|
throw new Error("must not acquire");
|
|
},
|
|
},
|
|
webModuleResolverFixture,
|
|
);
|
|
const result = await service.trace(args, { signal: controller.signal });
|
|
expect(result.ok).toBe(false);
|
|
if (!result.ok) expect(result.error._tag).toBe("AnalysisCancelledError");
|
|
});
|
|
});
|