fix(pilot): persist AI-proposal rejection + clear on outcome write
Issue #3 from phase-8-review-issues.md. 'Not yet' on the AI-confirming banner was a local-state hide; the proposal re-surfaced on the next refreshSessionDerived call. Two-part fix: - PATCH /outcome now clears ai_outcome_proposal on any terminal action (engineer has taken a decision; stale AI proposal is moot). - New DELETE /ai-sessions/:sid/suggested-fixes/:fid/ai-outcome-proposal endpoint for explicit 'Not yet' rejection. Does not touch status or state_version — pure UI state. Frontend handleRejectAIProposal now calls the DELETE and setActiveFix with the server response. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -196,6 +196,18 @@ export const sessionSuggestedFixesApi = {
|
||||
)
|
||||
return r.data
|
||||
},
|
||||
|
||||
/**
|
||||
* Explicitly dismiss the AI-proposed outcome banner ("Not yet").
|
||||
* Clears ai_outcome_proposal on the server without touching status or
|
||||
* state_version. Idempotent: returns 200 even when the field is already null.
|
||||
*/
|
||||
async clearAIProposal(sessionId: string, fixId: string): Promise<SessionSuggestedFix> {
|
||||
const r = await apiClient.delete<SessionSuggestedFix>(
|
||||
`/ai-sessions/${sessionId}/suggested-fixes/${fixId}/ai-outcome-proposal`,
|
||||
)
|
||||
return r.data
|
||||
},
|
||||
}
|
||||
|
||||
export default sessionSuggestedFixesApi
|
||||
|
||||
@@ -572,12 +572,20 @@ export default function AssistantChatPage() {
|
||||
await handleSetOutcome(fixOutcome, notes)
|
||||
}, [activeFix, handleSetOutcome])
|
||||
|
||||
// Phase 8: reject the AI proposal — clear it locally (client-side only for v1;
|
||||
// the proposal will re-surface on next server fetch but that's acceptable).
|
||||
const handleRejectAIProposal = useCallback(() => {
|
||||
if (!activeFix) return
|
||||
setActiveFix({ ...activeFix, ai_outcome_proposal: null })
|
||||
}, [activeFix])
|
||||
// Phase 8: reject the AI proposal — persist the rejection to the server so
|
||||
// the banner does not re-surface on the next refreshSessionDerived call.
|
||||
// Falls back to a local-state clear on error (non-fatal: banner may re-arm
|
||||
// on the next refetch, matching the previous behaviour).
|
||||
const handleRejectAIProposal = useCallback(async () => {
|
||||
if (!activeFix || !activeChatId) return
|
||||
try {
|
||||
const updated = await sessionSuggestedFixesApi.clearAIProposal(activeChatId, activeFix.id)
|
||||
setActiveFix(updated)
|
||||
} catch {
|
||||
// Non-fatal fallback: clear locally so the banner disappears immediately.
|
||||
setActiveFix({ ...activeFix, ai_outcome_proposal: null })
|
||||
}
|
||||
}, [activeFix, activeChatId])
|
||||
|
||||
// Phase 8: silence the nudge banner without recording an outcome.
|
||||
const handleSilenceNudge = useCallback(() => {
|
||||
|
||||
Reference in New Issue
Block a user