/* Unit tests for reflect route covering createAgentReflectRoute. It also guards the documented public contract and regression-sensitive edge cases. Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only. RFC-1311: Compass header sweep — declares the reflect suite's contract for test-file scaffold coverage. */ import { describe, it, expect, vi, beforeEach } from "vitest"; import { createAgentReflectRoute } from "../reflect-route.ts"; import type { ReflectionInput, LawKernelSummary } from "../../component-runtime/reflection.ts"; import type { ComponentDeclaration, ComponentId, ResolvedComponentSetV1, ResolvedComponentIdentityV1, } from "@warpgogol/werkstatt-shared/component"; import { computeSetHash } from "../../component/identity.ts"; import type { Sha256Digest } from "@warpgogol/werkstatt-shared/fingerprint"; const VALID_SHA = ("sha256:" + "a".repeat(64)) as Sha256Digest; function cid(id: string): ComponentId { return id as ComponentId; } function makeManifest(overrides: Partial = {}): ComponentDeclaration { const componentId = overrides.componentId ?? "werkstatt/engine"; return { schema: "werkstatt/component-declaration@1", componentId, version: "1.0.0", artifactHash: VALID_SHA, scope: "per-workshop", provides: [ { capability: "werkstatt/kernel", version: "1.0.0", schemaHash: VALID_SHA as string }, ], requires: [], requestedGrants: [], effects: [], isolation: { tier: 0, adapterId: null }, resources: [{ kind: "cpu", limit: "100ms", owner: componentId, lifecycle: "process" }], priority: 0, active: true, ...overrides, }; } function makeResolvedIdentity( overrides: Partial = {}, ): ResolvedComponentIdentityV1 { return { componentId: cid("werkstatt/engine"), version: "1.0.0", artifactHash: VALID_SHA, ...overrides, }; } function makeResolvedSet(): ResolvedComponentSetV1 { const base: Omit = { schema: "werkstatt/resolved-component-set@1", profileId: "site", components: [makeResolvedIdentity()], dependencyGraphHash: VALID_SHA as string, grantSetHash: VALID_SHA as string, effectPolicyHash: VALID_SHA as string, isolationPolicyHash: VALID_SHA as string, }; const setHash = computeSetHash(base); return { ...base, setHash }; } const STUB_LAW_KERNEL: LawKernelSummary = { activeGrants: 0, artifactStoreEntries: 0, killSwitchArmed: false, }; function makeReflectionInput(): ReflectionInput { return { activeSet: makeResolvedSet(), manifests: new Map([["werkstatt/engine", makeManifest()]]), observations: new Map([ ["werkstatt/engine", { componentId: cid("werkstatt/engine"), lifecycleState: "active" }], ]), observedAt: "2026-01-01T00:00:00Z", }; } function mockAPIRouteContext(clientAddress: string) { return { clientAddress, request: new Request("https://example.com/api/agent/reflect"), params: {}, site: undefined, props: {}, redirect: vi.fn(), url: new URL("https://example.com/api/agent/reflect"), locals: {}, cookies: { get: vi.fn(), set: vi.fn(), delete: vi.fn(), has: vi.fn(), }, } as unknown as Parameters["GET"]>[0]; } describe("createAgentReflectRoute", () => { beforeEach(() => { vi.resetModules(); }); it("returns 200 with RuntimeReflectionV1 JSON for authorized request (AC-6)", async () => { const route = createAgentReflectRoute({ reflectionInput: makeReflectionInput(), lawKernelSummary: STUB_LAW_KERNEL, }); const ctx = mockAPIRouteContext("192.168.1.1"); const response = await route.GET(ctx); expect(response.status).toBe(200); expect(response.headers.get("Content-Type")).toBe("application/json"); const body = await response.json(); expect(body.reflectedAt).toBe("2026-01-01T00:00:00Z"); expect(body.components).toHaveLength(1); expect(body.components[0].componentId).toBe("werkstatt/engine"); }); it("returns 429 with Retry-After when rate limit exceeded (AC-6)", async () => { const route = createAgentReflectRoute({ reflectionInput: makeReflectionInput(), lawKernelSummary: STUB_LAW_KERNEL, }); const ctx = mockAPIRouteContext("10.0.0.1"); for (let i = 0; i < 10; i++) { await route.GET(ctx); } const response = await route.GET(ctx); expect(response.status).toBe(429); expect(response.headers.get("Retry-After")).toBeTruthy(); const body = await response.json(); expect(body.error).toBe("rate_limited"); }); it("returns 204 for OPTIONS request", async () => { const route = createAgentReflectRoute({ reflectionInput: makeReflectionInput(), lawKernelSummary: STUB_LAW_KERNEL, }); const response = await route.OPTIONS({} as never); expect(response.status).toBe(204); expect(response.headers.get("Access-Control-Allow-Methods")).toBe("GET, OPTIONS"); }); it("rate limiting is per-IP (different IPs have separate buckets)", async () => { const route = createAgentReflectRoute({ reflectionInput: makeReflectionInput(), lawKernelSummary: STUB_LAW_KERNEL, }); const ctx1 = mockAPIRouteContext("10.0.0.1"); for (let i = 0; i < 10; i++) { await route.GET(ctx1); } const ctx2 = mockAPIRouteContext("10.0.0.2"); const response = await route.GET(ctx2); expect(response.status).toBe(200); }); it("returns CORS headers on GET response", async () => { const route = createAgentReflectRoute({ reflectionInput: makeReflectionInput(), lawKernelSummary: STUB_LAW_KERNEL, }); const ctx = mockAPIRouteContext("192.168.1.2"); const response = await route.GET(ctx); expect(response.headers.get("Access-Control-Allow-Origin")).toBe("*"); }); });