From cdd29b460e707f32b0e69523bd5853dd08433ff5 Mon Sep 17 00:00:00 2001 From: Michael Chihlas Date: Thu, 23 Apr 2026 15:20:16 -0400 Subject: [PATCH] feat(pilot): frontend fix-outcome types + patchOutcome API Extends SessionSuggestedFix with outcome fields (status, applied_at, verified_at, partial_notes, failure_reason, ai_outcome_proposal) and adds a patchOutcome method hitting the new backend endpoint. FixStatus (5 values) + FixOutcome (4 writable values) mirror the backend Pydantic types and the DB check constraint. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/src/api/sessionSuggestedFixes.ts | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/frontend/src/api/sessionSuggestedFixes.ts b/frontend/src/api/sessionSuggestedFixes.ts index c9974312..078d0d87 100644 --- a/frontend/src/api/sessionSuggestedFixes.ts +++ b/frontend/src/api/sessionSuggestedFixes.ts @@ -8,6 +8,25 @@ import apiClient from './client' export type UserDecision = 'one_off' | 'draft_template' | 'build_template' | 'dismissed' +export type FixStatus = + | 'proposed' + | 'applied_success' + | 'applied_failed' + | 'applied_partial' + | 'dismissed' + +export type FixOutcome = + | 'applied_success' + | 'applied_failed' + | 'applied_partial' + | 'dismissed' + +export interface AIOutcomeProposal { + fix_id: string + outcome: 'success' | 'failure' | 'partial' + reason: string +} + export interface SessionSuggestedFix { id: string session_id: string @@ -18,6 +37,12 @@ export interface SessionSuggestedFix { ai_drafted_script: string | null ai_drafted_parameters: Record | null user_decision: UserDecision | null + status: FixStatus + applied_at: string | null + verified_at: string | null + partial_notes: string | null + failure_reason: string | null + ai_outcome_proposal: AIOutcomeProposal | null superseded_at: string | null created_at: string } @@ -86,6 +111,27 @@ export const sessionSuggestedFixesApi = { return r.data }, + /** + * Record the outcome of applying a suggested fix. Transition rules: + * - from `proposed` or `applied_partial`: any outcome is valid (partial is + * parked, not terminal — engineer may update notes, abandon via dismiss, + * or advance to success/failed). + * - from a terminal status (`applied_success`, `applied_failed`, `dismissed`): + * server returns 409. + */ + async patchOutcome( + sessionId: string, + fixId: string, + outcome: FixOutcome, + notes?: string, + ): Promise { + const r = await apiClient.patch( + `/ai-sessions/${sessionId}/suggested-fixes/${fixId}/outcome`, + { outcome, notes }, + ) + return r.data + }, + /** * Fetch (or get cached) draft markdown for the Resolve note. Backend cache * is keyed on state_version, so calling this back-to-back without intervening