From 007f5ac286b78878f7134597a6dfdad4970eb196 Mon Sep 17 00:00:00 2001 From: robbond Date: Mon, 3 Aug 2026 19:11:32 +0100 Subject: [PATCH] feat: surface answer impact after update --- components/reasoning-workspace.jsx | 92 +++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/components/reasoning-workspace.jsx b/components/reasoning-workspace.jsx index a631010..3ee8e19 100644 --- a/components/reasoning-workspace.jsx +++ b/components/reasoning-workspace.jsx @@ -250,6 +250,89 @@ function LoadingOverlay({ isLoading, elapsed, currentMessage, variant }) { ); } +// ── Update acknowledgement ──────────────────────────────────── +function UpdateAcknowledgement({ answer, updateResult }) { + if (!updateResult || !answer?.trim()) return null; + + const hasResolvedNodes = + updateResult.resolvedUnknownNodeIds && updateResult.resolvedUnknownNodeIds.length > 0; + const hasAffectedNodes = + updateResult.affectedNodeIds && updateResult.affectedNodeIds.length > 0; + const graph = updateResult.updatedSituationGraph; + + function getNodeText(nodeId) { + if (!graph?.nodes) return String(nodeId); + const node = graph.nodes.find((n) => n.id === nodeId); + if (node) { + const parts = [node.label]; + if (node.status !== "resolved") { + parts.push(node.status); + } + return parts.join(" "); + } + return String(nodeId); + } + + let changedText; + if (hasResolvedNodes || hasAffectedNodes) { + const items = []; + if (hasResolvedNodes) { + for (const id of updateResult.resolvedUnknownNodeIds.slice(0, 5)) { + items.push(getNodeText(id)); + } + if (updateResult.resolvedUnknownNodeIds.length > 5) { + items.push(`and ${updateResult.resolvedUnknownNodeIds.length - 5} more resolved`); + } + } + if (hasAffectedNodes && !hasResolvedNodes) { + for (const id of updateResult.affectedNodeIds.slice(0, 5)) { + items.push(getNodeText(id)); + } + if (updateResult.affectedNodeIds.length > 5) { + items.push(`and ${updateResult.affectedNodeIds.length - 5} more affected`); + } + } + if (items.length === 0 && updateResult.changesApplied) { + const parts = []; + const ca = updateResult.changesApplied; + if (ca.addedNodeCount) parts.push(`${ca.addedNodeCount} node(s) added`); + if (ca.updatedNodeCount) parts.push(`${ca.updatedNodeCount} node(s) updated`); + if (ca.resolvedUnknownCount) parts.push(`${ca.resolvedUnknownCount} unknown(s) resolved`); + changedText = parts.join(", "); + } else { + changedText = items.join(". ") + "."; + } + } else if (updateResult.changesApplied) { + const ca = updateResult.changesApplied; + const parts = []; + if (ca.addedNodeCount) parts.push(`${ca.addedNodeCount} node(s) added`); + if (ca.updatedNodeCount) parts.push(`${ca.updatedNodeCount} node(s) updated`); + if (ca.addedEdgeCount) parts.push(`${ca.addedEdgeCount} edge(s) added`); + if (ca.removedEdgeCount) parts.push(`${ca.removedEdgeCount} edge(s) removed`); + changedText = parts.length > 0 ? parts.join(", ") : null; + } + + const summary = updateResult.summary || null; + const displayChanged = summary || changedText || "Your answer has been added to the investigation."; + + return ( +
+
+

+ You told us +

+

{answer}

+
+
+

+ What changed +

+

{displayChanged}

+
+
+ ); +} + // ── Developer details disclosure ────────────────────────────── function DeveloperDetails({ graph, selectedQuestion, diagnostics, newlySurfacedNodeIds, updateResult }) { return ( @@ -340,11 +423,16 @@ export default function ReasoningWorkspace({ ) : ( <> - {/* Completion or holding state (only when there is no next question) */} + {/* ── Post-update acknowledgement ─────────────── */} + {updateStatus === "success" && graph && ( + + )} + + {/* Completion state (only when there is no next question and nothing remains) */} {status === "success" && !canAnswer && graph && genuineCompletion && ( )} - {status === "success" && !canAnswer && graph && unresolvedRemaining && ( + {status === "success" && !canAnswer && graph && unresolvedRemaining && updateStatus !== "success" && (

There is no further question the engine can justify at the moment.

More evidence may be needed before a next step is clear.