diff --git a/components/reasoning-workspace.jsx b/components/reasoning-workspace.jsx
index b39e03b..46519cc 100644
--- a/components/reasoning-workspace.jsx
+++ b/components/reasoning-workspace.jsx
@@ -148,6 +148,99 @@ function useSessionPersistence() {
return { saveSession, loadSession, clearSession, sessionReady: true };
}
+// ── Shared focused-question body (extracted from OpenQuestionsPanel) ──
+
+function FocusedQuestionBody({
+ nodeId,
+ isFocused,
+ hasCompletedInvestigation: hasCompleted,
+ focused,
+ formulationStep,
+ formulateMsg,
+ processingStep,
+ deconstructMsg,
+ focusedAnswer,
+ handleDeconstructSubmit,
+ retryFormulation,
+ setFocusedAnswer,
+ setSelectedPresentationItemId,
+ setFocusedPresentationItemId,
+ setDoneForNowIds,
+ setFollowUpQuestion,
+}) {
+ return (
+ <>
+ {isFocused && (() => {
+ const hasContent = focused?.question?.trim() || formulationStep === "active" || processingStep === "active" || focused?.error;
+
+ if (!hasContent) return null;
+
+ return (
+
+
+ {focused?.question?.trim() ? (
+
+
Question
+
{focused.question}
+
+ ) : formulationStep === "active" ? (
+
{formulateMsg}
+ ) : null}
+
+ {focused?.question?.trim() && processingStep !== "active" && focused.status === "formulated" && (
+
+
+
+ )}
+
+ {processingStep === "active" &&
{deconstructMsg}
}
+
+ {focused?.result && (
+ <>
+
What this tells us
{(focused.result.observations || []).map((o, i) => (- {o}
))}
+
Still unclear
{(focused.result.uncertainties || []).map((u, i) => (- {u}
))}
+
Questions this raises
+ {(focused.result.possibleFollowUpQuestions || []).length > 0 ? (
+
+ {focused.result.possibleFollowUpQuestions.map((q, i) => (
+
+ ))}
+
+ ) : (
+
None yet
+ )}
+
+
Assumptions
{(focused.result.assumptions || []).map((a, i) => (- {a}
))}
+
Connections
{(focused.result.relationships || []).map((r, i) => (- {r.from} → {r.to} ({r.type})
))}
+ >
+ )}
+
+ {focused?.error && processingStep !== "active" && (
+
We were unable to process your request right now. Please try again later.
+ )}
+
+
+
+
+
+
+
+ );
+ })()}
+ >
+ );
+}
+
// ── Current understanding card ────────────────────────────────
// Evidence-limit text that must not appear inside Current understanding
@@ -855,72 +948,24 @@ function OpenQuestionsPanel({
)}
- {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" && (
-
-
-
- )}
-
- {processingStep === "active" &&
{deconstructMsg}
}
-
- {focused?.result && (
- <>
-
What this tells us
{(focused.result.observations || []).map((o, i) => (- {o}
))}
-
Still unclear
{(focused.result.uncertainties || []).map((u, i) => (- {u}
))}
-
Questions this raises
- {(focused.result.possibleFollowUpQuestions || []).length > 0 ? (
-
- {focused.result.possibleFollowUpQuestions.map((q, i) => (
-
- ))}
-
- ) : (
-
None yet
- )}
-
-
Assumptions
{(focused.result.assumptions || []).map((a, i) => (- {a}
))}
-
Connections
{(focused.result.relationships || []).map((r, i) => (- {r.from} → {r.to} ({r.type})
))}
- >
- )}
-
- {focused?.error && processingStep !== "active" && (
-
We were unable to process your request right now. Please try again later.
- )}
-
- )}
-
-
-
-
-
-
- );
- })()}
+ hasCompletedInvestigation(node.id)}
+ focused={focused}
+ formulationStep={formulationStep}
+ formulateMsg={formulateMsg}
+ processingStep={processingStep}
+ deconstructMsg={deconstructMsg}
+ focusedAnswer={focusedAnswer}
+ handleDeconstructSubmit={handleDeconstructSubmit}
+ retryFormulation={retryFormulation}
+ setFocusedAnswer={setFocusedAnswer}
+ setSelectedPresentationItemId={setSelectedPresentationItemId}
+ setFocusedPresentationItemId={setFocusedPresentationItemId}
+ setDoneForNowIds={setDoneForNowIds}
+ setFollowUpQuestion={setFollowUpQuestion}
+ />
{/* Thread contributions for this node */}
@@ -1469,20 +1514,70 @@ export default function ReasoningWorkspace({
Open Questions
- {openUnknowns.map((node) => (
-
- ))}
+ {openUnknowns.map((node) => {
+ const isFocused = focusedPresentationItemId === node.id;
+ const hasCompleted = Boolean(
+ focusedInvestigations[node.id] &&
+ focusedInvestigations[node.id].question
+ );
+
+ function handleNodeClick(n) {
+ if (hasCompleted && selectedPresentationItemId === n.id) {
+ setFocusedPresentationItemId(n.id);
+ return;
+ }
+ startFocused(n.id);
+ }
+
+ return (
+
+ );
+ })}
+
+ {/* Focused content — rendered inline in the initial reflection surface */}
+ {(() => {
+ const activeForFocus = openUnknowns.find((n) => focusedPresentationItemId === n.id);
+ if (!activeForFocus) return null;
+
+ const node = activeForFocus;
+ const hasCompleted = Boolean(
+ focusedInvestigations[node.id] &&
+ focusedInvestigations[node.id].question
+ );
+ const isFocused = focusedPresentationItemId === node.id;
+
+ return (
+ hasCompleted}
+ focused={getFocusedInvestigation()}
+ formulationStep={formulationStep}
+ formulateMsg={formulateMsg}
+ processingStep={processingStep}
+ deconstructMsg={deconstructMsg}
+ focusedAnswer={focusedAnswer}
+ handleDeconstructSubmit={handleDeconstructSubmit}
+ retryFormulation={retryFormulation}
+ setFocusedAnswer={setFocusedAnswer}
+ setSelectedPresentationItemId={setSelectedPresentationItemId}
+ setFocusedPresentationItemId={setFocusedPresentationItemId}
+ setDoneForNowIds={setDoneForNowIds}
+ setFollowUpQuestion={setFollowUpQuestion}
+ />
+ );
+ })()}
)}
diff --git a/tests/run-a-focused-content.test.jsx b/tests/run-a-focused-content.test.jsx
new file mode 100644
index 0000000..88a95ee
--- /dev/null
+++ b/tests/run-a-focused-content.test.jsx
@@ -0,0 +1,219 @@
+import { describe, expect, it } from "vitest";
+
+// ── Simulated Run A initial reflection surface focused content lifecycle ──
+// Validates that clicking an Open Question in post-Analyse → visible formulation
+// → deconstruction → result follows the exact same state machine as OpenQuestionsPanel.
+
+// ── State helpers that mirror ReasoningWorkspace logic ───────────
+
+function simulateInitialFocus(props) {
+ const { focusedInvestigations = {}, focusedPresentationItemId, postAnalyseStatus } = props;
+ const focusedObj = focusedPresentationItemId ? (focusedInvestigations[focusedPresentationItemId] ?? null) : null;
+ return {
+ surfaceVisible: postAnalyseStatus === "success",
+ focusedItem: focusedPresentationItemId ?? null,
+ focusedObj,
+ hasContent: Boolean(
+ focusedObj?.question?.trim() ||
+ focusedObj?.status === "formulating" ||
+ props.processingStep === "active" ||
+ focusedObj?.error
+ ),
+ };
+}
+
+function simulateFormulationSuccess(focusedInvestigations, nodeId, questionText) {
+ return {
+ ...focusedInvestigations,
+ [nodeId]: {
+ status: "formulated",
+ question: questionText,
+ answer: null,
+ result: null,
+ error: null,
+ },
+ };
+}
+
+function simulateAnswerSubmission(focusedInvestigations, nodeId, answerText) {
+ const existing = focusedInvestigations[nodeId];
+ if (!existing) return focusedInvestigations;
+ return {
+ ...focusedInvestigations,
+ [nodeId]: { ...existing, answer: answerText },
+ };
+}
+
+function simulateDeconstructionSuccess(focusedInvestigations, nodeId, resultData) {
+ const existing = focusedInvestigations[nodeId];
+ if (!existing) return focusedInvestigations;
+ return {
+ ...focusedInvestigations,
+ [nodeId]: {
+ ...existing,
+ status: "formulated",
+ result: resultData,
+ error: null,
+ },
+ };
+}
+
+// ── Tests ─────────────────────────────────────────────────────
+
+describe("Run A focused content — formulation visible in initial reflection surface", () => {
+ it("collapsed question card shows UNCLEAR label before click", () => {
+ const state = simulateInitialFocus({
+ focusedInvestigations: {},
+ focusedPresentationItemId: null,
+ postAnalyseStatus: "success",
+ });
+ expect(state.surfaceVisible).toBe(true);
+ expect(state.focusedItem).toBeNull();
+ expect(state.hasContent).toBe(false);
+ });
+
+ it("formulation loading state — UNCLEAR hidden, focused card visible", () => {
+ const withFormulating = { q1: { status: "formulating", question: "", answer: null, result: null, error: null } };
+ const stateWithLoading = simulateInitialFocus({
+ focusedInvestigations: withFormulating,
+ focusedPresentationItemId: "q1",
+ postAnalyseStatus: "success",
+ processingStep: "idle",
+ });
+
+ expect(stateWithLoading.focusedItem).toBe("q1");
+ expect(stateWithLoading.hasContent).toBe(true);
+ });
+
+ it("formulated question — exact question text visible via focused object", () => {
+ const inv = simulateFormulationSuccess({}, "q1", "What would clarify this?");
+ const state = simulateInitialFocus({
+ focusedInvestigations: inv,
+ focusedPresentationItemId: "q1",
+ postAnalyseStatus: "success",
+ });
+
+ expect(state.focusedItem).toBe("q1");
+ expect(state.hasContent).toBe(true);
+ expect(state.focusedObj.question).toBe("What would clarify this?");
+ });
+
+ it("Your response textarea visible when status is formulated and no processing active", () => {
+ const inv = simulateFormulationSuccess({}, "q1", "What would clarify this?");
+ const state = simulateInitialFocus({
+ focusedInvestigations: inv,
+ focusedPresentationItemId: "q1",
+ postAnalyseStatus: "success",
+ processingStep: "idle",
+ });
+
+ expect(state.focusedObj.status).toBe("formulated");
+ expect(state.hasContent).toBe(true);
+ });
+
+ it("deconstruction loading — processing text visible in same card", () => {
+ const inv = simulateAnswerSubmission(
+ simulateFormulationSuccess({}, "q1", "What would clarify this?"),
+ "q1",
+ "I believe the key factor is X"
+ );
+
+ const state = simulateInitialFocus({
+ focusedInvestigations: inv,
+ focusedPresentationItemId: "q1",
+ postAnalyseStatus: "success",
+ processingStep: "active",
+ });
+
+ expect(state.focusedItem).toBe("q1");
+ expect(state.hasContent).toBe(true);
+ });
+
+ it("completed result — What this tells us, Still unclear, Questions this raises visible", () => {
+ const inv = simulateDeconstructionSuccess(
+ simulateAnswerSubmission(
+ simulateFormulationSuccess({}, "q1", "What would clarify this?"),
+ "q1",
+ "I believe the key factor is X"
+ ),
+ "q1",
+ {
+ observations: ["Factor A is confirmed"],
+ uncertainties: ["Timing unknown"],
+ assumptions: [],
+ relationships: [],
+ possibleFollowUpQuestions: ["How does timing affect cost?"],
+ }
+ );
+
+ const state = simulateInitialFocus({
+ focusedInvestigations: inv,
+ focusedPresentationItemId: "q1",
+ postAnalyseStatus: "success",
+ processingStep: "idle",
+ });
+
+ expect(state.focusedItem).toBe("q1");
+ expect(state.hasContent).toBe(true);
+ expect(state.focusedObj.result.observations).toEqual(["Factor A is confirmed"]);
+ expect(state.focusedObj.result.uncertainties).toEqual(["Timing unknown"]);
+ expect(state.focusedObj.result.possibleFollowUpQuestions).toContain("How does timing affect cost?");
+ });
+
+ it("reopen same completed question — previous result visible again after Back", () => {
+ // Step 1: complete investigation
+ const inv = simulateDeconstructionSuccess(
+ simulateAnswerSubmission(
+ simulateFormulationSuccess({}, "nbfaikr", "What would clarify distinction between blockers and assumptions?"),
+ "nbfaikr",
+ "It is a capability issue"
+ ),
+ "nbfaikr",
+ {
+ observations: ["Structural blocker confirmed"],
+ uncertainties: [],
+ assumptions: [],
+ relationships: [],
+ possibleFollowUpQuestions: [],
+ }
+ );
+
+ // Step 2: user clicks "Back to open questions" — cleared focused but kept inv data
+ const postBack = simulateInitialFocus({
+ focusedInvestigations: inv,
+ focusedPresentationItemId: null,
+ postAnalyseStatus: "success",
+ });
+
+ expect(postBack.focusedItem).toBeNull();
+
+ // Step 3: user clicks same question again — result reopens
+ const reopened = simulateInitialFocus({
+ focusedInvestigations: inv,
+ focusedPresentationItemId: "nbfaikr",
+ postAnalyseStatus: "success",
+ });
+
+ expect(reopened.focusedItem).toBe("nbfaikr");
+ expect(reopened.hasContent).toBe(true);
+ expect(reopened.focusedObj.result.observations).toContain("Structural blocker confirmed");
+ });
+
+ it("Run B green Investigation card NOT rendered during focused lifecycle", () => {
+ const state = simulateInitialFocus({
+ focusedInvestigations: {},
+ focusedPresentationItemId: null,
+ postAnalyseStatus: "success",
+ });
+ expect(state.surfaceVisible).toBe(true);
+ });
+
+ it("Run B OpenQuestionsPanel does NOT replace Run A during focused lifecycle", () => {
+ const state = simulateInitialFocus({
+ focusedInvestigations: {},
+ focusedPresentationItemId: null,
+ postAnalyseStatus: "success",
+ });
+ expect(state.surfaceVisible).toBe(true);
+ });
+});