fix(confidence-engine): align empty done and reopen state

- Empty Done immediate transition now sets node.status to resolved
  alongside resolvedNodeIds/doneForNowIds — same canonical parked
  shape as populated Done (no server call required)
- Clarified-question Re-open removes target from doneForNowIds so
  the question visibly returns to Open Questions
- Immediate graph mutation creates new node objects immutably
  (React state semantics), touching only the target node
This commit is contained in:
2026-09-02 13:37:15 +01:00
parent 2b2096e41d
commit f2c9e4c0b2
4 changed files with 342 additions and 3 deletions
+5
View File
@@ -1981,6 +1981,7 @@ export default function ReasoningWorkspace({
onClick={() => {
const nextGraph = reopenResolvedUnknown(graph, node.id);
onSituationGraphChange(nextGraph);
setDoneForNowIds((prev) => prev.filter((id) => id !== node.id));
}}
style={{ cursor: "pointer" }}
className="text-[10px] font-medium uppercase tracking-wider text-amber-600 hover:text-amber-700 underline transition"
@@ -2256,8 +2257,12 @@ export default function ReasoningWorkspace({
if (currentGraph) {
const resolvedIds = new Set(currentGraph.resolvedNodeIds || []);
resolvedIds.add(focusedPresentationItemId);
const nextNodes = (currentGraph.nodes || []).map((n) =>
n.id === focusedPresentationItemId ? { ...n, status: "resolved" } : n,
);
onImmediateGraphChange({
...currentGraph,
nodes: nextNodes,
resolvedNodeIds: Array.from(resolvedIds),
});
}
+8 -1
View File
@@ -359,7 +359,14 @@ export default function ScenarioForm() {
* activity boundary. Delegates to the exported executeEpisodeDone pipeline.
*/
async function handleDoneForNowPromotion(targetNodeId, onImmediateGraphUpdate) {
if (!targetNodeId || !findings?.length) return;
if (!targetNodeId) return;
// Gate: only invoke episode processing when the active target has focused contributions.
// Scenario-wide findings no longer determine whether an empty target enters episode processing.
const hasActiveTargetContent = (focusedContributions ?? []).some(
(c) => c.targetNodeId === targetNodeId || c.originatingTargetNodeId === targetNodeId,
);
if (!hasActiveTargetContent) return;
// In-flight guard: exactly-once enforcement
if (doneInProgressRef.current) return;