import { describe, expect, it } from "vitest"; import { assessQuestionComplexity, assessUnknownAtomicity, formulateQuestion, } from "@/lib/graph/question-formulator.js"; import { applyValidatedProposal } from "@/lib/graph/apply-proposal.js"; import { makeGraph, makeNode } from "@/lib/graph/schema.js"; const SCENARIO = "I have developed a new reasoning method that aims to help people determine whether they have enough justified confidence to make a decision. I believe it could become a commercial product, but I do not yet know whether it solves a genuine problem, whether people would value it enough to pay for it, or whether it is fundamentally different from existing AI tools. Before investing significant time and money into building it further, I want to determine whether continuing development is commercially justified."; function makeCommercialValidationGraph() { const parent = makeNode({ id: "n-commercial-parent", label: "Commercial justification for whether continuing development is commercially justified", description: "Need to know whether this solves a genuine problem, whether people would value it enough to pay for it, and whether it is commercially justified before continuing development.", kind: "unknown", status: "unknown", confidence: "medium", }); return makeGraph({ centralStatement: SCENARIO, nodes: [parent], edges: [], activeUnknownNodeId: parent.id, resolvedNodeIds: [], currentSummary: "Commercial validation question simplicity fixture", }); } function makeMeaningfulNoOpProposal() { return { addedNodes: [ makeNode({ id: "n-anchor", label: "Update anchor", description: "Anchor state introduced by the answer because the update must contain a meaningful change.", kind: "state", status: "known", confidence: "low", }), ], updatedNodes: [], addedEdges: [], removedEdgeIds: [], resolvedUnknownNodeIds: [], affectedNodeIds: [], selectedQuestion: null, }; } describe("question simplicity", () => { it("rejects the original long compound financial-cost plus budget question", () => { const graph = makeCommercialValidationGraph(); const unknown = graph.nodes.find( (node) => node.id === "n-commercial-parent", ); const question = "Have you measured the current financial or operational cost to users who lack justified confidence, and what baseline budget do they currently allocate for comparable decision-support methods?"; const result = assessQuestionComplexity({ question, selectedUnknown: unknown, graph, }); expect(result.acceptable).toBe(false); expect(result.primaryConceptCount).toBeGreaterThan(1); expect(result.cognitiveLoad).toBe("high"); expect(result.reasons).toContain("multiple_requested_answers"); expect(result.reasons).toContain("cost_and_budget_combined"); }); it("accepts one simple concept question", () => { const graph = makeCommercialValidationGraph(); const unknown = makeNode({ id: "n-who", label: "Who experiences this problem", description: "Need to know who experiences this problem, because that must be clear before deciding whether it is commercially justified.", kind: "unknown", status: "unknown", confidence: "medium", parentId: "n-commercial-parent", }); const result = formulateQuestion({ node: unknown, graph }); expect(result.question).toBe("Who experiences this problem?"); expect(result.questionComplexity.acceptable).toBe(true); expect(result.questionComplexity.primaryConceptCount).toBe(1); expect(result.question.match(/\?/g) || []).toHaveLength(1); }); it("classifies broad commercial-validation unknowns as composite", () => { const graph = makeCommercialValidationGraph(); const unknown = graph.nodes.find( (node) => node.id === "n-commercial-parent", ); const result = assessUnknownAtomicity({ node: unknown, graph }); expect(result.atomicity).toBe("composite"); expect(result.decompositionKind).toBe("commercial_validation"); }); it("decomposes a broad commercial-validation unknown instead of merely rewording it", () => { const graph = makeCommercialValidationGraph(); const result = applyValidatedProposal({ situationGraph: graph, proposal: makeMeaningfulNoOpProposal(), }); expect(result.success).toBe(true); expect(result.decompositionPerformed).toBe(true); expect(result.selectedUnknownBefore).toBe("n-commercial-parent"); expect(result.selectedUnknownAfter).not.toBe("n-commercial-parent"); expect(result.childNodeIds.length).toBeGreaterThanOrEqual(2); expect(result.selectedQuestion.nodeId).toBe(result.selectedUnknownAfter); expect(result.selectedQuestion.question).toBe( "Who experiences this problem?", ); expect(result.selectedQuestion.reasoningPattern).toBe("decision"); expect(result.selectedQuestion.questionFamily).toBe("decision_foundation"); expect(result.selectedQuestion.selectedQuestionTemplate).toBe( "decision_foundation_direct_child", ); expect(result.selectedQuestion.question.match(/\?/g) || []).toHaveLength(1); expect(result.questionComplexityAccepted).toBe(true); expect(result.primaryConceptCount).toBe(1); }); it("selects a foundational child rather than price or budget", () => { const graph = makeCommercialValidationGraph(); const result = applyValidatedProposal({ situationGraph: graph, proposal: makeMeaningfulNoOpProposal(), }); const selectedNode = result.updatedSituationGraph.nodes.find( (node) => node.id === result.selectedUnknownAfter, ); expect(selectedNode.label).toBe("Who experiences this problem"); expect(selectedNode.label.toLowerCase()).not.toMatch(/pay|price|budget/); expect(result.selectedQuestion.question.toLowerCase()).not.toMatch( /pay|price|budget/, ); }); it("plain-language replacements simplify formal phrasing when safe", () => { const graph = makeCommercialValidationGraph(); const unknown = makeNode({ id: "n-actor-formal", label: "Relevant customer or user", description: "Need to identify the relevant customer, user, or value recipient because the decision depends on it.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph }); const complexity = assessQuestionComplexity({ question: "What evidence would clarify the relevant customer, user, or value recipient?", selectedUnknown: unknown, graph, }); expect(complexity.acceptable).toBe(false); expect(complexity.reasons).toContain("list_like_question"); }); it("does not remove scenario-relevant jargon blindly", () => { const graph = makeGraph({ centralStatement: "The team is deciding whether to continue a decision-support product.", nodes: [ makeNode({ id: "n-jargon", label: "Decision support methods", description: "Need evidence about decision support methods because the comparison depends on it.", kind: "unknown", status: "unknown", confidence: "medium", }), ], edges: [], activeUnknownNodeId: "n-jargon", resolvedNodeIds: [], currentSummary: "Jargon retention fixture", }); const result = formulateQuestion({ node: graph.nodes[0], graph }); expect(result.question.toLowerCase()).toContain("decision support methods"); }); });