From 92c66cc578489853be9c8c4ee510f7986546d1a3 Mon Sep 17 00:00:00 2001 From: Alex Alecu Date: Mon, 9 Mar 2026 17:13:06 +0200 Subject: [PATCH] fix(auto-fix): guard legacy create-pr endpoint against review-comment tickets The create-pr endpoint was being called by cloud-agent-next for review-comment tickets, bypassing the pr-callback route that correctly routes them to handleCommentReply. This caused duplicate notifications: a proper reply on the review thread plus a spurious issue-level comment on the PR main thread. Add a review_comment_id guard (rejects with 400) and a terminal-state check (returns early) so the endpoint can no longer interfere with tickets already handled by pr-callback. --- .../api/internal/auto-fix/create-pr/route.ts | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/app/api/internal/auto-fix/create-pr/route.ts b/src/app/api/internal/auto-fix/create-pr/route.ts index 3311025a1c..de8ac08e9f 100644 --- a/src/app/api/internal/auto-fix/create-pr/route.ts +++ b/src/app/api/internal/auto-fix/create-pr/route.ts @@ -19,7 +19,7 @@ import type { NextRequest } from 'next/server'; import { NextResponse } from 'next/server'; import { getFixTicketById, updateFixTicketStatus } from '@/lib/auto-fix/db/fix-tickets'; import { logExceptInTest, errorExceptInTest } from '@/lib/utils.server'; -import { captureException } from '@sentry/nextjs'; +import { captureException, captureMessage } from '@sentry/nextjs'; import { INTERNAL_API_SECRET } from '@/lib/config.server'; import { createPullRequest } from '@/lib/auto-fix/github/create-pull-request'; import { postIssueComment } from '@/lib/auto-fix/github/post-comment'; @@ -68,6 +68,44 @@ export async function POST(req: NextRequest) { return NextResponse.json({ error: 'Ticket not found' }, { status: 404 }); } + // Review-comment tickets should never go through this endpoint. + // They are handled entirely via handleCommentReply in the pr-callback route. + if (ticket.review_comment_id != null) { + errorExceptInTest( + '[auto-fix-create-pr] Rejecting review-comment ticket — use pr-callback instead', + { ticketId, reviewCommentId: ticket.review_comment_id } + ); + captureMessage('create-pr called for review-comment ticket', { + level: 'warning', + tags: { source: 'auto-fix-create-pr' }, + extra: { + ticketId, + sessionId, + reviewCommentId: ticket.review_comment_id, + triggerSource: ticket.trigger_source, + }, + }); + return NextResponse.json( + { error: 'Review-comment tickets are handled via pr-callback, not create-pr' }, + { status: 400 } + ); + } + + const isTerminalState = + ticket.status === 'completed' || ticket.status === 'failed' || ticket.status === 'cancelled'; + + if (isTerminalState) { + logExceptInTest('[auto-fix-create-pr] Ticket already in terminal state, skipping', { + ticketId, + currentStatus: ticket.status, + }); + return NextResponse.json({ + success: true, + message: 'Ticket already in terminal state', + currentStatus: ticket.status, + }); + } + try { // Use the provided branch name if available, otherwise default to session/{sessionId} // The agent may create a branch based on the prompt (e.g., auto-fix/{ticketId})