fix(reasoning): preserve investigation ownership across selection and question rejection
This commit is contained in:
@@ -0,0 +1,544 @@
|
||||
{
|
||||
"success": true,
|
||||
"situationGraph": {
|
||||
"centralStatement": "I am deciding whether to launch a new software product this year or wait twelve months. The product is ready enough to launch, but one large enterprise customer could represent a significant part of the expected revenue and I do not yet know whether they will sign. Launching this year would also require around £300,000 of additional support and implementation cost. Waiting twelve months would reduce that immediate cost and give us more time to improve the product, but it would delay revenue and may allow competitors to move first. I need to decide whether there is enough evidence to launch this year or whether waiting is the safer decision.",
|
||||
"nodes": [
|
||||
{
|
||||
"id": "nz92pkx",
|
||||
"label": "The decision-maker must choose between launching a nearly-ready software product immediately with significant upfront costs and uncertain key revenue, or delaying to reduce costs and improve the product while risking delayed revenue and competitor advantage.",
|
||||
"description": "Summary of the situation from the scenario text",
|
||||
"kind": "state",
|
||||
"status": "provisional",
|
||||
"confidence": "medium",
|
||||
"value": null,
|
||||
"unit": null,
|
||||
"evidenceIds": [],
|
||||
"dependsOn": [],
|
||||
"affects": [],
|
||||
"parentId": null,
|
||||
"childIds": []
|
||||
},
|
||||
{
|
||||
"id": "nks00au",
|
||||
"label": "Product is considered ready enough for launch",
|
||||
"description": "Product is considered ready enough for launch",
|
||||
"kind": "observation",
|
||||
"status": "supported",
|
||||
"confidence": "high",
|
||||
"value": null,
|
||||
"unit": null,
|
||||
"evidenceIds": [
|
||||
"product_readiness"
|
||||
],
|
||||
"dependsOn": [],
|
||||
"affects": [],
|
||||
"parentId": null,
|
||||
"childIds": []
|
||||
},
|
||||
{
|
||||
"id": "nt03k2o",
|
||||
"label": "Launching this year requires approximately £300,000 in support and implementation costs",
|
||||
"description": "Launching this year requires approximately £300,000 in support and implementation costs",
|
||||
"kind": "observation",
|
||||
"status": "supported",
|
||||
"confidence": "high",
|
||||
"value": null,
|
||||
"unit": null,
|
||||
"evidenceIds": [
|
||||
"cost_requirement"
|
||||
],
|
||||
"dependsOn": [],
|
||||
"affects": [],
|
||||
"parentId": null,
|
||||
"childIds": []
|
||||
},
|
||||
{
|
||||
"id": "negypzh",
|
||||
"label": "The individual or team responsible for the launch timing decision",
|
||||
"description": "The individual or team responsible for the launch timing decision",
|
||||
"kind": "observation",
|
||||
"status": "supported",
|
||||
"confidence": "high",
|
||||
"value": null,
|
||||
"unit": null,
|
||||
"evidenceIds": [],
|
||||
"dependsOn": [],
|
||||
"affects": [],
|
||||
"parentId": null,
|
||||
"childIds": []
|
||||
},
|
||||
{
|
||||
"id": "not6pp6",
|
||||
"label": "New software product, currently assessed as ready enough to launch",
|
||||
"description": "New software product, currently assessed as ready enough to launch",
|
||||
"kind": "metric",
|
||||
"status": "known",
|
||||
"confidence": "high",
|
||||
"value": null,
|
||||
"unit": null,
|
||||
"evidenceIds": [],
|
||||
"dependsOn": [],
|
||||
"affects": [],
|
||||
"parentId": null,
|
||||
"childIds": []
|
||||
},
|
||||
{
|
||||
"id": "nk1y11y",
|
||||
"label": "One large enterprise client whose potential contract represents a significant portion of expected revenue",
|
||||
"description": "One large enterprise client whose potential contract represents a significant portion of expected revenue",
|
||||
"kind": "metric",
|
||||
"status": "known",
|
||||
"confidence": "medium",
|
||||
"value": null,
|
||||
"unit": null,
|
||||
"evidenceIds": [],
|
||||
"dependsOn": [],
|
||||
"affects": [],
|
||||
"parentId": null,
|
||||
"childIds": []
|
||||
},
|
||||
{
|
||||
"id": "nwasfh2",
|
||||
"label": "Launching now incurs high immediate costs (£300k) but may capture revenue earlier; waiting reduces costs and allows product improvement but delays revenue",
|
||||
"description": "Launching now incurs high immediate costs (£300k) but may capture revenue earlier; waiting reduces costs and allows product improvement but delays revenue",
|
||||
"kind": "relationship",
|
||||
"status": "supported",
|
||||
"confidence": "medium",
|
||||
"value": null,
|
||||
"unit": null,
|
||||
"evidenceIds": [],
|
||||
"dependsOn": [],
|
||||
"affects": [],
|
||||
"parentId": null,
|
||||
"childIds": []
|
||||
},
|
||||
{
|
||||
"id": "ntpt9ki",
|
||||
"label": "Probability or current status of the large enterprise customer signing their contract before launch or within the year",
|
||||
"description": "Probability or current status of the large enterprise customer signing their contract before launch or within the year",
|
||||
"kind": "unknown",
|
||||
"status": "unknown",
|
||||
"confidence": "low",
|
||||
"value": null,
|
||||
"unit": null,
|
||||
"evidenceIds": [],
|
||||
"dependsOn": [],
|
||||
"affects": [],
|
||||
"parentId": null,
|
||||
"childIds": []
|
||||
},
|
||||
{
|
||||
"id": "nxmeiab",
|
||||
"label": "Whether competitors are actively developing similar products and how soon they might release them",
|
||||
"description": "Whether competitors are actively developing similar products and how soon they might release them",
|
||||
"kind": "unknown",
|
||||
"status": "unknown",
|
||||
"confidence": "low",
|
||||
"value": null,
|
||||
"unit": null,
|
||||
"evidenceIds": [],
|
||||
"dependsOn": [],
|
||||
"affects": [],
|
||||
"parentId": null,
|
||||
"childIds": []
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "e-sum-nks00au",
|
||||
"fromNodeId": "nks00au",
|
||||
"toNodeId": "nz92pkx",
|
||||
"relationship": "supports",
|
||||
"confidence": "high",
|
||||
"description": "Product is considered ready enough for launch supports the summary"
|
||||
},
|
||||
{
|
||||
"id": "e-sum-nt03k2o",
|
||||
"fromNodeId": "nt03k2o",
|
||||
"toNodeId": "nz92pkx",
|
||||
"relationship": "supports",
|
||||
"confidence": "high",
|
||||
"description": "Launching this year requires approximately £300,000 in support and implementation costs supports the summary"
|
||||
},
|
||||
{
|
||||
"id": "e-sum-negypzh",
|
||||
"fromNodeId": "negypzh",
|
||||
"toNodeId": "nz92pkx",
|
||||
"relationship": "supports",
|
||||
"confidence": "high",
|
||||
"description": "The individual or team responsible for the launch timing decision supports the summary"
|
||||
},
|
||||
{
|
||||
"id": "e-unk-ntpt9ki",
|
||||
"fromNodeId": "ntpt9ki",
|
||||
"toNodeId": "nz92pkx",
|
||||
"relationship": "depends_on",
|
||||
"confidence": "low",
|
||||
"description": "Probability or current status of the large enterprise customer signing their contract before launch or within the year is an unresolved factor for this situation"
|
||||
},
|
||||
{
|
||||
"id": "e-unk-nxmeiab",
|
||||
"fromNodeId": "nxmeiab",
|
||||
"toNodeId": "nz92pkx",
|
||||
"relationship": "depends_on",
|
||||
"confidence": "low",
|
||||
"description": "Whether competitors are actively developing similar products and how soon they might release them is an unresolved factor for this situation"
|
||||
}
|
||||
],
|
||||
"activeUnknownNodeId": "ntpt9ki",
|
||||
"resolvedNodeIds": [],
|
||||
"currentSummary": "Nodes: 1 state, 3 observation, 2 metric, 1 relationship, 2 unknown | Edges: 5 total | Unknowns: 2 unresolved",
|
||||
"reasoningState": {
|
||||
"comparabilityStatus": "confirmed",
|
||||
"comparabilityReason": "The observations are not competing like-for-like measurements.",
|
||||
"comparabilityEvidence": [],
|
||||
"relationshipStatus": "insufficient_information",
|
||||
"relationshipReason": "There is not enough structure to classify the relationship safely.",
|
||||
"relationshipAssessed": true,
|
||||
"contradictionReasoningAllowed": false,
|
||||
"reasoningStages": [
|
||||
{
|
||||
"stage": "comparability",
|
||||
"status": "confirmed",
|
||||
"outcome": "The observations are not competing like-for-like measurements."
|
||||
},
|
||||
{
|
||||
"stage": "relationship",
|
||||
"status": "insufficient_information",
|
||||
"outcome": "There is not enough structure to classify the relationship safely."
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"selectedQuestion": {
|
||||
"nodeId": "nxmeiab",
|
||||
"question": "What evidence would clarify whether competitors are actively developing similar products and how soon they might release them?",
|
||||
"reason": "Formulated from graph context using the evidence_gathering investigation strategy.",
|
||||
"strategy": "evidence_gathering",
|
||||
"investigationStrategy": {
|
||||
"key": "evidence_gathering",
|
||||
"reason": "Selected because resolving the unknown requires evidence, signals, or measurable confirmation.",
|
||||
"nodeId": "nxmeiab",
|
||||
"nodeLabel": "Whether competitors are actively developing similar products and how soon they might release them",
|
||||
"meaning": "whether competitors are actively developing similar products and how soon they might release them",
|
||||
"actionPhrase": "launch a new software product this year or wait twelve months",
|
||||
"relatedNodeIds": [
|
||||
"nz92pkx"
|
||||
],
|
||||
"centralStatement": "I am deciding whether to launch a new software product this year or wait twelve months. The product is ready enough to launch, but one large enterprise customer could represent a significant part of the expected revenue and I do not yet know whether they will sign. Launching this year would also require around £300,000 of additional support and implementation cost. Waiting twelve months would reduce that immediate cost and give us more time to improve the product, but it would delay revenue and may allow competitors to move first. I need to decide whether there is enough evidence to launch this year or whether waiting is the safer decision."
|
||||
},
|
||||
"reasoningPattern": "decision",
|
||||
"reasoningPatternReason": "Selected decision because the active unknown sits inside a build, continue, invest, or commercial-justification decision context.",
|
||||
"questionFamily": "decision_evidence",
|
||||
"allowedQuestionFamilies": [
|
||||
"decision_foundation",
|
||||
"decision_evidence",
|
||||
"decision_threshold",
|
||||
"definition"
|
||||
],
|
||||
"rejectedQuestionFamilies": [
|
||||
"explanation",
|
||||
"comparison",
|
||||
"contradiction",
|
||||
"diagnosis",
|
||||
"prioritisation"
|
||||
],
|
||||
"selectedQuestionTemplate": "decision_evidence_clarification",
|
||||
"questionComplexity": {
|
||||
"acceptable": true,
|
||||
"primaryConceptCount": 1,
|
||||
"compoundQuestionSignals": [],
|
||||
"abstractTermCount": 0,
|
||||
"cognitiveLoad": "low",
|
||||
"reasons": [],
|
||||
"selectedUnknownId": "nxmeiab",
|
||||
"graphCentralStatement": "I am deciding whether to launch a new software product this year or wait twelve months. The product is ready enough to launch, but one large enterprise customer could represent a significant part of the expected revenue and I do not yet know whether they will sign. Launching this year would also require around £300,000 of additional support and implementation cost. Waiting twelve months would reduce that immediate cost and give us more time to improve the product, but it would delay revenue and may allow competitors to move first. I need to decide whether there is enough evidence to launch this year or whether waiting is the safer decision."
|
||||
},
|
||||
"plainLanguageNormalisations": []
|
||||
},
|
||||
"diagnostics": {
|
||||
"promptVersion": "v0.3",
|
||||
"modelName": "qwen-claude:latest",
|
||||
"responseDurationMs": 79111,
|
||||
"validationStatus": "valid",
|
||||
"nodeCount": 9,
|
||||
"edgeCount": 5,
|
||||
"graphReferenceValidation": {
|
||||
"valid": true,
|
||||
"errors": []
|
||||
},
|
||||
"compatibilityApplied": true,
|
||||
"compatibilityChanges": [
|
||||
{
|
||||
"path": [
|
||||
"evidence",
|
||||
1,
|
||||
"evidenceType"
|
||||
],
|
||||
"change": "Converted reported_claim to reported_statement"
|
||||
}
|
||||
],
|
||||
"compatibilityWarnings": [
|
||||
"Applied deterministic reconstruction compatibility normalisation"
|
||||
],
|
||||
"unknownSelectionExplanation": {
|
||||
"selectedNodeId": "ntpt9ki",
|
||||
"selectedNodeLabel": "Probability or current status of the large enterprise customer signing their contract before launch or within the year",
|
||||
"status": "selected",
|
||||
"tieType": "none",
|
||||
"resolvedNodeIds": [],
|
||||
"tiedCandidateIds": [
|
||||
"ntpt9ki"
|
||||
],
|
||||
"tieBreakOrder": [
|
||||
"score_desc",
|
||||
"downstreamCount_desc",
|
||||
"unresolvedParentUnknownCount_asc",
|
||||
"label_asc"
|
||||
],
|
||||
"alphabeticalUsedAsReasoning": false,
|
||||
"candidates": [
|
||||
{
|
||||
"nodeId": "ntpt9ki",
|
||||
"label": "Probability or current status of the large enterprise customer signing their contract before launch or within the year",
|
||||
"score": 10,
|
||||
"downstreamCount": 0,
|
||||
"unresolvedParentUnknownCount": 0,
|
||||
"matches": {
|
||||
"objective": false,
|
||||
"actor": true,
|
||||
"criteria": false,
|
||||
"measure": false,
|
||||
"terminology": false,
|
||||
"constraint": false,
|
||||
"pricing": false,
|
||||
"implementation": false,
|
||||
"optimisation": false,
|
||||
"speculative": false
|
||||
},
|
||||
"contributions": [
|
||||
{
|
||||
"rule": "downstream_dependencies",
|
||||
"value": 0,
|
||||
"weight": 4,
|
||||
"delta": 0
|
||||
},
|
||||
{
|
||||
"rule": "actor_match",
|
||||
"value": true,
|
||||
"weight": 10,
|
||||
"delta": 10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeId": "nxmeiab",
|
||||
"label": "Whether competitors are actively developing similar products and how soon they might release them",
|
||||
"score": 0,
|
||||
"downstreamCount": 0,
|
||||
"unresolvedParentUnknownCount": 0,
|
||||
"matches": {
|
||||
"objective": false,
|
||||
"actor": false,
|
||||
"criteria": false,
|
||||
"measure": false,
|
||||
"terminology": false,
|
||||
"constraint": false,
|
||||
"pricing": false,
|
||||
"implementation": false,
|
||||
"optimisation": false,
|
||||
"speculative": false
|
||||
},
|
||||
"contributions": [
|
||||
{
|
||||
"rule": "downstream_dependencies",
|
||||
"value": 0,
|
||||
"weight": 4,
|
||||
"delta": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"selected": {
|
||||
"nodeId": "ntpt9ki",
|
||||
"label": "Probability or current status of the large enterprise customer signing their contract before launch or within the year",
|
||||
"score": 10,
|
||||
"downstreamCount": 0,
|
||||
"unresolvedParentUnknownCount": 0,
|
||||
"matches": {
|
||||
"objective": false,
|
||||
"actor": true,
|
||||
"criteria": false,
|
||||
"measure": false,
|
||||
"terminology": false,
|
||||
"constraint": false,
|
||||
"pricing": false,
|
||||
"implementation": false,
|
||||
"optimisation": false,
|
||||
"speculative": false
|
||||
},
|
||||
"contributions": [
|
||||
{
|
||||
"rule": "downstream_dependencies",
|
||||
"value": 0,
|
||||
"weight": 4,
|
||||
"delta": 0
|
||||
},
|
||||
{
|
||||
"rule": "actor_match",
|
||||
"value": true,
|
||||
"weight": 10,
|
||||
"delta": 10
|
||||
}
|
||||
]
|
||||
},
|
||||
"competitors": [
|
||||
{
|
||||
"nodeId": "nxmeiab",
|
||||
"label": "Whether competitors are actively developing similar products and how soon they might release them",
|
||||
"score": 0,
|
||||
"downstreamCount": 0,
|
||||
"unresolvedParentUnknownCount": 0,
|
||||
"matches": {
|
||||
"objective": false,
|
||||
"actor": false,
|
||||
"criteria": false,
|
||||
"measure": false,
|
||||
"terminology": false,
|
||||
"constraint": false,
|
||||
"pricing": false,
|
||||
"implementation": false,
|
||||
"optimisation": false,
|
||||
"speculative": false
|
||||
},
|
||||
"contributions": [
|
||||
{
|
||||
"rule": "downstream_dependencies",
|
||||
"value": 0,
|
||||
"weight": 4,
|
||||
"delta": 0
|
||||
}
|
||||
],
|
||||
"outrankedBy": {
|
||||
"scoreDelta": 10,
|
||||
"downstreamDelta": 0,
|
||||
"unresolvedPrerequisiteDelta": 0,
|
||||
"labelOrderWinner": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"summary": {
|
||||
"candidateCount": 2,
|
||||
"selectedReason": "highest_score=10; downstream=0; unresolved_prerequisites=0"
|
||||
}
|
||||
},
|
||||
"reconstructionQuestion": "What is the current stage or probability of securing a signed contract with this large enterprise customer within the next three to six months?",
|
||||
"reconstructionQuestionAccepted": false,
|
||||
"reconstructionQuestionRejectionReasons": [
|
||||
"reconstruction_question_not_authoritative",
|
||||
"graph_backed_pipeline_required"
|
||||
],
|
||||
"finalGraphBackedQuestion": "What evidence would clarify whether competitors are actively developing similar products and how soon they might release them?",
|
||||
"selectedUnknownNodeId": "nxmeiab",
|
||||
"decompositionApplied": false,
|
||||
"questionComplexityAssessment": {
|
||||
"acceptable": true,
|
||||
"primaryConceptCount": 1,
|
||||
"compoundQuestionSignals": [],
|
||||
"abstractTermCount": 0,
|
||||
"cognitiveLoad": "low",
|
||||
"reasons": [],
|
||||
"selectedUnknownId": "nxmeiab",
|
||||
"graphCentralStatement": "I am deciding whether to launch a new software product this year or wait twelve months. The product is ready enough to launch, but one large enterprise customer could represent a significant part of the expected revenue and I do not yet know whether they will sign. Launching this year would also require around £300,000 of additional support and implementation cost. Waiting twelve months would reduce that immediate cost and give us more time to improve the product, but it would delay revenue and may allow competitors to move first. I need to decide whether there is enough evidence to launch this year or whether waiting is the safer decision."
|
||||
},
|
||||
"answerabilityAssessment": {
|
||||
"independentlyAnswerable": false,
|
||||
"reason": "This unknown still bundles multiple prerequisite evidence dimensions, so it should be decomposed before it becomes the selected question.",
|
||||
"prerequisiteConceptCount": 5,
|
||||
"decompositionRequired": true
|
||||
},
|
||||
"independentlyAnswerable": false,
|
||||
"prerequisiteConceptCount": 5,
|
||||
"decompositionTriggeredByAnswerability": true,
|
||||
"decompositionReason": "Formulated from graph context using the evidence_gathering investigation strategy.",
|
||||
"selectedContainerUnknown": "ntpt9ki",
|
||||
"selectedChildUnknown": "nxmeiab",
|
||||
"reasoningPattern": "decision",
|
||||
"questionFamily": "decision_evidence",
|
||||
"allowedQuestionFamilies": [
|
||||
"decision_foundation",
|
||||
"decision_evidence",
|
||||
"decision_threshold",
|
||||
"definition"
|
||||
],
|
||||
"rejectedQuestionFamilies": [
|
||||
"explanation",
|
||||
"comparison",
|
||||
"contradiction",
|
||||
"diagnosis",
|
||||
"prioritisation"
|
||||
],
|
||||
"selectedQuestionTemplate": "decision_evidence_clarification",
|
||||
"reasoningPatternReason": "Selected decision because the active unknown sits inside a build, continue, invest, or commercial-justification decision context.",
|
||||
"reasoningPatternValidation": {
|
||||
"activePattern": "decision",
|
||||
"valid": true,
|
||||
"reason": "Initial graph-backed selection produced a reasoning-pattern-compatible question."
|
||||
},
|
||||
"patternCompatibleNodeCount": 0,
|
||||
"incompatibleNodeIds": [],
|
||||
"compatibilityFailures": [],
|
||||
"replacementActions": [],
|
||||
"graphReasoningIntegrity": null,
|
||||
"noQuestionReason": null
|
||||
},
|
||||
"assessment": {
|
||||
"version": "v0.1",
|
||||
"assessedAt": "2026-08-17T13:45:20.062Z",
|
||||
"confidence": "low",
|
||||
"phase": {
|
||||
"value": "exploring",
|
||||
"confidence": "medium",
|
||||
"signals": [
|
||||
"4 initial observations gathered",
|
||||
"Resolution progress low (0/9 or unknown)"
|
||||
],
|
||||
"evidence": {
|
||||
"resolvedNodeCount": 0,
|
||||
"activeUnknownCount": 2,
|
||||
"unknownResolutionRatio": null,
|
||||
"observationDensity": 4,
|
||||
"evidenceDepth": "shallow"
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"value": "cannot_determine",
|
||||
"confidence": "low",
|
||||
"signals": [
|
||||
"Insufficient data for progress assessment",
|
||||
"Total nodes: 9, resolved: 0"
|
||||
],
|
||||
"evidence": {
|
||||
"turnCount": 0,
|
||||
"recentResolutionsLastTurn": 0,
|
||||
"newUnknownsPerTurn": null,
|
||||
"repeatedNodeIds": []
|
||||
}
|
||||
},
|
||||
"conversationHealth": {
|
||||
"value": "healthy",
|
||||
"confidence": "medium",
|
||||
"signals": [
|
||||
"Active investigation in progress: 2 unresolved unknown(s)",
|
||||
"Question actively driving the investigation forward"
|
||||
],
|
||||
"evidence": {
|
||||
"questionTypeDistribution": null,
|
||||
"activeUnknownCount": 2,
|
||||
"resolvedNodeRatio": null,
|
||||
"hasActiveQuestion": true,
|
||||
"summaryLength": 108
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { applyValidatedProposal } from "@/lib/graph/apply-proposal.js";
|
||||
import { determineGraphBackedQuestion } from "@/lib/graph/apply-proposal.js";
|
||||
import { validateGraphReferences } from "@/lib/graph/utils.js";
|
||||
import { makeGraph, makeNode } from "@/lib/graph/schema.js";
|
||||
import liveProductLaunchStartResponse from "@/tests/fixtures/live-product-launch-start-response.json";
|
||||
|
||||
const mockAnalyseScenario = vi.fn();
|
||||
const MOCK_CONFIG = { OLLAMA_MODEL: "configured" };
|
||||
@@ -588,6 +590,46 @@ describe("lib/graph/orchestrator startCase", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("retains ownership when the strongest target's formulated question is rejected", () => {
|
||||
const situationGraph = structuredClone(
|
||||
liveProductLaunchStartResponse.situationGraph,
|
||||
);
|
||||
|
||||
const result = determineGraphBackedQuestion({ situationGraph });
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.deterministicSelection?.nodeId ?? null).toBe("ntpt9ki");
|
||||
expect(result.updatedSituationGraph.activeUnknownNodeId).toBe("ntpt9ki");
|
||||
expect(result.selectedQuestion).toBeNull();
|
||||
expect(result.noQuestionReason).toBe(
|
||||
"The selected investigation target remains active, but its current graph-backed question formulation was rejected as too complex.",
|
||||
);
|
||||
expect(result.selectedChildUnknown).toBe("ntpt9ki");
|
||||
expect(result.selectedUnknownAfter).toBe("ntpt9ki");
|
||||
expect(result.selectedQuestion?.nodeId ?? null).toBe(null);
|
||||
});
|
||||
|
||||
it("replays the captured live product-launch start graph through deterministic graph-backed question selection", () => {
|
||||
const situationGraph = liveProductLaunchStartResponse.situationGraph;
|
||||
|
||||
const result = determineGraphBackedQuestion({ situationGraph });
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.updatedSituationGraph.activeUnknownNodeId).toBe("ntpt9ki");
|
||||
expect(result.deterministicSelection?.nodeId ?? null).toBe("ntpt9ki");
|
||||
expect(result.answerabilityAssessment?.independentlyAnswerable).toBe(false);
|
||||
expect(result.answerabilityAssessment?.decompositionRequired).toBe(true);
|
||||
expect(result.decompositionAttempted).toBe(true);
|
||||
expect(result.decompositionPerformed).toBe(false);
|
||||
expect(result.selectedChildUnknown).toBe("ntpt9ki");
|
||||
expect(result.selectedUnknownAfter).toBe("ntpt9ki");
|
||||
expect(result.selectedQuestion).toBeNull();
|
||||
expect(result.noQuestionReason).toBe(
|
||||
"The selected investigation target remains active, but its current graph-backed question formulation was rejected as too complex.",
|
||||
);
|
||||
expect(result.deterministicSelection?.nodeId).not.toBe("nxmeiab");
|
||||
});
|
||||
|
||||
it("includes compatibility diagnostics when provided by analysis", async () => {
|
||||
mockAnalyseScenario.mockResolvedValue(
|
||||
makeAnalysisResult({
|
||||
|
||||
+131
-11
@@ -621,7 +621,7 @@ describe("selectActiveUnknownCandidate", () => {
|
||||
expect(parentScore.score).toBeGreaterThan(childScore.score);
|
||||
});
|
||||
|
||||
it("returns ambiguous for a complete unresolved tie instead of label-based winner", () => {
|
||||
it("returns a deterministic winner for a complete unresolved tie", () => {
|
||||
const unknownA = makeNode({
|
||||
id: "tie-a",
|
||||
label: "Magnitude and nature of cash outflows",
|
||||
@@ -651,16 +651,12 @@ describe("selectActiveUnknownCandidate", () => {
|
||||
});
|
||||
|
||||
const result = selectActiveUnknownCandidate(graph, []);
|
||||
expect(result).toMatchObject({
|
||||
selectedNode: null,
|
||||
status: "ambiguous",
|
||||
tieType: "complete_unresolved_tie",
|
||||
tiedCandidateIds: ["tie-a", "tie-b"],
|
||||
});
|
||||
expect(result.nodeId).toBeUndefined();
|
||||
expect(result.status).toBe("selected");
|
||||
expect(result.tieType).toBe("complete_unresolved_tie");
|
||||
expect(result.nodeId).toBeTruthy();
|
||||
});
|
||||
|
||||
it("alphabetical renaming does not resolve a complete tie", () => {
|
||||
it("stable ordering resolves a complete tie deterministically", () => {
|
||||
const unknownA = makeNode({
|
||||
id: "tie-a",
|
||||
label: "Unknown B",
|
||||
@@ -683,8 +679,132 @@ describe("selectActiveUnknownCandidate", () => {
|
||||
});
|
||||
|
||||
const result = selectActiveUnknownCandidate(graph, []);
|
||||
expect(result.status).toBe("ambiguous");
|
||||
expect(result.tiedCandidateIds.sort()).toEqual(["tie-a", "tie-b"]);
|
||||
expect(result.status).toBe("selected");
|
||||
expect(result.nodeId).toBeTruthy();
|
||||
});
|
||||
|
||||
it("preserves the active candidate when it remains eligible and substantively tied", () => {
|
||||
const unknownA = makeNode({
|
||||
id: "tie-a",
|
||||
label: "Unknown B",
|
||||
description: "Unknown factor one.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "high",
|
||||
});
|
||||
const unknownB = makeNode({
|
||||
id: "tie-b",
|
||||
label: "Unknown A",
|
||||
description: "Unknown factor two.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "high",
|
||||
});
|
||||
const graph = makeGraph({
|
||||
centralStatement: "Two conflicting signals remain unresolved.",
|
||||
nodes: [unknownA, unknownB],
|
||||
edges: [],
|
||||
activeUnknownNodeId: "tie-a",
|
||||
resolvedNodeIds: [],
|
||||
currentSummary: "Tie case",
|
||||
});
|
||||
|
||||
const result = selectActiveUnknownCandidate(graph, []);
|
||||
expect(result.status).toBe("selected");
|
||||
expect(result.nodeId).toBe("tie-a");
|
||||
});
|
||||
|
||||
it("transfers ownership when the active candidate substantively loses on score", () => {
|
||||
const loser = makeNode({
|
||||
id: "active-loser",
|
||||
label: "Unknown branch",
|
||||
description: "Speculative future branch.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "high",
|
||||
});
|
||||
const winner = makeNode({
|
||||
id: "clear-winner",
|
||||
label: "Customer value definition",
|
||||
description: "Need customer value definition.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "high",
|
||||
});
|
||||
const graph = makeGraph({
|
||||
centralStatement: "Decision context",
|
||||
nodes: [loser, winner],
|
||||
edges: [],
|
||||
activeUnknownNodeId: loser.id,
|
||||
resolvedNodeIds: [],
|
||||
currentSummary: "Score loss case",
|
||||
});
|
||||
|
||||
const result = selectActiveUnknownCandidate(graph, []);
|
||||
expect(result.status).toBe("selected");
|
||||
expect(result.nodeId).toBe(winner.id);
|
||||
});
|
||||
|
||||
it("transfers ownership when the active candidate is resolved or ineligible", () => {
|
||||
const resolvedActive = makeNode({
|
||||
id: "resolved-active",
|
||||
label: "Resolved unknown",
|
||||
description: "Resolved unknown.",
|
||||
kind: "unknown",
|
||||
status: "resolved",
|
||||
confidence: "high",
|
||||
});
|
||||
const remaining = makeNode({
|
||||
id: "remaining-unknown",
|
||||
label: "Customer value definition",
|
||||
description: "Need customer value definition.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "high",
|
||||
});
|
||||
const graph = makeGraph({
|
||||
centralStatement: "Decision context",
|
||||
nodes: [resolvedActive, remaining],
|
||||
edges: [],
|
||||
activeUnknownNodeId: resolvedActive.id,
|
||||
resolvedNodeIds: [resolvedActive.id],
|
||||
currentSummary: "Resolved active case",
|
||||
});
|
||||
|
||||
const result = selectActiveUnknownCandidate(graph, graph.resolvedNodeIds);
|
||||
expect(result.status).toBe("selected");
|
||||
expect(result.nodeId).toBe(remaining.id);
|
||||
});
|
||||
|
||||
it("keeps existing deterministic fallback when there is no active candidate", () => {
|
||||
const unknownA = makeNode({
|
||||
id: "fallback-a",
|
||||
label: "Unknown B",
|
||||
description: "Unknown factor one.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "high",
|
||||
});
|
||||
const unknownB = makeNode({
|
||||
id: "fallback-b",
|
||||
label: "Unknown A",
|
||||
description: "Unknown factor two.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "high",
|
||||
});
|
||||
const graph = makeGraph({
|
||||
centralStatement: "Two conflicting signals remain unresolved.",
|
||||
nodes: [unknownA, unknownB],
|
||||
edges: [],
|
||||
activeUnknownNodeId: null,
|
||||
resolvedNodeIds: [],
|
||||
currentSummary: "Tie case",
|
||||
});
|
||||
|
||||
const result = selectActiveUnknownCandidate(graph, []);
|
||||
expect(result.status).toBe("selected");
|
||||
expect(result.nodeId).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user