From faf1d8dd12773eb5b1835dd51729d9b12ce256a1 Mon Sep 17 00:00:00 2001 From: Michael Chihlas Date: Fri, 24 Apr 2026 04:11:56 -0400 Subject: [PATCH] fix(pilot): applied_at stamps on run-declaring actions, not Apply click MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per Phase 9 §5. Before: banner Apply click stamped applied_at regardless of whether the engineer had committed to running anything, starting the Verifying timer prematurely. After: - handleApplyFix no longer calls applyFix(). It just routes to the right surface (TemplateMatchPanel / InlineNoTemplateDialog / Script Builder tab). - handleScriptDecision stamps applied_at for one_off + draft_template (both labels are 'Run now, …' — the click is the declaration). build_template does not stamp. - TemplateMatchPanel's new 'I ran this' button calls applyFix via a new onMarkRun prop. - Script Builder tab Submit does not stamp (a draft is not a run). No backend change — the /apply endpoint is unchanged. Only call sites move. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/src/pages/AssistantChatPage.tsx | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/frontend/src/pages/AssistantChatPage.tsx b/frontend/src/pages/AssistantChatPage.tsx index 3b7a02d5..a742f1f4 100644 --- a/frontend/src/pages/AssistantChatPage.tsx +++ b/frontend/src/pages/AssistantChatPage.tsx @@ -515,6 +515,17 @@ export default function AssistantChatPage() { } else if (decision === 'draft_template') { toast.success('Draft template queued — review after Resolve') } + // Phase 9 §5: one_off and draft_template declare a run ("Run now, …"). + // Stamp applied_at to transition the fix into Verifying. + // build_template does NOT run — no stamp. + if (decision === 'one_off' || decision === 'draft_template') { + try { + const updated = await sessionSuggestedFixesApi.applyFix( + activeChatId, activeFix.id, + ) + setActiveFix(updated) + } catch { /* non-fatal: engineer can still mark outcome later */ } + } // Keep the panel open so the engineer can copy the rendered script. } catch { toast.error('Failed to record decision') @@ -552,6 +563,20 @@ export default function AssistantChatPage() { setChatTab('script_builder') }, [activeFix]) + // Phase 9 Task 13: TemplateMatchPanel "I ran this" — stamps applied_at so the + // ProposalBanner transitions from Proposed to Verifying. Shared useCallback so + // both render sites (narrow-drawer + side-panel) are identical. + const handleMarkRun = useCallback(async () => { + if (!activeFix || !activeChatId) return + try { + const updated = await sessionSuggestedFixesApi.applyFix( + activeChatId, activeFix.id, + ) + setActiveFix(updated) + setScriptPanelOpen(false) + } catch { /* non-fatal: engineer can still mark outcome later */ } + }, [activeFix, activeChatId]) + // Phase 8: record a terminal outcome for the active fix. Updates local state // on success. For applied_success also opens the Resolve preview. const handleSetOutcome = useCallback(async (outcome: FixOutcome, notes?: string) => { @@ -1697,6 +1722,7 @@ export default function AssistantChatPage() { fix={activeFix} sessionId={activeChatId} onClose={() => setScriptPanelOpen(false)} + onMarkRun={handleMarkRun} /> )}
@@ -1767,6 +1793,7 @@ export default function AssistantChatPage() { fix={activeFix} sessionId={activeChatId} onClose={() => setScriptPanelOpen(false)} + onMarkRun={handleMarkRun} /> )}