diff --git a/src/paired-execution-context.test.ts b/src/paired-execution-context.test.ts index 918b167..d6cac42 100644 --- a/src/paired-execution-context.test.ts +++ b/src/paired-execution-context.test.ts @@ -143,6 +143,7 @@ function buildPairedTask(overrides: Partial = {}): PairedTask { review_requested_at: null, round_trip_count: 0, owner_failure_count: 0, + reviewer_failure_count: 0, owner_step_done_streak: 0, finalize_step_done_count: 0, task_done_then_user_reopen_count: 0, @@ -1322,7 +1323,7 @@ describe('paired execution context', () => { ); }); - it('keeps reviewer tasks review_ready when reviewer execution fails without a terminal verdict', () => { + it('keeps reviewer tasks review_ready and increments reviewer_failure_count after the first silent failure', () => { vi.mocked(db.getPairedTaskById).mockReturnValue( buildPairedTask({ status: 'in_review', @@ -1340,11 +1341,38 @@ describe('paired execution context', () => { 'task-1', expect.objectContaining({ status: 'review_ready', + reviewer_failure_count: 1, updated_at: expect.any(String), }), ); }); + it('requests arbiter after repeated reviewer execution failures without a visible verdict', () => { + vi.spyOn(config, 'isArbiterEnabled').mockReturnValue(true); + vi.mocked(db.getPairedTaskById).mockReturnValue( + buildPairedTask({ + status: 'review_ready', + reviewer_failure_count: 1, + }), + ); + + completePairedExecutionContext({ + taskId: 'task-1', + role: 'reviewer', + status: 'failed', + summary: 'runtime exploded before verdict', + }); + + expect(db.updatePairedTask).toHaveBeenCalledWith( + 'task-1', + expect.objectContaining({ + status: 'arbiter_requested', + reviewer_failure_count: 2, + arbiter_requested_at: expect.any(String), + }), + ); + }); + it('keeps arbiter tasks arbiter_requested when arbiter execution fails without a terminal verdict', () => { vi.mocked(db.getPairedTaskById).mockReturnValue( buildPairedTask({