import { describe, expect, it } from "vitest"; import { assessUnknownAtomicity, formulateQuestion, formulateTieResolutionQuestion, selectReasoningPattern, selectInvestigationStrategy, } from "@/lib/graph/question-formulator.js"; import { makeEdge, 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", }); } describe("formulateQuestion", () => { it("atomicity assessment leaves focused unknowns direct and marks broad explanation unknowns composite", () => { const atomicUnknown = makeNode({ id: "n-atomic", label: "Complaint rate denominator", description: "Need the denominator because it directly determines the complaint rate.", kind: "unknown", status: "unknown", confidence: "high", }); const compositeUnknown = makeNode({ id: "n-composite", 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, because that is needed to investigate their relationship.", kind: "unknown", status: "unknown", confidence: "medium", }); const compositeGraph = makeGraphFor(compositeUnknown, { 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 decreased over the same period.", description: "Cash in the bank decreased over the same period.", kind: "observation", status: "supported", confidence: "high", }), ], }); expect( assessUnknownAtomicity({ node: atomicUnknown, graph: makeGraphFor(atomicUnknown), }).atomicity, ).toBe("atomic"); expect( assessUnknownAtomicity({ node: compositeUnknown, graph: compositeGraph, }).atomicity, ).toBe("composite"); }); it("commercial viability plus build decision produces a decision-threshold question", () => { const unknown = makeNode({ id: "n-commercial", label: "Uncertainty regarding the commercial value of the product", description: "Commercial justification remains unclear because the decision depends on it.", kind: "unknown", status: "unknown", confidence: "high", parentId: "n-decision", }); const decision = makeNode({ id: "n-decision", label: "Build decision", description: "Decision introduced by the answer.", kind: "state", status: "known", confidence: "medium", childIds: [unknown.id], value: "Deciding whether to build the product", }); const graph = makeGraphFor(unknown, { nodes: [decision], resolvedNodeIds: [decision.id], }); const result = formulateQuestion({ node: unknown, graph }); expect(result.strategy).toBe("decision_threshold"); expect(result.reasoningPattern).toBe("decision"); expect(result.questionFamily).toBe("decision_threshold"); expect(result.question).toContain("What outcome"); expect(result.question.toLowerCase()).toContain("justify"); }); it("commercial viability does not produce a pricing-first question", () => { const unknown = makeNode({ id: "n-commercial", label: "Commercial viability", description: "Commercial viability remains unresolved because the decision depends on it.", kind: "unknown", status: "unknown", confidence: "high", }); const graph = makeGraphFor(unknown); const result = formulateQuestion({ node: unknown, graph }); expect(result.question.toLowerCase()).not.toContain("price"); expect(result.question.toLowerCase()).not.toContain("pricing"); }); it("undefined term produces a definition question", () => { const unknown = makeNode({ id: "n-term", label: "Success criteria definition", description: "Need a definition of the term because the team uses it inconsistently.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.strategy).toBe("definition"); expect(result.reasoningPattern).toBe("definition"); expect(result.questionFamily).toBe("definition"); expect(result.question).toMatch(/^What does /); }); it("unsupported claim produces an evidence question", () => { const unknown = makeNode({ id: "n-claim", label: "Demand claim", description: "Need evidence because the claim has not been validated.", kind: "reported_claim", status: "provisional", confidence: "low", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.strategy).toBe("evidence_gathering"); expect(result.question).toContain("What evidence"); }); it("missing previous state produces a baseline question", () => { const unknown = makeNode({ id: "n-baseline", label: "Baseline conversion rate", description: "Need the previous baseline because the change cannot be assessed without it.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.strategy).toBe("baseline_reconstruction"); expect(result.question).toContain("What was the comparable state before"); }); it("conflicting claim produces a contradiction-resolution question", () => { const unknown = makeNode({ id: "n-conflict", label: "Conflicting churn claim", description: "Need to resolve the inconsistency because the current figures contradict each other.", kind: "unknown", status: "unknown", confidence: "medium", }); const contradiction = makeNode({ id: "n-contradiction", label: "Contradicted report", description: "Two sources disagree about churn.", kind: "conclusion", status: "contradicted", confidence: "low", childIds: [unknown.id], }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown, { nodes: [contradiction] }), }); expect(result.strategy).toBe("contradiction_resolution"); expect(result.reasoningPattern).toBe("contradiction"); expect(result.question).toContain("resolve the contradiction"); }); it("reasoning pattern selection marks commercial validation as decision rather than explanation", () => { const unknown = makeNode({ id: "n-commercial-pattern", 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 more, we need to know whether continuing development is commercially justified.", }); const result = selectReasoningPattern({ node: unknown, graph }); expect(result.pattern).toBe("decision"); }); it("comparison scenario selects the comparison pattern", () => { const unknown = makeNode({ id: "n-comparison-pattern", label: "How the two observations were measured", description: "Need evidence about the measure used for each observation, because that could help explain the difference.", kind: "unknown", status: "unknown", confidence: "medium", }); const graph = makeGraphFor(unknown, { centralStatement: "Traffic increased, but sales stayed flat.", nodes: [ makeNode({ id: "n-traffic-observation", label: "Traffic increased.", description: "Traffic increased.", kind: "observation", status: "supported", confidence: "high", }), makeNode({ id: "n-sales-observation", label: "Sales stayed flat.", description: "Sales stayed flat.", kind: "observation", status: "supported", confidence: "high", }), ], }); const result = selectReasoningPattern({ node: unknown, graph }); expect(result.pattern).toBe("comparison"); }); it("user-owned constraint ambiguity produces a clarification question rather than an evidence request", () => { const unknown = makeNode({ id: "n-constraint", label: "Whether avoiding additional risk is a hard constraint", description: "Need to know whether avoiding additional risk is a hard constraint or a preference/trade-off.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.strategy).toBeNull(); expect(result.question).toBe( "Is avoiding additional risk a hard constraint or a preference/trade-off?", ); }); it("60B.21 signing-status node does not route to decision_audience and preserves the proposition", () => { const unknown = makeNode({ id: "n-customer-signing-status", label: "Prospective enterprise customer signing status", description: "Uncertainty about whether the prospective enterprise customer will sign if we launch this year, so that its resolution is needed to decide which timing option provides superior net value.", kind: "unknown", status: "unknown", confidence: "medium", }); const graph = makeGraphFor(unknown, { centralStatement: "We need to decide which launch timing option provides superior net value.", }); const result = formulateQuestion({ node: unknown, graph }); expect(result.questionFamily).not.toBe("decision_foundation"); expect(result.selectedQuestionTemplate).not.toBe("decision_audience"); expect(result.question.toLowerCase()).toContain( "whether the prospective enterprise customer will sign if we launch this year", ); expect(result.question.toLowerCase()).not.toContain( "relevant customer, user, or value recipient", ); }); it("legitimate audience identity unknown still routes to decision_audience", () => { const unknown = makeNode({ id: "n-target-customer", label: "Who is the target customer?", description: "Need to know who the target customer is before continuing development.", kind: "unknown", status: "unknown", confidence: "medium", }); const graph = makeGraphFor(unknown, { centralStatement: "Before investing more, we need to know whether continuing development is commercially justified.", }); const result = formulateQuestion({ node: unknown, graph }); expect(result.questionFamily).toBe("decision_foundation"); expect(result.selectedQuestionTemplate).toBe("decision_audience"); expect(result.question).toBe("Who experiences this problem?"); }); it("customer as proposition subject does not imply audience family", () => { const unknown = makeNode({ id: "n-customer-renewal", label: "Customer renewal likelihood", description: "Uncertainty about whether the customer will renew next year, because that affects the decision.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.selectedQuestionTemplate).not.toBe("decision_audience"); expect(result.question.toLowerCase()).toContain( "whether the customer will renew next year", ); }); it("user as proposition subject does not imply audience family", () => { const unknown = makeNode({ id: "n-user-adoption", label: "User adoption uncertainty", description: "Uncertainty about whether users will adopt the change, because that affects the decision.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.selectedQuestionTemplate).not.toBe("decision_audience"); expect(result.question.toLowerCase()).toContain( "whether users will adopt the change", ); }); it("buyer or stakeholder lexical mentions do not automatically trigger audience discovery", () => { const unknown = makeNode({ id: "n-stakeholder-approval", label: "Stakeholder approval uncertainty", description: "Uncertainty about whether the stakeholder will approve the plan, because that affects the decision.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.selectedQuestionTemplate).not.toBe("decision_audience"); expect(result.question.toLowerCase()).toContain( "whether the stakeholder will approve the plan", ); }); it("existing direct interrogative decision behaviour is preserved", () => { const unknown = makeNode({ id: "n-client-leave", label: "Will our largest client leave if we relocate?", description: "Uncertainty regarding whether our largest client would depart following a relocation to Manchester; matters because their departure would cost approximately £5M per year.", kind: "unknown", status: "unknown", confidence: "medium", }); const graph = makeGraphFor(unknown, { centralStatement: "We need to decide whether relocating is commercially justified.", }); const result = formulateQuestion({ node: unknown, graph }); expect(result.question.toLowerCase()).toBe( "will our largest client leave if we relocate?", ); }); it("60B.24 regression strips whether-rationale and uses evidence framing without mutating the source node", () => { const description = "Whether one prospective enterprise customer will sign if we launch this year; they account for ~£700k of the £1.2M expected annual revenue, so that resolving their intent is needed to assess the financial impact of launching now."; const unknown = makeNode({ id: "n-60b24-signing-status", label: "Prospective enterprise customer signing status", description, kind: "unknown", status: "unknown", confidence: "medium", }); const graph = makeGraphFor(unknown, { centralStatement: "We need to decide which launch timing option provides superior net value.", }); const result = formulateQuestion({ node: unknown, graph }); expect(result.question).toContain( "whether one prospective enterprise customer will sign if we launch this year", ); expect(result.question).toContain("What evidence would clarify"); expect(result.question).not.toContain("£700k"); expect(result.question).not.toContain("£1.2M"); expect(result.question).not.toContain("resolving their intent"); expect(result.question).not.toContain("financial impact"); expect(unknown.description).toBe(description); }); it("clean whether proposition uses evidence framing rather than a direct whether-question", () => { const unknown = makeNode({ id: "n-supplier-renewal", label: "Supplier renewal likelihood", description: "Whether the supplier will renew the contract.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.question).toBe( "What evidence would clarify whether the supplier will renew the contract?", ); expect(result.question).not.toBe( "Whether the supplier will renew the contract?", ); }); it("wh-question remains unchanged", () => { const unknown = makeNode({ id: "n-wh-question", label: "What would change the preferred option?", description: "What would change the preferred option?", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.question).toBe("What would change the preferred option?"); }); it("non-whether semicolon content is not globally truncated", () => { const unknown = makeNode({ id: "n-semicolon-baseline", label: "Unknown baseline measurement basis; current and previous figures were prepared differently.", description: "Baseline measurement basis; current and previous figures were prepared differently.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.question).toContain( "baseline measurement basis; current and previous figures were prepared differently", ); expect(result.question).not.toContain("What would clarify whether"); }); it("evidence-resolvable competing-cause unknown stays on an evidence route rather than neutral clarification", () => { const unknown = makeNode({ id: "n-delivery-cause", label: "Possible causes of the delivery delay", description: "Need to determine whether staff capacity or supplier lead times are responsible for the delivery delay.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown, { centralStatement: "Delivery is delayed and the cause is still unknown.", }), }); expect(result.reasoningPattern).toBe("diagnosis"); expect(result.question).toContain("What evidence"); expect(result.question).not.toContain("What would clarify"); }); it("the same unknown can produce different questions when paired with different strategies", () => { const thresholdUnknown = makeNode({ id: "n-threshold-unknown", label: "Value threshold", description: "Need to resolve the value threshold.", kind: "unknown", status: "unknown", confidence: "high", }); const definitionUnknown = makeNode({ id: "n-definition-unknown", label: "Value term", description: "Need to resolve what value term refers to in this context.", kind: "unknown", status: "unknown", confidence: "high", }); const decisionGraph = makeGraphFor(thresholdUnknown, { centralStatement: "We are deciding whether to launch this product.", nodes: [ makeNode({ id: "n-decision", label: "Launch decision", description: "Decision depends on the value threshold.", kind: "state", status: "known", confidence: "medium", childIds: [thresholdUnknown.id], value: "Deciding whether to launch the product", }), ], }); const definitionGraph = makeGraphFor(definitionUnknown, { centralStatement: "The team uses the term value threshold inconsistently.", nodes: [ makeNode({ id: "n-definition", label: "Definition disagreement about value threshold", description: "Need a definition of value threshold because the term is used inconsistently before comparing options.", kind: "state", status: "known", confidence: "medium", childIds: [definitionUnknown.id], }), ], }); const decisionResult = formulateQuestion({ node: thresholdUnknown, graph: decisionGraph, }); const definitionResult = formulateQuestion({ node: definitionUnknown, graph: definitionGraph, }); expect(decisionResult.strategy).toBe("decision_threshold"); expect(definitionResult.strategy).toBe("definition"); expect(decisionResult.question).not.toBe(definitionResult.question); }); it("strategy selection is deterministic and explainable", () => { const unknown = makeNode({ id: "n-threshold", label: "Success threshold", description: "Need the success threshold because the decision depends on it.", kind: "unknown", status: "unknown", confidence: "high", }); const graph = makeGraphFor(unknown, { centralStatement: "We need to decide whether to continue investing.", }); const first = selectInvestigationStrategy({ node: unknown, graph }); const second = selectInvestigationStrategy({ node: unknown, graph }); expect(first).toEqual(second); expect(first.key).toBe("decision_threshold"); expect(first.reason).toContain("threshold"); }); it("question is singular and answerable", () => { const unknown = makeNode({ id: "n-evidence", label: "Evidence of demand", description: "Need evidence of demand because the decision depends on it.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.question.match(/\?/g) || []).toHaveLength(1); expect(result.question.toLowerCase()).not.toContain(" and "); }); it("awkward uncertainty phrasing is rejected via fallback", () => { const unknown = makeNode({ id: "n-weird", label: "Uncertainty regarding service reliability", description: "Unknown service reliability.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.question).not.toContain("How should uncertainty regarding"); expect(result.question).not.toContain( "What would resolve uncertainty regarding", ); }); it("ambiguous contradiction produces a broad distinguishing question without accounting jargon", () => { const unknown = makeNode({ id: "n-cause-a", label: "Cash outflow cause", description: "Unclear explanation for the contradiction.", kind: "unknown", status: "unknown", confidence: "high", }); const contradiction = makeNode({ id: "n-contradiction", label: "Divergent movement between revenue and cash", description: "Two signals moved in opposite directions.", kind: "relationship", status: "supported", confidence: "medium", }); const revenueObservation = makeNode({ id: "n-revenue-observation", label: "Revenue increased by 18%.", description: "Revenue increased by 18%.", kind: "observation", status: "supported", confidence: "high", }); const cashObservation = makeNode({ id: "n-cash-observation", label: "Cash in the bank decreased over the same period.", description: "Cash in the bank decreased over the same period.", kind: "observation", status: "supported", confidence: "high", }); const graph = makeGraphFor(unknown, { centralStatement: "Revenue increased by 18%, but cash in the bank fell over the same period.", nodes: [contradiction, revenueObservation, cashObservation], }); const result = formulateTieResolutionQuestion({ graph }); expect(result.question).toBe( "Were these figures measured on the same basis and at the same scale?", ); expect(result.comparabilityStatus).toBe("uncertain"); expect(result.question.toLowerCase()).not.toMatch( /accounts receivable|capex|debt repayments|working capital/, ); }); it("definition is selected only for genuine definition unknowns", () => { const unknown = makeNode({ id: "n-definition-only", label: "Definition of success criteria", description: "The term is used inconsistently and needs a definition.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.strategy).toBe("definition"); }); it("an unknown about possible causes does not become a definition question", () => { const unknown = makeNode({ id: "n-causes", label: "Possible causes of the divergence", description: "Several causes may explain the divergence.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.reasoningPattern).toBe("diagnosis"); expect(result.strategy).toBeNull(); expect(result.question).toBe( "What would clarify possible causes of the divergence in this situation?", ); }); it("malformed punctuation is rejected", () => { const unknown = makeNode({ id: "n-punct", label: "Magnitude and nature of cash outflows (operating expenses).", description: "Magnitude and nature of cash outflows (operating expenses).", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.question).not.toContain("). is true?"); expect(result.question).toBe( "What would clarify magnitude and nature of cash outflows (operating expenses) in this situation?", ); }); // ── 60B.28 / 60B.30: uncertainty-prefix coverage ─────────────────── it("60B.27 regression: 'Unknown whether...' preserves full proposition", () => { const unknown = makeNode({ id: "unc-60b27", label: "Prospective enterprise customer signing likelihood", description: "Unknown whether one prospective enterprise customer will sign if we launch this year, so that the remaining £700k of the expected £1.2M annual revenue is realized.", kind: "unknown", status: "unknown", confidence: "medium", }); const graph = makeGraphFor(unknown, { centralStatement: "We need to decide which launch timing option provides superior net value.", }); const result = formulateQuestion({ node: unknown, graph }); expect(result.question).toBe( "What evidence would clarify whether one prospective enterprise customer will sign if we launch this year?", ); // Rationale must NOT leak into the final question expect(result.question).not.toContain("£700k"); expect(result.question).not.toContain("£1.2M"); expect(result.question.toLowerCase()).not.toContain("annual revenue"); }); it("'Uncertain whether...' exposes the full proposition with evidence framing", () => { const unknown = makeNode({ id: "unc-uncertain", label: "Supplier renewal uncertainty", description: "Uncertain whether the supplier will renew, because the contract is still under review.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.question).toBe( "What evidence would clarify whether the supplier will renew?", ); }); it("60B.29 regression: 'Uncertainty over whether...' preserves full proposition", () => { const unknown = makeNode({ id: "unc-60b29", label: "Prospective enterprise customer signing status", description: "Uncertainty over whether the prospective enterprise customer will sign if we launch this year, because their contract accounts for approximately £700,000 of the expected first-year revenue and could materially flip the net-value comparison.", kind: "unknown", status: "unknown", confidence: "medium", }); const graph = makeGraphFor(unknown, { centralStatement: "We need to decide which launch timing option provides superior net value.", }); const result = formulateQuestion({ node: unknown, graph }); expect(result.question).toBe( "What evidence would clarify whether the prospective enterprise customer will sign if we launch this year?", ); expect(result.question).not.toContain("£700,000"); expect(result.question).not.toContain("expected first-year revenue"); expect(result.question).not.toContain("materially flip"); expect(result.question).not.toContain("because their contract"); }); it("'Uncertainty over whether...' without rationale uses evidence framing", () => { const unknown = makeNode({ id: "unc-over", label: "Supplier renewal status", description: "Uncertainty over whether the supplier will renew.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.question).toBe( "What evidence would clarify whether the supplier will renew?", ); }); it("bare 'Whether...' remains unchanged (existing behaviour)", () => { const unknown = makeNode({ id: "unc-bare-whether", label: "Supplier renewal likelihood", description: "Whether the supplier will renew the contract.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.question).toBe( "What evidence would clarify whether the supplier will renew the contract?", ); }); it("'Uncertainty about whether...' remains unchanged (existing behaviour)", () => { const unknown = makeNode({ id: "unc-about", label: "Customer renewal likelihood", description: "Uncertainty about whether the customer will renew next year, because that affects the decision.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.question.toLowerCase()).toContain( "whether the customer will renew next year", ); }); it("'Uncertainty regarding whether...' remains unchanged (existing behaviour)", () => { const unknown = makeNode({ id: "unc-regarding", label: "Client retention uncertainty", description: "Uncertainty regarding whether our largest client would depart following a relocation to Manchester; matters because their departure would cost approximately £5M per year.", kind: "unknown", status: "unknown", confidence: "medium", }); const graph = makeGraphFor(unknown, { centralStatement: "We need to decide whether relocating is commercially justified.", }); const result = formulateQuestion({ node: unknown, graph }); expect(result.question.toLowerCase()).toContain( "whether our largest client would depart following a relocation to manchester", ); }); it("direct interrogative label remains direct", () => { const unknown = makeNode({ id: "unc-direct", label: "Will our largest client leave if we relocate?", description: "Uncertainty regarding whether our largest client would depart following a relocation to Manchester; matters because their departure would cost approximately £5M per year.", kind: "unknown", status: "unknown", confidence: "medium", }); const graph = makeGraphFor(unknown, { centralStatement: "We need to decide whether relocating is commercially justified.", }); const result = formulateQuestion({ node: unknown, graph }); expect(result.question).toBe( "Will our largest client leave if we relocate?", ); }); it("nominal label without explicit 'whether...' falls back to label-based extraction", () => { const unknown = makeNode({ id: "unc-nominal", label: "Service reliability uncertainty", description: "Unknown service reliability.", kind: "unknown", status: "unknown", confidence: "medium", }); const result = formulateQuestion({ node: unknown, graph: makeGraphFor(unknown), }); expect(result.question).not.toContain("How should uncertainty regarding"); }); it("source description is never mutated by question formulation", () => { const description = "Unknown whether one prospective enterprise customer will sign if we launch this year, so that the remaining £700k of the expected £1.2M annual revenue is realized."; const unknown = makeNode({ id: "unc-preserve", label: "Prospective enterprise customer signing likelihood", description, kind: "unknown", status: "unknown", confidence: "medium", }); const graph = makeGraphFor(unknown, { centralStatement: "We need to decide which launch timing option provides superior net value.", }); formulateQuestion({ node: unknown, graph }); expect(unknown.description).toBe(description); }); });