From 7ccf4c602bad74ba9688a17793e6f04d1a378739 Mon Sep 17 00:00:00 2001 From: Michael Chihlas Date: Tue, 21 Apr 2026 23:44:19 -0400 Subject: [PATCH] fix(pilot): reorder Phase 3 useCallbacks to avoid TDZ on render refreshSessionDerived's dep array referenced refreshActiveFix and schedulePreviewRefresh before they were declared. React evaluates useCallback deps synchronously during render, so the page blew up with "Cannot access 'refreshActiveFix' before initialization" before a single render completed. Moved the three leaf helpers above the aggregator. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/src/pages/AssistantChatPage.tsx | 84 ++++++++++++------------ 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/frontend/src/pages/AssistantChatPage.tsx b/frontend/src/pages/AssistantChatPage.tsx index c709e39c..833d9cad 100644 --- a/frontend/src/pages/AssistantChatPage.tsx +++ b/frontend/src/pages/AssistantChatPage.tsx @@ -267,48 +267,9 @@ export default function AssistantChatPage() { } }, []) - // Phase 3: convenience helper — refresh fact list, active fix, and (if open) - // schedule a preview refresh. Called after every chat send so the new state - // (PROMOTE-synthesized facts, new SUGGEST_FIX) appears in the lane. - const refreshSessionDerived = useCallback(async (chatId: string) => { - await Promise.all([refreshFacts(chatId), refreshActiveFix(chatId)]) - if (previewOpen) schedulePreviewRefresh(chatId) - }, [refreshFacts, refreshActiveFix, previewOpen, schedulePreviewRefresh]) - - const handleAddNote = async (text: string, summary: string | null) => { - if (!activeChatId) return - try { - const fact = await sessionFactsApi.create(activeChatId, { text, summary }) - setFacts(prev => [...prev, fact]) - schedulePreviewRefresh(activeChatId) - } catch { - toast.error('Failed to add note') - } - } - - const handleUpdateFact = async (factId: string, text: string, summary: string | null) => { - if (!activeChatId) return - try { - const updated = await sessionFactsApi.update(activeChatId, factId, { text, summary }) - setFacts(prev => prev.map(f => f.id === factId ? updated : f)) - schedulePreviewRefresh(activeChatId) - } catch { - toast.error('Failed to update fact') - } - } - - const handleDeleteFact = async (factId: string) => { - if (!activeChatId) return - try { - await sessionFactsApi.remove(activeChatId, factId) - setFacts(prev => prev.filter(f => f.id !== factId)) - schedulePreviewRefresh(activeChatId) - } catch { - toast.error('Failed to remove fact') - } - } - // Phase 3 — active suggested fix + resolution-note preview. + // Declared BEFORE refreshSessionDerived / handleAddNote so the useCallback + // dep arrays don't hit a temporal dead zone on React's synchronous render. const refreshActiveFix = useCallback(async (chatId: string) => { try { const fix = await sessionSuggestedFixesApi.getActive(chatId) @@ -351,6 +312,47 @@ export default function AssistantChatPage() { }, 500) }, [previewOpen, refreshPreview]) + // Phase 3: convenience helper — refresh fact list, active fix, and (if open) + // schedule a preview refresh. Called after every chat send so the new state + // (PROMOTE-synthesized facts, new SUGGEST_FIX) appears in the lane. + const refreshSessionDerived = useCallback(async (chatId: string) => { + await Promise.all([refreshFacts(chatId), refreshActiveFix(chatId)]) + if (previewOpen) schedulePreviewRefresh(chatId) + }, [refreshFacts, refreshActiveFix, previewOpen, schedulePreviewRefresh]) + + const handleAddNote = async (text: string, summary: string | null) => { + if (!activeChatId) return + try { + const fact = await sessionFactsApi.create(activeChatId, { text, summary }) + setFacts(prev => [...prev, fact]) + schedulePreviewRefresh(activeChatId) + } catch { + toast.error('Failed to add note') + } + } + + const handleUpdateFact = async (factId: string, text: string, summary: string | null) => { + if (!activeChatId) return + try { + const updated = await sessionFactsApi.update(activeChatId, factId, { text, summary }) + setFacts(prev => prev.map(f => f.id === factId ? updated : f)) + schedulePreviewRefresh(activeChatId) + } catch { + toast.error('Failed to update fact') + } + } + + const handleDeleteFact = async (factId: string) => { + if (!activeChatId) return + try { + await sessionFactsApi.remove(activeChatId, factId) + setFacts(prev => prev.filter(f => f.id !== factId)) + schedulePreviewRefresh(activeChatId) + } catch { + toast.error('Failed to remove fact') + } + } + const handleDismissFix = async () => { if (!activeChatId || !activeFix) return try {