From 63a451524161212aee93777127cfc3a49ece2e8b Mon Sep 17 00:00:00 2001 From: Eyejoker Date: Wed, 3 Jun 2026 01:37:22 +0800 Subject: [PATCH] fix: resume owner after failed reviewer feedback (#208) --- src/paired-completion-signals.test.ts | 10 +++++++ src/paired-completion-signals.ts | 4 ++- src/paired-execution-context-reviewer.ts | 7 +++-- src/paired-execution-context.test.ts | 33 ++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/paired-completion-signals.test.ts b/src/paired-completion-signals.test.ts index 95f9197..9894c02 100644 --- a/src/paired-completion-signals.test.ts +++ b/src/paired-completion-signals.test.ts @@ -135,6 +135,16 @@ describe('paired completion signals', () => { visibleVerdict: 'done', }), ).toEqual({ kind: 'request_owner_finalize' }); + expect( + resolveReviewerFailureSignal({ + visibleVerdict: 'step_done', + }), + ).toEqual({ kind: 'request_owner_changes' }); + expect( + resolveReviewerFailureSignal({ + visibleVerdict: 'done_with_concerns', + }), + ).toEqual({ kind: 'request_owner_changes' }); expect( resolveReviewerFailureSignal({ visibleVerdict: 'needs_context', diff --git a/src/paired-completion-signals.ts b/src/paired-completion-signals.ts index b1ab590..146e81a 100644 --- a/src/paired-completion-signals.ts +++ b/src/paired-completion-signals.ts @@ -98,13 +98,15 @@ export function resolveReviewerFailureSignal(args: { case 'task_done': case 'done': return { kind: 'request_owner_finalize' }; + case 'step_done': + case 'done_with_concerns': + return { kind: 'request_owner_changes' }; case 'blocked': case 'needs_context': return { kind: 'complete', completionReason: 'escalated', }; - case 'done_with_concerns': case 'continue': default: return { kind: 'preserve_review_ready' }; diff --git a/src/paired-execution-context-reviewer.ts b/src/paired-execution-context-reviewer.ts index 119a1aa..4320b58 100644 --- a/src/paired-execution-context-reviewer.ts +++ b/src/paired-execution-context-reviewer.ts @@ -52,7 +52,8 @@ export function handleFailedReviewerExecution(args: { }); if ( signal.kind === 'request_owner_finalize' || - signal.kind === 'complete' + signal.kind === 'complete' || + signal.kind === 'request_owner_changes' ) { const ownerWs = signal.kind === 'request_owner_finalize' @@ -68,7 +69,9 @@ export function handleFailedReviewerExecution(args: { nextStatus: signal.kind === 'request_owner_finalize' ? 'merge_ready' - : 'completed', + : signal.kind === 'request_owner_changes' + ? 'active' + : 'completed', expectedUpdatedAt: task.updated_at, updatedAt: now, patch: { diff --git a/src/paired-execution-context.test.ts b/src/paired-execution-context.test.ts index 918b167..9597861 100644 --- a/src/paired-execution-context.test.ts +++ b/src/paired-execution-context.test.ts @@ -1445,3 +1445,36 @@ describe('paired execution context', () => { }); }); }); + +describe('paired execution context reviewer failures', () => { + beforeEach(() => { + vi.resetAllMocks(); + }); + + it('moves failed reviewer STEP_DONE output back to active for owner follow-up', () => { + const task = buildPairedTask({ + status: 'in_review', + updated_at: '2026-03-28T00:05:00.000Z', + }); + vi.mocked(db.getPairedTaskById).mockReturnValue(task); + + completePairedExecutionContext({ + taskId: task.id, + role: 'reviewer', + status: 'failed', + runId: 'run-failed-reviewer-step-done', + summary: 'STEP_DONE\n오너 수정이 더 필요합니다.', + }); + + expect(db.updatePairedTask).toHaveBeenCalledWith( + task.id, + expect.objectContaining({ + status: 'active', + }), + ); + expect(db.releasePairedTaskExecutionLease).toHaveBeenCalledWith({ + taskId: task.id, + runId: 'run-failed-reviewer-step-done', + }); + }); +});