diff --git a/tests/e2e/manual-recorded-journey-live-capture.spec.js b/tests/e2e/manual-recorded-journey-live-capture.spec.js new file mode 100644 index 0000000..705769a --- /dev/null +++ b/tests/e2e/manual-recorded-journey-live-capture.spec.js @@ -0,0 +1,359 @@ +import { test, expect } from "@playwright/test"; +import * as fs from "node:fs"; +import * as path from "node:path"; + +const MODEL_RESPONSE_TIMEOUT = 120_000; + +test("live-capture second-update boundary", async ({ page }) => { + test.setTimeout(420_000); + + const timings = {}; + const captures = { + start: null, + update1: null, + update2: null, + }; + + async function readJson(response) { + try { + return await response.json(); + } catch { + return null; + } + } + + function readRequestJson(response) { + try { + return response.request().postDataJSON(); + } catch { + return null; + } + } + + async function captureResponse(response, startedAt) { + return { + url: response.url(), + status: response.status(), + elapsedMs: Date.now() - startedAt, + requestBody: readRequestJson(response), + responseBody: await readJson(response), + }; + } + + // ================================================================ + // AUTHORITATIVE MANUAL JOURNEY + // Browser actions, selectors, inputs and ordering are kept intact. + // Instrumentation is additive only. No mocks are enabled here. + // ================================================================ + + await page.goto("http://localhost:3000/"); + + await page.getByTestId("scenario-textarea").click(); + await page.getByTestId("scenario-textarea").click(); + await page + .getByTestId("scenario-textarea") + .fill( + "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.", + ); + + // ===== ANALYSE -> real POST /api/cases/start ===== + const startStartedAt = Date.now(); + + const startResponsePromise = page.waitForResponse( + (response) => + response.request().method() === "POST" && + response.url().includes("/api/cases/start"), + { timeout: MODEL_RESPONSE_TIMEOUT }, + ); + + await page.getByRole("button", { name: "Analyse" }).click(); + + const startResponse = await startResponsePromise; + captures.start = await captureResponse(startResponse, startStartedAt); + timings.startElapsedMs = captures.start.elapsedMs; + + console.log( + `[LIVE CAPTURE] start: status=${captures.start.status}, elapsed=${captures.start.elapsedMs}ms`, + ); + + // Do not move to the first answer until the real app has rendered it. + const responseTextarea = page.getByTestId("response-textarea"); + + await expect(responseTextarea).toBeVisible({ + timeout: MODEL_RESPONSE_TIMEOUT, + }); + + await responseTextarea.click(); + + await responseTextarea.fill( + "Launching this year would need to remain commercially viable without the enterprise customer. I would want to see enough committed or highly probable revenue from other customers to cover the additional £300,000 implementation and support cost and still produce an acceptable return.", + ); + + // ===== UPDATE 1 -> real POST /api/cases/update ===== + const update1StartedAt = Date.now(); + + const update1ResponsePromise = page.waitForResponse( + (response) => + response.request().method() === "POST" && + response.url().includes("/api/cases/update"), + { timeout: MODEL_RESPONSE_TIMEOUT }, + ); + + await page.getByRole("button", { name: "Update" }).click(); + + const update1Response = await update1ResponsePromise; + captures.update1 = await captureResponse(update1Response, update1StartedAt); + timings.update1ElapsedMs = captures.update1.elapsedMs; + + console.log( + `[LIVE CAPTURE] update 1: status=${captures.update1.status}, elapsed=${captures.update1.elapsedMs}ms`, + ); + + // Do not type the second answer until the real first update has rendered. + await expect(responseTextarea).toBeVisible({ + timeout: MODEL_RESPONSE_TIMEOUT, + }); + + await responseTextarea.click(); + + await responseTextarea.fill( + "We have £450,000 of annual recurring revenue already committed from other customers, plus another £250,000 in late-stage opportunities that I would estimate have about a 70% probability of closing within the next six months.", + ); + + // ===== UPDATE 2 TARGET -> real POST /api/cases/update ===== + const update2StartedAt = Date.now(); + + const update2ResponsePromise = page.waitForResponse( + (response) => + response.request().method() === "POST" && + response.url().includes("/api/cases/update"), + { timeout: MODEL_RESPONSE_TIMEOUT }, + ); + + await page.getByRole("button", { name: "Update" }).click(); + + const update2Response = await update2ResponsePromise; + captures.update2 = await captureResponse(update2Response, update2StartedAt); + timings.update2ElapsedMs = captures.update2.elapsedMs; + + console.log( + `[LIVE CAPTURE] update 2: status=${captures.update2.status}, elapsed=${captures.update2.elapsedMs}ms`, + ); + + expect(captures.update2.responseBody).not.toBeNull(); + + const resp = captures.update2.responseBody; + + // ================================================================ + // UPDATE 2 DIAGNOSTICS + // Use the actual response shape; do not assume top-level aliases. + // ================================================================ + + const extracted = { + activeUnknownNodeId: + resp?.updatedSituationGraph?.activeUnknownNodeId ?? null, + + selectedQuestionNodeId: resp?.selectedQuestion?.nodeId ?? null, + + selectedQuestionTemplate: + resp?.selectedQuestion?.selectedQuestionTemplate ?? null, + + selectedQuestionText: resp?.selectedQuestion?.question ?? null, + + diagnosticsSelectedUnknownNodeId: + resp?.diagnostics?.selectedUnknownNodeId ?? "not exposed", + + finalGraphBackedQuestion: + resp?.diagnostics?.finalGraphBackedQuestion ?? null, + + noQuestionReason: resp?.diagnostics?.noQuestionReason ?? null, + }; + + // ================================================================ + // ACTIVE NODE LABEL + // ================================================================ + + let activeNodeLabel = "unknown"; + + const activeId = extracted.activeUnknownNodeId; + const nodes = resp?.updatedSituationGraph?.nodes; + + if (activeId && Array.isArray(nodes)) { + const activeNode = nodes.find((node) => node.id === activeId); + + if (activeNode?.label) { + activeNodeLabel = activeNode.label; + } + } + + // ================================================================ + // VISIBLE CURRENT QUESTION + // + // response-textarea is the ANSWER field. + // It must NOT be interpreted as the current question. + // ================================================================ + + let visibleQuestion = "NOT CAPTURED"; + + const questionTestId = page.getByTestId("question-text"); + + if ((await questionTestId.count()) > 0) { + const text = (await questionTestId.first().textContent())?.trim(); + + if (text) { + visibleQuestion = text; + } + } else if (extracted.selectedQuestionText) { + /* + * If the application has no dedicated question test id, + * only check whether the exact backend-selected question + * is visibly rendered somewhere. + * + * Do not guess another UI selector. + */ + const selectedQuestionOnPage = page.getByText( + extracted.selectedQuestionText, + { exact: true }, + ); + + if ((await selectedQuestionOnPage.count()) > 0) { + try { + await expect(selectedQuestionOnPage.first()).toBeVisible({ + timeout: 10_000, + }); + + visibleQuestion = extracted.selectedQuestionText; + } catch { + // Leave as NOT CAPTURED. + } + } + } + + // ================================================================ + // CLASSIFICATION + // ================================================================ + + let classification = "A - BACKEND QUESTION AND ACTIVE TARGET AGREE"; + + if ( + extracted.activeUnknownNodeId != null && + extracted.selectedQuestionNodeId != null && + extracted.activeUnknownNodeId !== extracted.selectedQuestionNodeId + ) { + classification = "B - BACKEND TARGET MISMATCH"; + } + + // ================================================================ + // DURABLE CAPTURE + // ================================================================ + + const artifactDir = path.join(process.cwd(), "tests", "e2e", "artifacts"); + + fs.mkdirSync(artifactDir, { + recursive: true, + }); + + const artifactPath = path.join( + artifactDir, + "manual-recorded-journey-update2-capture.json", + ); + + const artifact = { + capturedAt: new Date().toISOString(), + + timings, + + start: { + status: captures.start.status, + elapsedMs: captures.start.elapsedMs, + }, + + update1: { + status: captures.update1.status, + elapsedMs: captures.update1.elapsedMs, + }, + + update2: { + url: captures.update2.url, + status: captures.update2.status, + elapsedMs: captures.update2.elapsedMs, + + /* + * Critical evidence for later deterministic replay. + */ + requestBody: captures.update2.requestBody, + + responseBody: captures.update2.responseBody, + }, + + extracted, + activeNodeLabel, + visibleQuestion, + classification, + }; + + fs.writeFileSync(artifactPath, JSON.stringify(artifact, null, 2)); + + // ================================================================ + // COMPACT REPORT + // ================================================================ + + console.log("\n=== LIVE SECOND-UPDATE CAPTURE ==="); + + console.log("Classification:", classification); + + console.log("Start elapsed ms:", timings.startElapsedMs); + + console.log("Update 1 elapsed ms:", timings.update1ElapsedMs); + + console.log("Update 2 elapsed ms:", timings.update2ElapsedMs); + + console.log( + "Update 2 request captured:", + captures.update2.requestBody !== null, + ); + + console.log("activeUnknownNodeId:", extracted.activeUnknownNodeId); + + console.log("selectedQuestion.nodeId:", extracted.selectedQuestionNodeId); + + console.log( + "diagnostics.selectedUnknownNodeId:", + extracted.diagnosticsSelectedUnknownNodeId, + ); + + console.log( + "selectedQuestion.selectedQuestionTemplate:", + extracted.selectedQuestionTemplate, + ); + + console.log("selectedQuestion.question:", extracted.selectedQuestionText); + + console.log( + "diagnostics.finalGraphBackedQuestion:", + extracted.finalGraphBackedQuestion, + ); + + console.log("diagnostics.noQuestionReason:", extracted.noQuestionReason); + + console.log("active node label:", activeNodeLabel); + + console.log("visible current question:", visibleQuestion); + + console.log("artifact:", artifactPath); + + // ================================================================ + // ASSERTIONS + // + // Assert only that the REAL requests completed and were captured. + // + // A target mismatch is diagnostic evidence, not a Playwright + // test failure. + // ================================================================ + + expect(captures.start.elapsedMs).toBeGreaterThan(0); + + expect(captures.update1.elapsedMs).toBeGreaterThan(0); + + expect(captures.update2.elapsedMs).toBeGreaterThan(0); +}); diff --git a/tests/fixtures/live-product-launch-update-2-response.json b/tests/fixtures/live-product-launch-update-2-response.json new file mode 100644 index 0000000..1eb770b --- /dev/null +++ b/tests/fixtures/live-product-launch-update-2-response.json @@ -0,0 +1,691 @@ +{ + "success": true, + "stage": "update_applied", + "updatedSituationGraph": { + "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": [ + "nR4vL9w" + ], + "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": [] + }, + { + "id": "nR4vL9w", + "label": "Sufficiency of committed or highly probable revenue from other customers to cover £300k cost and yield acceptable return", + "description": "The amount of non-enterprise revenue secured or likely enough to justify launching now without the enterprise customer, because resolving this determines whether immediate launch is commercially viable.", + "kind": "unknown", + "status": "resolved", + "confidence": "medium", + "value": null, + "unit": null, + "evidenceIds": [], + "dependsOn": [], + "affects": [], + "parentId": null, + "childIds": [ + "nz92pkx" + ] + } + ], + "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" + }, + { + "id": "e-rev-viability-dep", + "fromNodeId": "nR4vL9w", + "toNodeId": "nz92pkx", + "relationship": "depends_on", + "confidence": "medium", + "description": "Revenue viability without the enterprise customer is a prerequisite for assessing the immediate launch decision" + } + ], + "activeUnknownNodeId": "ntpt9ki", + "resolvedNodeIds": [ + "nR4vL9w" + ], + "currentSummary": "Nodes: 1 state, 3 observation, 2 metric, 1 relationship, 3 unknown | Edges: 6 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." + } + ] + } + }, + "proposal": { + "addedNodes": [], + "updatedNodes": [ + { + "nodeId": "nR4vL9w", + "previousStatus": "unknown", + "newStatus": "resolved", + "previousValue": null, + "newValue": null, + "reason": "User provided committed ARR (£450k) and estimated late-stage revenue (~£175k), confirming that non-enterprise funds cover the £300k cost requirement." + } + ], + "addedEdges": [], + "removedEdgeIds": [], + "resolvedUnknownNodeIds": [ + "nR4vL9w" + ], + "affectedNodeIds": [ + "nz92pkx" + ], + "selectedQuestion": { + "nodeId": "ntpt9ki", + "question": "Has the large enterprise customer formally signed their contract yet?", + "reason": "While non-enterprise revenue covers launch costs, the remaining status of this key client remains an unresolved factor affecting total expected revenue and sales momentum." + }, + "answerMeaning": { + "userSupportedMeaning": "Non-enterprise revenue (£450k committed plus ~£175k expected from late-stage opportunities) is sufficient to cover the £300k immediate cost, meaning launch viability does not strictly depend on the large enterprise customer signing.", + "possibleInference": "The decision can move forward with a launch this year based on existing commercial traction, reducing immediate dependency on unresolved external sales or competitor timing for financial justification.", + "supportCategory": "other", + "resolutionGuidance": "may_resolve" + }, + "structuralActionRequired": true + }, + "selectedQuestion": { + "nodeId": "ntpt9ki", + "question": "What evidence would clarify probability or current status of the large enterprise customer signing their contract before launch or within the year?", + "reason": "Formulated from graph context using the baseline_reconstruction investigation strategy.", + "strategy": "baseline_reconstruction", + "investigationStrategy": { + "key": "baseline_reconstruction", + "reason": "Selected because the unknown explicitly references a missing previous or baseline state.", + "nodeId": "ntpt9ki", + "nodeLabel": "Probability or current status of the large enterprise customer signing their contract before launch or within the year", + "meaning": "probability or current status of the large enterprise customer signing their contract before launch or within the year", + "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": false, + "primaryConceptCount": 1, + "compoundQuestionSignals": [], + "abstractTermCount": 0, + "cognitiveLoad": "low", + "reasons": [ + "very_long_question" + ], + "selectedUnknownId": "ntpt9ki", + "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": [] + }, + "affectedNodeIds": [ + "nz92pkx", + "nR4vL9w" + ], + "resolvedUnknownNodeIds": [ + "nR4vL9w" + ], + "previousActiveUnknownNodeId": "nR4vL9w", + "newActiveUnknownNodeId": "ntpt9ki", + "changesApplied": { + "addedNodeCount": 0, + "addedUnknownCount": 0, + "updatedNodeCount": 1, + "addedEdgeCount": 0, + "removedEdgeCount": 0, + "resolvedUnknownCount": 1, + "affectedNodeCount": 2 + }, + "diagnostics": { + "promptVersion": "v0.4", + "modelName": "qwen-claude:latest", + "responseDurationMs": 67986, + "validationStatus": "valid", + "nodeCount": 10, + "edgeCount": 6, + "graphReferenceValidation": { + "valid": true, + "errors": [] + }, + "normalisationsApplied": [], + "investigationStrategy": { + "key": "baseline_reconstruction", + "reason": "Selected because the unknown explicitly references a missing previous or baseline state.", + "nodeId": "ntpt9ki", + "nodeLabel": "Probability or current status of the large enterprise customer signing their contract before launch or within the year", + "meaning": "probability or current status of the large enterprise customer signing their contract before launch or within the year", + "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." + }, + "previousComparabilityStatus": "confirmed", + "comparabilityStatus": "confirmed", + "relationshipStatus": "insufficient_information", + "relationshipAssessed": true, + "reasoningStagesBefore": [ + { + "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." + } + ], + "reasoningStagesAfter": [ + { + "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." + } + ], + "resolvedReasoningNodeIds": [], + "emergentReasoningNodeCreated": false, + "emergentReasoningNodeId": null, + "emergentReasoningNodeReason": null, + "atomicityAssessment": "atomic", + "atomicityDecisionReason": "This unknown already targets a single concrete detail that can be investigated directly.", + "decompositionDepth": 0, + "decompositionAttempted": true, + "decompositionAccepted": false, + "decompositionStoppedReason": "Decomposition stopped because no meaning-preserving child family was justified for this parent.", + "proposedChildCount": 0, + "acceptedChildCount": 0, + "rejectedChildren": [], + "selectedChildNodeId": null, + "childQualitySummary": [], + "propagationPerformed": false, + "resolvedChildNodeId": null, + "parentNodeId": null, + "parentStatusBefore": null, + "parentStatusAfter": null, + "parentConfidenceBefore": null, + "parentConfidenceAfter": null, + "evidenceConfidenceBefore": null, + "evidenceConfidenceAfter": null, + "completenessBefore": null, + "completenessAfter": null, + "conclusionConfidenceBefore": null, + "conclusionConfidenceAfter": null, + "resolvedDirectChildren": 0, + "unresolvedDirectChildren": 0, + "contradictoryDirectChildren": 0, + "corroboratingBranchCount": 0, + "conflictingBranchCount": 0, + "duplicateEvidenceCount": 0, + "independentBranchCount": 0, + "interactionSummary": null, + "confidenceCapReason": null, + "ancestorPropagationStoppedReason": "no_resolved_child_propagation_needed", + "affectedAncestorIds": [], + "nextSelectedSibling": null, + "parentResolved": false, + "decompositionPerformed": false, + "childUnknownCount": 0, + "childNodeIds": [], + "atomicityReason": "No resolved decomposition child required upward propagation.", + "questionComplexityAccepted": false, + "primaryConceptCount": 1, + "cognitiveLoad": "low", + "complexityReasons": [ + "very_long_question" + ], + "decompositionTriggeredByQuestionComplexity": false, + "previousQuestion": "What outcome would demonstrate enough value to justify launching a new software product this year or wait twelve months?", + "finalQuestion": "What evidence would clarify probability or current status of the large enterprise customer signing their contract before launch or within the year?", + "selectedUnknownBefore": "ntpt9ki", + "selectedUnknownAfter": "ntpt9ki", + "plainLanguageNormalisations": [], + "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.", + "unresolvedCandidateCount": 2, + "eligibleCandidateCount": 2, + "candidateNodeIds": [ + "ntpt9ki", + "nxmeiab" + ], + "resolvedCurrentTurnNodeIds": [ + "nR4vL9w" + ], + "noQuestionReason": null, + "reasoningPatternValidation": { + "activePattern": "decision", + "valid": true, + "reason": "All selectable unknowns are compatible with decision reasoning." + }, + "patternCompatibleNodeCount": 2, + "incompatibleNodeIds": [], + "compatibilityFailures": [], + "replacementActions": [], + "graphReasoningIntegrity": "valid", + "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": [ + "nR4vL9w" + ], + "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" + } + } + }, + "assessment": { + "version": "v0.1", + "assessedAt": "2026-08-17T13:47:44.548Z", + "confidence": "medium", + "phase": { + "value": "exploring", + "confidence": "medium", + "signals": [ + "4 initial observations gathered", + "Resolution progress low (1/10 or unknown)" + ], + "evidence": { + "resolvedNodeCount": 1, + "activeUnknownCount": 2, + "unknownResolutionRatio": 0.1, + "observationDensity": 4, + "evidenceDepth": "shallow" + } + }, + "progress": { + "value": "stalled", + "confidence": "high", + "signals": [ + "Low resolution progress: 10% of nodes resolved", + "1 of 10 nodes resolved — insufficient momentum" + ], + "evidence": { + "turnCount": 3, + "recentResolutionsLastTurn": 1, + "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": 0.1, + "hasActiveQuestion": true, + "summaryLength": 108 + } + } + } +} \ No newline at end of file diff --git a/tests/fixtures/live-product-launch-update-response.json b/tests/fixtures/live-product-launch-update-response.json new file mode 100644 index 0000000..5c66a0e --- /dev/null +++ b/tests/fixtures/live-product-launch-update-response.json @@ -0,0 +1,779 @@ +{ + "success": true, + "stage": "update_applied", + "updatedSituationGraph": { + "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": [ + "nR4vL9w" + ], + "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": [] + }, + { + "id": "nR4vL9w", + "label": "Sufficiency of committed or highly probable revenue from other customers to cover £300k cost and yield acceptable return", + "description": "The amount of non-enterprise revenue secured or likely enough to justify launching now without the enterprise customer, because resolving this determines whether immediate launch is commercially viable.", + "kind": "unknown", + "status": "unknown", + "confidence": "medium", + "value": null, + "unit": null, + "evidenceIds": [], + "dependsOn": [], + "affects": [], + "parentId": null, + "childIds": [ + "nz92pkx" + ] + } + ], + "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" + }, + { + "id": "e-rev-viability-dep", + "fromNodeId": "nR4vL9w", + "toNodeId": "nz92pkx", + "relationship": "depends_on", + "confidence": "medium", + "description": "Revenue viability without the enterprise customer is a prerequisite for assessing the immediate launch decision" + } + ], + "activeUnknownNodeId": "nR4vL9w", + "resolvedNodeIds": [], + "currentSummary": "Nodes: 1 state, 3 observation, 2 metric, 1 relationship, 3 unknown | Edges: 6 total | Unknowns: 3 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." + } + ] + } + }, + "proposal": { + "addedNodes": [ + { + "id": "nR4vL9w", + "label": "Sufficiency of committed or highly probable revenue from other customers to cover £300k cost and yield acceptable return", + "description": "The amount of non-enterprise revenue secured or likely enough to justify launching now without the enterprise customer, because resolving this determines whether immediate launch is commercially viable.", + "kind": "unknown", + "status": "unknown", + "confidence": "medium", + "value": null, + "unit": null, + "evidenceIds": [], + "dependsOn": [], + "affects": [], + "parentId": null, + "childIds": [ + "nz92pkx" + ] + } + ], + "updatedNodes": [], + "addedEdges": [ + { + "id": "e-rev-viability-dep", + "fromNodeId": "nR4vL9w", + "toNodeId": "nz92pkx", + "relationship": "depends_on", + "confidence": "medium", + "description": "Revenue viability without the enterprise customer is a prerequisite for assessing the immediate launch decision" + } + ], + "removedEdgeIds": [], + "resolvedUnknownNodeIds": [], + "affectedNodeIds": [ + "nz92pkx" + ], + "selectedQuestion": { + "nodeId": "nR4vL9w", + "question": "How much committed or highly probable revenue exists from other customers relative to the £300k implementation cost?", + "reason": "The user's answer highlights commercial viability without the enterprise customer as the immediate deciding factor for launching this year." + }, + "answerMeaning": { + "userSupportedMeaning": "Launching this year must remain commercially viable without the enterprise customer, requiring enough committed or highly probable revenue from other customers to cover the £300k cost and yield an acceptable return.", + "possibleInference": "The competitor landscape is secondary to establishing a non-enterprise revenue baseline that makes the launch financially safe.", + "supportCategory": "conditional_tradeoff", + "resolutionGuidance": null + }, + "structuralActionRequired": true + }, + "selectedQuestion": { + "nodeId": "nR4vL9w", + "question": "What outcome would demonstrate enough value to justify launching a new software product this year or wait twelve months?", + "reason": "Formulated from graph context using the decision_threshold investigation strategy.", + "strategy": "decision_threshold", + "investigationStrategy": { + "key": "decision_threshold", + "reason": "Selected because the unknown determines the threshold for making or justifying a decision.", + "nodeId": "nR4vL9w", + "nodeLabel": "Sufficiency of committed or highly probable revenue from other customers to cover £300k cost and yield acceptable return", + "meaning": "sufficiency of committed or highly probable revenue from other customers to cover £300k cost and yield acceptable return", + "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_threshold", + "allowedQuestionFamilies": [ + "decision_foundation", + "decision_evidence", + "decision_threshold", + "definition" + ], + "rejectedQuestionFamilies": [ + "explanation", + "comparison", + "contradiction", + "diagnosis", + "prioritisation" + ], + "selectedQuestionTemplate": "decision_threshold_outcome", + "questionComplexity": { + "acceptable": true, + "primaryConceptCount": 1, + "compoundQuestionSignals": [], + "abstractTermCount": 0, + "cognitiveLoad": "low", + "reasons": [], + "selectedUnknownId": "nR4vL9w", + "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": [] + }, + "affectedNodeIds": [ + "nz92pkx" + ], + "resolvedUnknownNodeIds": [], + "previousActiveUnknownNodeId": "ntpt9ki", + "newActiveUnknownNodeId": "nR4vL9w", + "changesApplied": { + "addedNodeCount": 1, + "addedUnknownCount": 1, + "updatedNodeCount": 0, + "addedEdgeCount": 1, + "removedEdgeCount": 0, + "resolvedUnknownCount": 0, + "affectedNodeCount": 1 + }, + "diagnostics": { + "promptVersion": "v0.4", + "modelName": "qwen-claude:latest", + "responseDurationMs": 75413, + "validationStatus": "valid", + "nodeCount": 10, + "edgeCount": 6, + "graphReferenceValidation": { + "valid": true, + "errors": [] + }, + "normalisationsApplied": [], + "investigationStrategy": { + "key": "decision_threshold", + "reason": "Selected because the unknown determines the threshold for making or justifying a decision.", + "nodeId": "nR4vL9w", + "nodeLabel": "Sufficiency of committed or highly probable revenue from other customers to cover £300k cost and yield acceptable return", + "meaning": "sufficiency of committed or highly probable revenue from other customers to cover £300k cost and yield acceptable return", + "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." + }, + "previousComparabilityStatus": "confirmed", + "comparabilityStatus": "confirmed", + "relationshipStatus": "insufficient_information", + "relationshipAssessed": true, + "reasoningStagesBefore": [ + { + "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." + } + ], + "reasoningStagesAfter": [ + { + "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." + } + ], + "resolvedReasoningNodeIds": [], + "emergentReasoningNodeCreated": false, + "emergentReasoningNodeId": null, + "emergentReasoningNodeReason": null, + "atomicityAssessment": "composite", + "atomicityDecisionReason": "This unknown still bundles multiple abstract uncertainties together, so it should be decomposed before asking it directly.", + "decompositionDepth": 0, + "decompositionAttempted": true, + "decompositionAccepted": false, + "decompositionStoppedReason": "Decomposition stopped because no meaning-preserving child family was justified for this parent.", + "proposedChildCount": 0, + "acceptedChildCount": 0, + "rejectedChildren": [], + "selectedChildNodeId": null, + "childQualitySummary": [], + "propagationPerformed": false, + "resolvedChildNodeId": null, + "parentNodeId": null, + "parentStatusBefore": null, + "parentStatusAfter": null, + "parentConfidenceBefore": null, + "parentConfidenceAfter": null, + "evidenceConfidenceBefore": null, + "evidenceConfidenceAfter": null, + "completenessBefore": null, + "completenessAfter": null, + "conclusionConfidenceBefore": null, + "conclusionConfidenceAfter": null, + "resolvedDirectChildren": 0, + "unresolvedDirectChildren": 0, + "contradictoryDirectChildren": 0, + "corroboratingBranchCount": 0, + "conflictingBranchCount": 0, + "duplicateEvidenceCount": 0, + "independentBranchCount": 0, + "interactionSummary": null, + "confidenceCapReason": null, + "ancestorPropagationStoppedReason": "no_resolved_child_propagation_needed", + "affectedAncestorIds": [], + "nextSelectedSibling": null, + "parentResolved": false, + "decompositionPerformed": false, + "childUnknownCount": 0, + "childNodeIds": [], + "atomicityReason": "No resolved decomposition child required upward propagation.", + "questionComplexityAccepted": true, + "primaryConceptCount": 1, + "cognitiveLoad": "low", + "complexityReasons": [], + "decompositionTriggeredByQuestionComplexity": false, + "previousQuestion": "What evidence would clarify whether competitors are actively developing similar products and how soon they might release them?", + "finalQuestion": "What outcome would demonstrate enough value to justify launching a new software product this year or wait twelve months?", + "selectedUnknownBefore": "nR4vL9w", + "selectedUnknownAfter": "nR4vL9w", + "plainLanguageNormalisations": [], + "reasoningPattern": "decision", + "questionFamily": "decision_threshold", + "allowedQuestionFamilies": [ + "decision_foundation", + "decision_evidence", + "decision_threshold", + "definition" + ], + "rejectedQuestionFamilies": [ + "explanation", + "comparison", + "contradiction", + "diagnosis", + "prioritisation" + ], + "selectedQuestionTemplate": "decision_threshold_outcome", + "reasoningPatternReason": "Selected decision because the active unknown sits inside a build, continue, invest, or commercial-justification decision context.", + "unresolvedCandidateCount": 3, + "eligibleCandidateCount": 3, + "candidateNodeIds": [ + "ntpt9ki", + "nxmeiab", + "nR4vL9w" + ], + "resolvedCurrentTurnNodeIds": [], + "noQuestionReason": null, + "reasoningPatternValidation": { + "activePattern": "decision", + "valid": true, + "reason": "All selectable unknowns are compatible with decision reasoning." + }, + "patternCompatibleNodeCount": 3, + "incompatibleNodeIds": [], + "compatibilityFailures": [], + "replacementActions": [], + "graphReasoningIntegrity": "valid", + "unknownSelectionExplanation": { + "selectedNodeId": "nR4vL9w", + "selectedNodeLabel": "Sufficiency of committed or highly probable revenue from other customers to cover £300k cost and yield acceptable return", + "status": "selected", + "tieType": "none", + "resolvedNodeIds": [], + "tiedCandidateIds": [ + "nR4vL9w" + ], + "tieBreakOrder": [ + "score_desc", + "downstreamCount_desc", + "unresolvedParentUnknownCount_asc", + "label_asc" + ], + "alphabeticalUsedAsReasoning": false, + "candidates": [ + { + "nodeId": "nR4vL9w", + "label": "Sufficiency of committed or highly probable revenue from other customers to cover £300k cost and yield acceptable return", + "score": 25, + "downstreamCount": 1, + "unresolvedParentUnknownCount": 0, + "matches": { + "objective": false, + "actor": true, + "criteria": true, + "measure": false, + "terminology": false, + "constraint": false, + "pricing": false, + "implementation": false, + "optimisation": false, + "speculative": false + }, + "contributions": [ + { + "rule": "downstream_dependencies", + "value": 1, + "weight": 4, + "delta": 4 + }, + { + "rule": "actor_match", + "value": true, + "weight": 10, + "delta": 10 + }, + { + "rule": "criteria_match", + "value": true, + "weight": 11, + "delta": 11 + } + ] + }, + { + "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": "nR4vL9w", + "label": "Sufficiency of committed or highly probable revenue from other customers to cover £300k cost and yield acceptable return", + "score": 25, + "downstreamCount": 1, + "unresolvedParentUnknownCount": 0, + "matches": { + "objective": false, + "actor": true, + "criteria": true, + "measure": false, + "terminology": false, + "constraint": false, + "pricing": false, + "implementation": false, + "optimisation": false, + "speculative": false + }, + "contributions": [ + { + "rule": "downstream_dependencies", + "value": 1, + "weight": 4, + "delta": 4 + }, + { + "rule": "actor_match", + "value": true, + "weight": 10, + "delta": 10 + }, + { + "rule": "criteria_match", + "value": true, + "weight": 11, + "delta": 11 + } + ] + }, + "competitors": [ + { + "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 + } + ], + "outrankedBy": { + "scoreDelta": 15, + "downstreamDelta": 1, + "unresolvedPrerequisiteDelta": 0, + "labelOrderWinner": null + } + }, + { + "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": 25, + "downstreamDelta": 1, + "unresolvedPrerequisiteDelta": 0, + "labelOrderWinner": null + } + } + ], + "summary": { + "candidateCount": 3, + "selectedReason": "highest_score=25; downstream=1; unresolved_prerequisites=0" + } + } + }, + "assessment": { + "version": "v0.1", + "assessedAt": "2026-08-17T13:46:36.201Z", + "confidence": "low", + "phase": { + "value": "exploring", + "confidence": "medium", + "signals": [ + "4 initial observations gathered", + "Resolution progress low (0/10 or unknown)" + ], + "evidence": { + "resolvedNodeCount": 0, + "activeUnknownCount": 3, + "unknownResolutionRatio": null, + "observationDensity": 4, + "evidenceDepth": "shallow" + } + }, + "progress": { + "value": "cannot_determine", + "confidence": "low", + "signals": [ + "Insufficient data for progress assessment", + "Total nodes: 10, resolved: 0" + ], + "evidence": { + "turnCount": 0, + "recentResolutionsLastTurn": 0, + "newUnknownsPerTurn": null, + "repeatedNodeIds": [] + } + }, + "conversationHealth": { + "value": "healthy", + "confidence": "medium", + "signals": [ + "Active investigation in progress: 3 unresolved unknown(s)", + "Question actively driving the investigation forward" + ], + "evidence": { + "questionTypeDistribution": null, + "activeUnknownCount": 3, + "resolvedNodeRatio": null, + "hasActiveQuestion": true, + "summaryLength": 108 + } + } + } +} \ No newline at end of file