import { describe, expect, it } from 'vitest'; import { parseVisibleVerdict, isUserInputWaitVerdict, parseReviewerVisibleVerdict, resolveOwnerCompletionSignal, resolveReviewerCompletionSignal, resolveReviewerFailureSignal, } from './paired-execution-context-shared.js'; describe('paired execution context shared verdict helpers', () => { it('parses visible verdicts from the first summary line only', () => { expect(parseVisibleVerdict('STEP_DONE\nmore to do')).toBe('step_done'); expect(parseVisibleVerdict('TASK_DONE\nall done')).toBe('task_done'); expect(parseVisibleVerdict('APPROVE\nlooks good')).toBe('task_done'); expect(parseVisibleVerdict('APPROVED\nlooks good')).toBe('task_done'); expect( parseVisibleVerdict( 'DONE_WITH_CONCERNS\n\nfollow-up detail that should not affect parsing', ), ).toBe('done_with_concerns'); expect(parseVisibleVerdict('BLOCKED\nextra detail')).toBe('blocked'); expect(parseVisibleVerdict('random prose')).toBe('continue'); expect(parseVisibleVerdict('PROCEED — arbiter-style text')).toBe( 'continue', ); expect( parseReviewerVisibleVerdict('PROCEED — review approved, no work left'), ).toBe('task_done'); }); it('detects STEP_DONE summaries that are only waiting for user input', () => { expect( isUserInputWaitVerdict( 'STEP_DONE — 대기 유지. whoami 결과를 보내주면 바로 SSH 로그인 테스트합니다.', ), ).toBe(true); expect( isUserInputWaitVerdict( 'STEP_DONE\n키 등록 끝나면 알려주세요. 그 전까지 더 안 보냅니다.', ), ).toBe(true); expect( isUserInputWaitVerdict('STEP_DONE\n1단계 완료, 다음 단계 진행합니다.'), ).toBe(false); expect( isUserInputWaitVerdict('TASK_DONE\n사용자 입력 대기 없이 완료'), ).toBe(false); }); it('maps normal owner completion verdicts to reviewer or arbiter signals', () => { expect( resolveOwnerCompletionSignal({ phase: 'normal', visibleVerdict: 'step_done', }), ).toEqual({ kind: 'request_reviewer', resetStatusToActive: false, }); expect( resolveOwnerCompletionSignal({ phase: 'normal', visibleVerdict: 'done', }), ).toEqual({ kind: 'request_reviewer', resetStatusToActive: false, }); expect( resolveOwnerCompletionSignal({ phase: 'normal', visibleVerdict: 'blocked', }), ).toEqual({ kind: 'request_arbiter' }); }); it('maps finalize owner outcomes to complete, re-review, or arbiter', () => { expect( resolveOwnerCompletionSignal({ phase: 'finalize', visibleVerdict: 'step_done', hasChangesSinceApproval: false, roundTripCount: 0, deadlockThreshold: 2, }), ).toEqual({ kind: 'request_reviewer', resetStatusToActive: true, }); expect( resolveOwnerCompletionSignal({ phase: 'finalize', visibleVerdict: 'done', hasChangesSinceApproval: false, roundTripCount: 0, deadlockThreshold: 2, }), ).toEqual({ kind: 'complete', completionReason: 'done' }); expect( resolveOwnerCompletionSignal({ phase: 'finalize', visibleVerdict: 'done_with_concerns', hasChangesSinceApproval: false, roundTripCount: 1, deadlockThreshold: 3, }), ).toEqual({ kind: 'request_reviewer', resetStatusToActive: true, }); expect( resolveOwnerCompletionSignal({ phase: 'finalize', visibleVerdict: 'done', hasChangesSinceApproval: true, roundTripCount: 3, deadlockThreshold: 3, }), ).toEqual({ kind: 'request_arbiter' }); }); it('maps reviewer completion verdicts to finalize, owner changes, or arbiter', () => { expect( resolveReviewerCompletionSignal({ visibleVerdict: parseVisibleVerdict('APPROVE\nverified'), roundTripCount: 2, deadlockThreshold: 2, }), ).toEqual({ kind: 'request_owner_finalize' }); expect( resolveReviewerCompletionSignal({ visibleVerdict: 'task_done', roundTripCount: 0, deadlockThreshold: 3, }), ).toEqual({ kind: 'request_owner_finalize' }); expect( resolveReviewerCompletionSignal({ visibleVerdict: 'step_done', roundTripCount: 0, deadlockThreshold: 3, }), ).toEqual({ kind: 'request_owner_changes' }); expect( resolveReviewerCompletionSignal({ visibleVerdict: 'done', roundTripCount: 0, deadlockThreshold: 3, }), ).toEqual({ kind: 'request_owner_finalize' }); expect( resolveReviewerCompletionSignal({ visibleVerdict: 'continue', roundTripCount: 1, deadlockThreshold: 3, }), ).toEqual({ kind: 'request_owner_changes' }); expect( resolveReviewerCompletionSignal({ visibleVerdict: 'done_with_concerns', roundTripCount: 3, deadlockThreshold: 3, }), ).toEqual({ kind: 'request_arbiter' }); }); it('maps reviewer failure verdicts to explicit failure signals', () => { expect( resolveReviewerFailureSignal({ visibleVerdict: 'task_done', }), ).toEqual({ kind: 'request_owner_finalize' }); expect( resolveReviewerFailureSignal({ visibleVerdict: 'done', }), ).toEqual({ kind: 'request_owner_finalize' }); expect( resolveReviewerFailureSignal({ visibleVerdict: 'needs_context', }), ).toEqual({ kind: 'complete', completionReason: 'escalated' }); expect( resolveReviewerFailureSignal({ visibleVerdict: 'continue', }), ).toEqual({ kind: 'preserve_review_ready' }); }); });