From 85b9f4411f16158e6d00d4cf21a526254f4387d0 Mon Sep 17 00:00:00 2001 From: robbond Date: Tue, 8 Sep 2026 09:42:46 +0100 Subject: [PATCH] fix(confidence-engine): reopen resolved unknowns by graph state --- lib/graph/reopen-resolved-unknown.js | 9 ++++++--- tests/graph/reopen-resolved-unknown.test.js | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/graph/reopen-resolved-unknown.js b/lib/graph/reopen-resolved-unknown.js index 329fb85..2c9bb7d 100644 --- a/lib/graph/reopen-resolved-unknown.js +++ b/lib/graph/reopen-resolved-unknown.js @@ -1,11 +1,12 @@ /** * Deterministically reopen a resolved unknown node in a SituationGraph. * - * Transition: node.status "resolved" → "unknown", and removes the node's ID + * Transition: removes the node's ID from resolvedNodeIds and establishes + * node.status "unknown". * from resolvedNodeIds. This reverses canonical resolution so the question * reappears among Open Questions for further investigation. * - * Idempotent — if the target is not a currently-resolved unknown, returns the + * Idempotent — if the target is not an unknown marked resolved in graph state, returns the * original graph unchanged (no mutation). Does NOT create nodes, delete edges, * or touch contributions/findings/historical evidence. */ @@ -17,7 +18,9 @@ export function reopenResolvedUnknown(situationGraph, nodeId) { if (nodeIndex === -1) return situationGraph; const node = situationGraph.nodes[nodeIndex]; - if (node.kind !== "unknown" || node.status !== "resolved") return situationGraph; + if (node.kind !== "unknown" || !situationGraph.resolvedNodeIds?.includes(nodeId)) { + return situationGraph; + } const newNode = { ...node, status: "unknown" }; const newNodes = [...situationGraph.nodes]; diff --git a/tests/graph/reopen-resolved-unknown.test.js b/tests/graph/reopen-resolved-unknown.test.js index 24ab4dc..c56dd13 100644 --- a/tests/graph/reopen-resolved-unknown.test.js +++ b/tests/graph/reopen-resolved-unknown.test.js @@ -145,6 +145,23 @@ describe("reopenResolvedUnknown — pure deterministic transformation", () => { }); }); + describe("canonical resolved-node-ID target", () => { + it("reopens an unknown-status node marked resolved by graph state without mutating input", () => { + const graph = makeTestGraph(); + graph.nodes[0] = { ...graph.nodes[0], status: "unknown" }; + + const result = reopenResolvedUnknown(graph, "u-1"); + const targetNode = result.nodes.find((n) => n.id === "u-1"); + + expect(targetNode.kind).toBe("unknown"); + expect(targetNode.status).toBe("unknown"); + expect(result.resolvedNodeIds).not.toContain("u-1"); + expect(result.resolvedNodeIds).toContain("u-2"); + expect(graph.nodes.find((n) => n.id === "u-1").status).toBe("unknown"); + expect(graph.resolvedNodeIds).toContain("u-1"); + }); + }); + describe("invalid/no-op cases", () => { it("returns original graph when node does not exist", () => { const graph = makeTestGraph();