FlowPilot: /pilot/:id direct URL load shows blank main pane until sidebar click #142
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Symptom
Opening a FlowPilot session via direct URL in a fresh tab — either
/pilot/<session-id>or the Phase 1 legacy redirect/assistant/<session-id>— the main chat pane renders empty (no messages, no input state) until the user clicks the session in the left sidebar, at which point the conversation loads.Surfaced during Gate 1 verification of the FlowPilot migration (Phase 1) on 2026-04-21.
Reproduction
/pilot./pilot/<id>.Also reproducible via
/assistant/<id>(same redirect path throughAssistantSessionRedirect).What works correctly (ruled out)
AssistantSessionRedirectat frontend/src/router.tsx#L109-L112 correctly<Navigate>s to/pilot/<id>withreplace.GET /api/v1/ai-sessions/<id> HTTP/1.1 200~3 seconds after the redirect during a real session.Hypothesis
Render-before-load flash.
AssistantChatPageseedsactiveChatIdfromurlSessionIdon mount (AssistantChatPage.tsx#L36-L39) and firesselectChat(urlSessionId)viauseEffect(L106-L110), but the main pane renders once withmessages=[]andactiveChatId=<id>in the gap betweensetActiveChatId(chatId)(synchronous, L227) and the awaitedaiSessionsApi.getSession(chatId)resolving (L235). The pane probably has no loading state that covers this window — it just looks empty.Clicking the sidebar entry re-triggers
selectChat, but by then the original promise has already resolved — what actually fixed the UI is a re-render, not the second fetch.Proposed fixes
AssistantChatPage's main pane while the initialselectChatpromise is in flight. Gate on something likeisLoadingSessionset totrueat the top ofselectChatand cleared in the finally block.activeChatIdhighlights as "active" immediately whenactiveChatIdis URL-seeded. If it doesn't, the user perceives the session as unselected, which is the other half of the confusing UX.Low priority — no data loss, no broken state, just polish — but it's the kind of thing that makes the direct-URL path feel broken to anyone who hits it cold.
Context
Branch:
feat/flowpilot-migration(Phase 1 merged the/pilotroute unification).Related handoff doc (now deleted):
docs/FlowAssist_Migration/MIGRATION-HANDOFF.md§Gate 1 item 5.Closing — fixed.
The root cause was the
urlSessionId === activeChatIdgate bailing on direct-URL mount (they match becauseactiveChatIdis seeded fromurlSessionId), soselectChatnever fired. Replaced with aloadedChatIdsReftracking which URL chatIds were already loaded for the page lifecycle — see AssistantChatPage.tsx:259-301, which also documents the prior failure mode in-line.The page also picked up several related stale-flash fixes since (
665530f,8914391,b56da2f).