import { describe, expect, it } from "vitest"; import { reopenResolvedUnknown } from "@/lib/graph/reopen-resolved-unknown.js"; function makeTestGraph() { return { centralStatement: "Should we enter the European market?", currentSummary: "We have some initial understanding.", nodes: [ { id: "u-1", label: "Whether there is genuine demand for our category in Europe", description: "Need to validate European demand.", kind: "unknown", status: "resolved", confidence: "high", evidenceIds: ["e-1"], dependsOn: [], affects: [], }, { id: "u-2", label: "Whether our product is suitable for European compliance requirements", description: "Compliance question.", kind: "unknown", status: "resolved", confidence: "medium", evidenceIds: ["e-2"], dependsOn: [], affects: [], }, { id: "u-3", label: "Whether the cost is justified by market size", description: "Cost-benefit question.", kind: "unknown", status: "unknown", confidence: "medium", evidenceIds: [], dependsOn: ["u-2"], affects: [], }, { id: "obs-1", label: "Current revenue is $2M ARR.", description: "Financial observation.", kind: "observation", status: "known", confidence: "high", evidenceIds: [], dependsOn: [], affects: [], }, { id: "state-1", label: "Evaluating European market entry", kind: "state", status: "provisional", confidence: "medium", evidenceIds: [], dependsOn: [], affects: [], }, ], edges: [ { fromNodeId: "u-2", toNodeId: "u-3" }, ], resolvedNodeIds: ["u-1", "u-2"], }; } describe("reopenResolvedUnknown — pure deterministic transformation", () => { describe("resolved unknown target", () => { it("sets canonical unresolved status on target node", () => { const graph = makeTestGraph(); const result = reopenResolvedUnknown(graph, "u-1"); const targetNode = result.nodes.find((n) => n.id === "u-1"); expect(targetNode.status).toBe("unknown"); }); it("preserves same node identity (id unchanged)", () => { const graph = makeTestGraph(); const result = reopenResolvedUnknown(graph, "u-1"); const targetNode = result.nodes.find((n) => n.id === "u-1"); expect(targetNode.id).toBe("u-1"); }); it("removes node ID from resolvedNodeIds", () => { const graph = makeTestGraph(); const result = reopenResolvedUnknown(graph, "u-1"); expect(result.resolvedNodeIds).not.toContain("u-1"); }); it("preserves other resolvedNodeIds (unrelated state)", () => { const graph = makeTestGraph(); const result = reopenResolvedUnknown(graph, "u-1"); expect(result.resolvedNodeIds).toContain("u-2"); }); it("preserves all unrelated node properties", () => { const graph = makeTestGraph(); const result = reopenResolvedUnknown(graph, "u-1"); const u2 = result.nodes.find((n) => n.id === "u-2"); expect(u2.status).toBe("resolved"); expect(u2.confidence).toBe("medium"); expect(u2.label).toBe("Whether our product is suitable for European compliance requirements"); const obs1 = result.nodes.find((n) => n.id === "obs-1"); expect(obs1.status).toBe("known"); expect(obs1.kind).toBe("observation"); }); it("preserves all edges", () => { const graph = makeTestGraph(); const result = reopenResolvedUnknown(graph, "u-1"); expect(result.edges).toHaveLength(1); expect(result.edges[0].fromNodeId).toBe("u-2"); expect(result.edges[0].toNodeId).toBe("u-3"); }); it("preserves centralStatement and currentSummary", () => { const graph = makeTestGraph(); const result = reopenResolvedUnknown(graph, "u-1"); expect(result.centralStatement).toBe("Should we enter the European market?"); expect(result.currentSummary).toBe("We have some initial understanding."); }); it("does not mutate input graph", () => { const graph = makeTestGraph(); reopenResolvedUnknown(graph, "u-1"); const targetNode = graph.nodes.find((n) => n.id === "u-1"); expect(targetNode.status).toBe("resolved"); const u2 = graph.nodes.find((n) => n.id === "u-2"); expect(u2.status).toBe("resolved"); expect(graph.resolvedNodeIds).toContain("u-1"); }); }); describe("canonical resolved-node-ID target", () => { it("reopens an unknown-status node marked resolved by graph state without mutating input", () => { const graph = makeTestGraph(); graph.nodes[0] = { ...graph.nodes[0], status: "unknown" }; const result = reopenResolvedUnknown(graph, "u-1"); const targetNode = result.nodes.find((n) => n.id === "u-1"); expect(targetNode.kind).toBe("unknown"); expect(targetNode.status).toBe("unknown"); expect(result.resolvedNodeIds).not.toContain("u-1"); expect(result.resolvedNodeIds).toContain("u-2"); expect(graph.nodes.find((n) => n.id === "u-1").status).toBe("unknown"); expect(graph.resolvedNodeIds).toContain("u-1"); }); }); describe("invalid/no-op cases", () => { it("returns original graph when node does not exist", () => { const graph = makeTestGraph(); const result = reopenResolvedUnknown(graph, "nonexistent"); expect(result).toBe(graph); expect(result.nodes.find((n) => n.id === "u-1").status).toBe("resolved"); expect(result.resolvedNodeIds).toContain("u-1"); }); it("returns original graph when node is already unresolved", () => { const graph = makeTestGraph(); const result = reopenResolvedUnknown(graph, "u-3"); expect(result).toBe(graph); expect(result.resolvedNodeIds).toContain("u-1"); expect(result.resolvedNodeIds).toContain("u-2"); }); it("returns original graph when node is not an unknown kind", () => { const graph = makeTestGraph(); const result = reopenResolvedUnknown(graph, "obs-1"); expect(result).toBe(graph); }); it("returns original graph when input graph is null", () => { expect(reopenResolvedUnknown(null, "u-1")).toBeNull(); }); it("returns original graph when input graph has no nodes", () => { const graph = makeTestGraph(); const noNodes = { ...graph, nodes: [] }; const result = reopenResolvedUnknown(noNodes, "u-1"); expect(result).toBe(noNodes); }); }); });