From 7daa16fe307b69d11fc2a0d349d451f5474b0826 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Wed, 15 Jul 2026 17:12:32 -0700 Subject: [PATCH] FN-8002: suppress reconnecting hint on planning question screen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gate Planning Mode's "Reconnecting…" indicator to the loading view so persisted awaiting-input questions stay free of transient SSE reconnect noise. - Show planning.reconnecting only when view.type is "loading" - Cover desktop and mobile resumed question screens without the hint - Keep the hint during active generation loading reconnects - Add patch changeset for the user-facing fix Files changed: .changeset/FN-8002-planning-reconnecting-hint.md | 7 +++ .../dashboard/app/components/PlanningModeModal.tsx | 6 +- .../PlanningModeModal.planning-flow.test.tsx | 73 ++++++++++++++++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) Fusion-Task-Id: FN-8002 Fusion-Task-Lineage: 0a8682ee-922d-4acd-b7ce-bbf4f25dfce7 Co-authored-by: Fusion (runfusion.ai) --- .../FN-8002-planning-reconnecting-hint.md | 7 ++ .../app/components/PlanningModeModal.tsx | 6 +- .../PlanningModeModal.planning-flow.test.tsx | 73 +++++++++++++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 .changeset/FN-8002-planning-reconnecting-hint.md diff --git a/.changeset/FN-8002-planning-reconnecting-hint.md b/.changeset/FN-8002-planning-reconnecting-hint.md new file mode 100644 index 0000000000..eb76503d69 --- /dev/null +++ b/.changeset/FN-8002-planning-reconnecting-hint.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Suppress the Planning Mode reconnecting hint on persisted question screens. +category: fix +dev: Gate the `planning.reconnecting` indicator in `PlanningModeModal` to `view.type === "loading"` so idle `awaiting_input`/DB-backed views render purely from persisted state. diff --git a/packages/dashboard/app/components/PlanningModeModal.tsx b/packages/dashboard/app/components/PlanningModeModal.tsx index 40ef373e09..9c7b085073 100644 --- a/packages/dashboard/app/components/PlanningModeModal.tsx +++ b/packages/dashboard/app/components/PlanningModeModal.tsx @@ -2174,7 +2174,11 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat
{error &&
{error}
} - {isReconnecting &&
{t("planning.reconnecting", "Reconnecting…")}
} + {/* + FNXC:PlanningMode 2026-07-15-00:00: + Awaiting-input questions are persisted database state, so transient idle SSE reconnects must not imply that the question is being regenerated. Reserve this hint for the active loading view, where live generation genuinely depends on the stream. + */} + {isReconnecting && view.type === "loading" &&
{t("planning.reconnecting", "Reconnecting…")}
} {view.type === "initial" && (
diff --git a/packages/dashboard/app/components/__tests__/PlanningModeModal.planning-flow.test.tsx b/packages/dashboard/app/components/__tests__/PlanningModeModal.planning-flow.test.tsx index 3d0d34b924..bfa609371b 100644 --- a/packages/dashboard/app/components/__tests__/PlanningModeModal.planning-flow.test.tsx +++ b/packages/dashboard/app/components/__tests__/PlanningModeModal.planning-flow.test.tsx @@ -1935,6 +1935,79 @@ describe("PlanningModeModal", () => { expect(screen.queryByRole("button", { name: "Refine Further" })).toBeNull(); }); + it.each(["desktop", "mobile"] as const)("keeps persisted awaiting-input questions free of reconnecting hints on %s", async (viewportMode) => { + mockViewport(viewportMode); + let streamHandlers: any; + mockConnectPlanningStream.mockImplementationOnce((_sessionId: string, _projectId: string | undefined, handlers: any) => { + streamHandlers = handlers; + return { close: vi.fn(), isConnected: vi.fn().mockReturnValue(true) }; + }); + mockFetchAiSession.mockResolvedValueOnce({ + id: `session-reconnect-question-${viewportMode}`, + type: "planning", + status: "awaiting_input", + title: "Persisted question", + inputPayload: JSON.stringify({ initialPlan: "Resume persisted question" }), + conversationHistory: "[]", + currentQuestion: JSON.stringify(mockQuestion), + result: null, + thinkingOutput: "", + error: null, + projectId: null, + createdAt: "2026-01-01T00:00:00.000Z", + updatedAt: "2026-01-01T00:00:00.000Z", + }); + + render( + , + ); + + expect(await screen.findByText(mockQuestion.question)).toBeInTheDocument(); + act(() => { + streamHandlers.onConnectionStateChange?.("reconnecting"); + }); + + expect(screen.getByText(mockQuestion.question)).toBeInTheDocument(); + expect(screen.queryByText("Reconnecting…")).toBeNull(); + }); + + it("shows the reconnecting hint while active generation is loading", async () => { + let streamHandlers: any; + mockConnectPlanningStream.mockImplementationOnce((_sessionId: string, _projectId: string | undefined, handlers: any) => { + streamHandlers = handlers; + return { close: vi.fn(), isConnected: vi.fn().mockReturnValue(true) }; + }); + + render( + , + ); + + fireEvent.change(screen.getByPlaceholderText(/e.g., Build a user authentication/), { + target: { value: "Generate a planning task" }, + }); + fireEvent.click(screen.getByText("Start Planning")); + await waitFor(() => expect(mockConnectPlanningStream).toHaveBeenCalledTimes(1)); + + act(() => { + streamHandlers.onConnectionStateChange?.("reconnecting"); + }); + + expect(screen.getByText("Reconnecting…")).toBeInTheDocument(); + }); + it("shows summary view when resuming a complete persisted session", async () => { const resumedSummary: PlanningSummary = { title: "Resume-ready planning output",