import { describe, expect, it } from "vitest"; import { formulateQuestion, formulateTieResolutionQuestion, selectReasoningPattern, } from "@/lib/graph/question-formulator.js"; import { makeGraph, makeNode } from "@/lib/graph/schema.js"; function makeGraphFor(node, extra = {}) { return makeGraph({ centralStatement: extra.centralStatement || "Decision context", nodes: [node, ...(extra.nodes || [])], edges: extra.edges || [], activeUnknownNodeId: node.id, resolvedNodeIds: extra.resolvedNodeIds || [], currentSummary: "Test summary", reasoningState: extra.reasoningState, }); } describe("reasoning pattern selection", () => { it("commercial-method scenario selects the decision pattern and rejects explanation family", () => { const unknown = makeNode({ id: "n-commercial-method", label: "Whether the method addresses a genuine, high-priority problem for a specific audience", description: "Need to know whether this solves a real problem for a clear audience before continuing development.", kind: "unknown", status: "unknown", confidence: "high", }); const graph = makeGraphFor(unknown, { centralStatement: "Before investing significant time and money, we need to know whether continuing development is commercially justified.", }); const result = formulateQuestion({ node: unknown, graph }); expect(result.reasoningPattern).toBe("decision"); expect(result.questionFamily).not.toBe("explanation"); expect(result.allowedQuestionFamilies).toContain("decision_foundation"); expect(result.rejectedQuestionFamilies).toContain("explanation"); }); it("revenue and cash relationship scenario allows the explanation family", () => { const unknown = makeNode({ id: "n-revenue-cash-explanation", label: "Explanation for why revenue increased by 18%, but cash in the bank fell over the same period", description: "Need to understand what change or event could explain why these observations differ.", kind: "unknown", status: "unknown", confidence: "medium", }); const graph = makeGraphFor(unknown, { centralStatement: "Revenue increased by 18%, but cash in the bank fell over the same period.", nodes: [ makeNode({ id: "n-revenue-observation", label: "Revenue increased by 18%.", description: "Revenue increased by 18%.", kind: "observation", status: "supported", confidence: "high", }), makeNode({ id: "n-cash-observation", label: "Cash in the bank fell over the same period.", description: "Cash in the bank fell over the same period.", kind: "observation", status: "supported", confidence: "high", }), ], }); const result = formulateQuestion({ node: unknown, graph }); expect(result.reasoningPattern).toBe("explanation"); expect(result.allowedQuestionFamilies).toContain("explanation"); }); it("duplicate observations reject explanation family during tie resolution", () => { const graph = makeGraph({ centralStatement: "The same figure was repeated twice.", nodes: [ makeNode({ id: "n-obs-1", label: "Revenue increased by 10%.", description: "Revenue increased by 10%.", kind: "observation", status: "supported", confidence: "high", }), makeNode({ id: "n-obs-2", label: "Revenue increased by 10%.", description: "Revenue increased by 10%.", kind: "observation", status: "supported", confidence: "high", }), ], edges: [], activeUnknownNodeId: null, resolvedNodeIds: [], currentSummary: "Duplicate observation fixture", }); const result = formulateTieResolutionQuestion({ graph }); expect(result.questionFamily).not.toBe("explanation"); expect(result.rejectedQuestionFamilies).toContain("explanation"); }); it("definition scenario selects the definition pattern", () => { const unknown = makeNode({ id: "n-definition-pattern", label: "Definition of justified confidence", description: "The term needs clearer boundaries.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = selectReasoningPattern({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.pattern).toBe("definition"); }); it("comparison scenario selects the comparison pattern", () => { const unknown = makeNode({ id: "n-comparison-pattern-2", label: "How the two observations were measured", description: "Need evidence about the measure used for each observation before comparing them.", kind: "unknown", status: "unknown", confidence: "medium", }); const graph = makeGraphFor(unknown, { centralStatement: "Traffic increased, but sales stayed flat.", nodes: [ makeNode({ id: "n-traffic-2", label: "Traffic increased.", description: "Traffic increased.", kind: "observation", status: "supported", confidence: "high", }), makeNode({ id: "n-sales-2", label: "Sales stayed flat.", description: "Sales stayed flat.", kind: "observation", status: "supported", confidence: "high", }), ], reasoningState: { comparabilityStatus: "uncertain", relationshipStatus: "insufficient_information", }, }); const result = selectReasoningPattern({ node: unknown, graph }); expect(result.pattern).toBe("comparison"); }); it("question family stays compatible with the reasoning pattern", () => { const unknown = makeNode({ id: "n-decision-family-compatibility", label: "Who experiences this problem", description: "Need to know who experiences this problem before continuing development.", kind: "unknown", status: "unknown", confidence: "medium", }); const graph = makeGraphFor(unknown, { centralStatement: "We need to know whether continuing development is commercially justified.", }); const result = formulateQuestion({ node: unknown, graph }); expect(result.reasoningPattern).toBe("decision"); expect(result.allowedQuestionFamilies).toContain(result.questionFamily); expect(result.rejectedQuestionFamilies).not.toContain( result.questionFamily, ); }); });