diff --git a/components/reasoning-workspace.jsx b/components/reasoning-workspace.jsx index c3f0c4d..c7475ae 100644 --- a/components/reasoning-workspace.jsx +++ b/components/reasoning-workspace.jsx @@ -310,6 +310,157 @@ function EvidenceLimitCard({ summary }) { ); } +// ── Quiet facilitator state (experiment mode) ───────────────────── + +function QuietStateCard() { + return ( +
+

+ Nothing more to add here right now +

+

+ You can continue with another question, switch branches, or return when + you have more information. +

+
+ ); +} + +// ── New connection / late-result indicator ──────────────────────── + +function UpdatedConnectionCard({ update }) { + return ( +
+

+ New update +

+
+

{update.text}

+
+
+ ); +} + +// ── Branch notebook content (RTO.27A) ──────────────────────────── +// Smallest useful branch-scoped composition from fixture data. +// Only renders sections grounded in existing records. + +function BranchNotebookContent({ + branchContext, + contributions, + openQuestions, + lateResults, + inactiveBranchNewResults, +}) { + const hasOpenItems = openQuestions && openQuestions.length > 0; + const hasContributions = contributions && contributions.length > 0; + + return ( +
+ {/* Why this branch exists */} + {branchContext && ( +
+

+ Current branch +

+

{branchContext.label}

+ {branchContext.origin && ( +

+ Trying to understand: {branchContext.origin} +

+ )} +
+ )} + + {/* What we know here */} + {hasContributions && ( +
+

+ What we know here +

+
+ {contributions.map((c, i) => ( +
+

{c.text}

+
+ ))} +
+
+ )} + + {/* Still uncertain here */} + {hasOpenItems && ( +
+

+ Still uncertain / open questions +

+
+ {openQuestions.map((q, i) => ( + + ))} +
+
+ )} + + {/* New connection / updates (active branch) */} + {lateResults && lateResults.length > 0 && ( + + )} + + {/* Quiet state — only when there are no open items and no updates */} + {!hasOpenItems && !lateResults?.length && ( + + )} +
+ ); +} + +// ── Question row (renders clickable card with optional focused content) ─ + +function QuestionRow({ question }) { + const [isFocused, setIsFocused] = useState(false); + + if (!isFocused) { + return ( + + ); + } + + return ( +
+

{question.label}

+
+

+ We have not explored this yet. Do you want to work through it? +

+ +
+ +
+ ); +} + // ── Current understanding card ──────────────────────────────── function CurrentUnderstandingCard({ currentSummary, plainLanguage }) { if (plainLanguage) return ; @@ -510,6 +661,132 @@ function getErrorType(errorStr, stage, hasGraph) { return null; } +// ── Open questions panel (production, non-experiment mode) ──────── + +function OpenQuestionsPanel({ + graph, selectedPresentationItemId, focusedPresentationItemId, hasFocusedContent, + focused, formulationStep, formulateMsg, processingStep, deconstructMsg, doneForNowIds, + startFocused, handleDeconstructSubmit, retryFormulation, setSelectedPresentationItemId, + setFocusedPresentationItemId, setFocusedAnswer, focusedAnswer, setDoneForNowIds, +}) { + const openNodes = (graph?.nodes || []).filter( + (n) => n.kind === "unknown" && n.status !== "resolved" && !doneForNowIds.includes(n.id), + ); + if (openNodes.length <= 1) return null; + + return ( +
+

+ Open questions +

+
+ {openNodes.map((node) => { + const isSelected = selectedPresentationItemId === node.id; + const isFocused = focusedPresentationItemId === node.id; + + return ( +
+
{ + if (!focused?.question?.trim() || (focused && !hasFocusedContent())) { + setSelectedPresentationItemId( + selectedPresentationItemId === node.id ? null : node.id, + ); + } + }} + style={{ cursor: "pointer" }} + className="w-full text-left rounded-lg border border-gray-200 px-4 py-3 transition hover:border-gray-300 hover:bg-white" + > +

+ {node.label} +

+ + {isSelected && !hasFocusedContent() && ( +
+

+ We have not explored this yet. Do you want to work through it? +

+ +
+ )} + + {isFocused && (() => { + const focusedNode = graph?.nodes.find((n) => n.id === node.id); + return ( +
+ {hasFocusedContent() && ( +
+ {focused?.question?.trim() ? ( +
+

Question

+

{focused.question}

+
+ ) : formulationStep === "active" ? ( +

{formulateMsg}

+ ) : null} + + {focused?.question?.trim() && processingStep !== "active" && focused.status === "formulated" && ( +
+ +