/** * Experiment 25A — Tests for assessEvidenceConditionScope. * * Validates scope classification (direct_match, partial_match, * different_timeframe, unrelated, cannot_determine) against explicit * conditions and evidence nodes. */ import { describe, expect, it } from "vitest"; import { assessEvidenceConditionScope } from "@/lib/graph/evidence-condition-scope.js"; import { buildScenarioFixture } from "@/lib/mocks/scenarios.js"; /* ── Helpers ─────────────────────────────────────────────── */ function makeNode(id, text) { return { id, description: text, label: text }; } const DEMAND_CONDITION = "Credible customer demand exists in Europe"; const COMPLIANCE_PRESENT = "The platform currently supports EU data residency requirements"; const COMPLIANCE_FUTURE = "European compliance can be achieved within an acceptable time and cost"; const VALUE_COST_CONDITION = "The expected market value justifies the cost of entry"; /* ── direct_match: present-state condition versus present evidence ─── */ describe("assessEvidenceConditionScope — direct_match", () => { it("returns direct_match for identical compliance subject in present state", () => { const evidence = makeNode( "obs-3", "Our platform does not currently support EU data residency requirements", ); const result = assessEvidenceConditionScope({ condition: { text: COMPLIANCE_PRESENT }, evidenceNode: evidence, }); expect(result.scope).toBe("direct_match"); }); it("returns direct_match for demand condition versus market evidence", () => { const evidence = makeNode( "obs-2", "The European analytics SaaS market is valued at approximately €8B and growing 15% annually", ); const result = assessEvidenceConditionScope({ condition: { text: DEMAND_CONDITION }, evidenceNode: evidence, }); expect(result.scope).toBe("direct_match"); }); it("returns direct_match when both condition and evidence use 'currently'", () => { const evidence = makeNode("t-1", "The platform already supports GDPR requirements and data residency"); const result = assessEvidenceConditionScope({ condition: { text: COMPLIANCE_PRESENT }, evidenceNode: evidence, }); expect(result.scope).toBe("direct_match"); }); it("returns direct_match using the long-investigation compliance example", () => { const fixture = buildScenarioFixture("long", 3); const graphNodes = fixture.situationGraph.nodes; const obs3Node = graphNodes.find((n) => n.id === "obs-3"); expect(obs3Node).toBeDefined(); const result = assessEvidenceConditionScope({ condition: { text: COMPLIANCE_PRESENT }, evidenceNode: obs3Node, }); expect(result.scope).toBe("direct_match"); }); it("returns direct_match for value-cost present-state condition", () => { const evidence = makeNode("v-1", "The total addressable market provides sufficient return on investment"); const result = assessEvidenceConditionScope({ condition: { text: "The platform currently offers sufficient financial viability" }, evidenceNode: evidence, }); expect(result.scope).toBe("direct_match"); }); }); /* ── different_timeframe: future condition versus present evidence ─── */ describe("assessEvidenceConditionScope — different_timeframe", () => { it("returns different_timeframe for compliance future condition versus current evidence", () => { const evidence = makeNode( "obs-3", "Our platform does not currently support EU data residency requirements", ); const result = assessEvidenceConditionScope({ condition: { text: COMPLIANCE_FUTURE }, evidenceNode: evidence, }); expect(result.scope).toBe("different_timeframe"); }); it("returns different_timeframe when evidence describes the present and condition uses 'can be achieved'", () => { const evidence = makeNode("t-2", "Our team currently has no EU regulatory expertise"); const result = assessEvidenceConditionScope({ condition: { text: "Can credible customer demand be achieved in Europe" }, evidenceNode: evidence, }); expect(result.scope).toBe("different_timeframe"); }); it("returns different_timeframe for value_cost future condition versus current evidence", () => { const evidence = makeNode("t-3", "The platform currently has no pricing data for Europe"); const result = assessEvidenceConditionScope({ condition: { text: "Can market value be achieved within acceptable cost" }, evidenceNode: evidence, }); expect(result.scope).toBe("different_timeframe"); }); }); /* ── partial_match: feasibility evidence versus future condition ─── */ describe("assessEvidenceConditionScope — partial_match", () => { it("returns partial_match for compliance feasibility evidence against future condition", () => { const evidence = makeNode( "obs-4", "Achieving compliance would require approximately six months and $500K", ); const result = assessEvidenceConditionScope({ condition: { text: COMPLIANCE_FUTURE }, evidenceNode: evidence, }); expect(result.scope).toBe("partial_match"); }); it("returns partial_match using the long-investigation value/cost example", () => { const fixture = buildScenarioFixture("long", 3); const graphNodes = fixture.situationGraph.nodes; const obs4Node = graphNodes.find((n) => n.id === "obs-4"); expect(obs4Node).toBeDefined(); const result = assessEvidenceConditionScope({ condition: { text: COMPLIANCE_FUTURE }, evidenceNode: obs4Node, }); expect(result.scope).toBe("partial_match"); }); it("returns partial_match for demand feasibility question", () => { const evidence = makeNode("t-4", "Entry would require approximately €2M marketing investment over three years"); const result = assessEvidenceConditionScope({ condition: { text: "Credible customer demand can be achieved within acceptable cost" }, evidenceNode: evidence, }); expect(result.scope).toBe("partial_match"); }); }); /* ── unrelated: different subjects ─────────────────────── */ describe("assessEvidenceConditionScope — unrelated", () => { it("returns unrelated when evidence is about market size but condition is about compliance", () => { const evidence = makeNode( "t-5", "European demand for analytics tools is increasing rapidly", ); const result = assessEvidenceConditionScope({ condition: { text: COMPLIANCE_PRESENT }, evidenceNode: evidence, }); expect(result.scope).toBe("unrelated"); }); it("returns unrelated when both subjects are completely different", () => { const evidence = makeNode("t-6", "The office lease expires in December 2026"); const result = assessEvidenceConditionScope({ condition: { text: DEMAND_CONDITION }, evidenceNode: evidence, }); expect(result.scope).toBe("unrelated"); }); }); /* ── cannot_determine: missing or unclear input ──────────── */ describe("assessEvidenceConditionScope — cannot_determine", () => { it("returns cannot_determine when condition is missing", () => { const result = assessEvidenceConditionScope({ evidenceNode: makeNode("t-1", "test") }); expect(result.scope).toBe("cannot_determine"); }); it("returns cannot_determine when condition is null", () => { const result = assessEvidenceConditionScope({ condition: null, evidenceNode: makeNode("t-1", "test") }); expect(result.scope).toBe("cannot_determine"); }); it("returns cannot_determine when evidenceNode is missing", () => { const result = assessEvidenceConditionScope({ condition: { text: DEMAND_CONDITION } }); expect(result.scope).toBe("cannot_determine"); }); it("returns cannot_determine when evidenceNode is null", () => { const result = assessEvidenceConditionScope({ condition: { text: DEMAND_CONDITION }, evidenceNode: null, }); expect(result.scope).toBe("cannot_determine"); }); it("returns cannot_determine when condition has empty text", () => { const result = assessEvidenceConditionScope({ condition: { text: "" }, evidenceNode: makeNode("t-1", "test"), }); expect(result.scope).toBe("cannot_determine"); }); it("returns cannot_determine when evidenceNode has empty description", () => { const result = assessEvidenceConditionScope({ condition: { text: DEMAND_CONDITION }, evidenceNode: makeNode("t-1", ""), }); expect(result.scope).toBe("cannot_determine"); }); it("returns cannot_determine when neither input is provided", () => { const result = assessEvidenceConditionScope({}); expect(result.scope).toBe("cannot_determine"); }); }); /* ── Deterministic output ───────────────────────────────── */ describe("assessEvidenceConditionScope — determinism", () => { it("returns identical results for identical inputs across multiple calls", () => { const evidence = makeNode("det-1", "European analytics market valued at €8B"); const input = { condition: { text: DEMAND_CONDITION }, evidenceNode: evidence, }; const r1 = assessEvidenceConditionScope(input); const r2 = assessEvidenceConditionScope(input); expect(r1).toEqual(r2); }); it("deterministic across 5 calls with long-investigation data", () => { const fixture = buildScenarioFixture("long", 3); const graphNodes = fixture.situationGraph.nodes; const obs3Node = graphNodes.find((n) => n.id === "obs-3"); const input = { condition: { text: COMPLIANCE_PRESENT }, evidenceNode: obs3Node, }; const results = [1, 2, 3, 4, 5].map(() => assessEvidenceConditionScope(input)); for (let i = 1; i < results.length; i++) { expect(results[i]).toEqual(results[0]); } }); }); /* ── Input immutability ─────────────────────────────────── */ describe("assessEvidenceConditionScope — input immutability", () => { it("does not mutate the condition object", () => { const cond = { text: DEMAND_CONDITION }; const originalText = cond.text; const evidence = makeNode("imm-1", "European market valued at €8B"); assessEvidenceConditionScope({ condition: cond, evidenceNode: evidence }); expect(cond.text).toBe(originalText); }); it("does not mutate the evidenceNode object", () => { const node = makeNode("imm-2", "test description"); const originalDesc = node.description; const condition = { text: DEMAND_CONDITION }; assessEvidenceConditionScope({ condition, evidenceNode: node }); expect(node.description).toBe(originalDesc); }); }); /* ── Four long-investigation examples from the brief ─────── */ describe("assessEvidenceConditionScope — required cases from long investigation", () => { it("compliance direct present-state match (condition vs obs-3)", () => { const fixture = buildScenarioFixture("long", 3); const graphNodes = fixture.situationGraph.nodes; const obs3Node = graphNodes.find((n) => n.id === "obs-3"); expect(obs3Node).toBeDefined(); const result = assessEvidenceConditionScope({ condition: { text: COMPLIANCE_PRESENT }, evidenceNode: obs3Node, }); expect(result.scope).toBe("direct_match"); }); it("future feasibility versus current compliance evidence", () => { const fixture = buildScenarioFixture("long", 3); const graphNodes = fixture.situationGraph.nodes; const obs3Node = graphNodes.find((n) => n.id === "obs-3"); expect(obs3Node).toBeDefined(); const result = assessEvidenceConditionScope({ condition: { text: COMPLIANCE_FUTURE }, evidenceNode: obs3Node, }); expect(result.scope).toBe("different_timeframe"); }); it("future feasibility versus implementation evidence (partial_match)", () => { const fixture = buildScenarioFixture("long", 3); const graphNodes = fixture.situationGraph.nodes; const obs4Node = graphNodes.find((n) => n.id === "obs-4"); expect(obs4Node).toBeDefined(); const result = assessEvidenceConditionScope({ condition: { text: COMPLIANCE_FUTURE }, evidenceNode: obs4Node, }); expect(result.scope).toBe("partial_match"); }); it("demand direct_match (obs-2)", () => { const fixture = buildScenarioFixture("long", 3); const graphNodes = fixture.situationGraph.nodes; const obs2Node = graphNodes.find((n) => n.id === "obs-2"); expect(obs2Node).toBeDefined(); const result = assessEvidenceConditionScope({ condition: { text: DEMAND_CONDITION }, evidenceNode: obs2Node, }); expect(result.scope).toBe("direct_match"); }); // ── Experiment 25B: actual fixture wording ──────────────── it("compliance condition 'is achievable' versus present-state evidence returns different_timeframe", () => { const result = assessEvidenceConditionScope({ condition: { text: "European compliance is achievable" }, evidenceNode: makeNode( "obs-3", "Our platform does not currently support EU data residency requirements", ), }); expect(result.scope).toBe("different_timeframe"); }); it("differentiation condition versus actual fixture evidence returns direct_match", () => { const result = assessEvidenceConditionScope({ condition: { text: "The product offers sufficient competitive differentiation" }, evidenceNode: makeNode( "obs-5", "Our real-time collaboration feature has no direct European equivalent and aligns with EU procurement trends", ), }); expect(result.scope).toBe("direct_match"); }); });