From aa6477cf2b84f168428fd81c36f5653a8b2fdd93 Mon Sep 17 00:00:00 2001 From: Eyejoker Date: Mon, 30 Mar 2026 01:37:30 +0900 Subject: [PATCH] fix: respect owner verdict during finalize turn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the reviewer approves (merge_ready) and the owner finalizes, the system previously only checked for code changes. If the owner raised concerns (DONE_WITH_CONCERNS, BLOCKED, NEEDS_CONTEXT) during finalize — e.g. push failed due to detached HEAD — the system ignored it and auto-completed the task. Now the owner's verdict is checked first. If the owner raises concerns, the task goes back to active and re-triggers the reviewer so the issue can be addressed collaboratively. --- src/paired-execution-context.ts | 64 +++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/src/paired-execution-context.ts b/src/paired-execution-context.ts index 1534db7..a1192d1 100644 --- a/src/paired-execution-context.ts +++ b/src/paired-execution-context.ts @@ -348,32 +348,52 @@ export function completePairedExecutionContext(args: { if (role === 'owner') { const now = new Date().toISOString(); - // merge_ready → reviewer already approved. Check if owner made - // additional changes that need re-review. + // merge_ready → reviewer already approved. Check owner verdict and + // whether owner made additional changes that need re-review. if (task.status === 'merge_ready') { - const workspace = getPairedWorkspace(task.id, 'owner'); - const hasNewChanges = workspace?.workspace_dir - ? hasCodeChangesSinceRef(workspace.workspace_dir, task.source_ref) - : null; - - if (hasNewChanges === false) { - // No code changes since reviewer approved → finalize complete - updatePairedTask(taskId, { status: 'completed', updated_at: now }); + // Owner can raise concerns even during finalize (e.g. push failed, + // detached HEAD, discovered issue). Respect the owner's verdict. + const ownerVerdict = classifyReviewerVerdict(args.summary); + if ( + ownerVerdict === 'done_with_concerns' || + ownerVerdict === 'blocked' || + ownerVerdict === 'needs_context' + ) { + updatePairedTask(taskId, { status: 'active', updated_at: now }); logger.info( - { taskId, summary: args.summary?.slice(0, 100) }, - 'Owner finalized after reviewer approval — task completed', + { + taskId, + ownerVerdict, + summary: args.summary?.slice(0, 100), + }, + 'Owner raised concerns during finalize — task set back to active', + ); + // Fall through to auto-trigger reviewer for the new concern + } else { + const workspace = getPairedWorkspace(task.id, 'owner'); + const hasNewChanges = workspace?.workspace_dir + ? hasCodeChangesSinceRef(workspace.workspace_dir, task.source_ref) + : null; + + if (hasNewChanges === false) { + // No code changes since reviewer approved → finalize complete + updatePairedTask(taskId, { status: 'completed', updated_at: now }); + logger.info( + { taskId, summary: args.summary?.slice(0, 100) }, + 'Owner finalized after reviewer approval — task completed', + ); + return; + } + // Owner made changes after approval → needs re-review + logger.info( + { + taskId, + sourceRef: task.source_ref, + hasNewChanges, + }, + 'Owner made changes after reviewer approval — re-triggering review', ); - return; } - // Owner made changes after approval → needs re-review - logger.info( - { - taskId, - sourceRef: task.source_ref, - hasNewChanges, - }, - 'Owner made changes after reviewer approval — re-triggering review', - ); } // Normal turn → auto-trigger reviewer (if within round trip limit)