
    iFg                       d Z ddlmZ ddlZddlZddlZddlZddlmZ  ed      Z	ddZ
	 	 	 d	 	 	 	 	 	 	 	 	 ddZddZ	 	 d 	 	 	 	 	 	 	 	 	 d!d	Zd"d#d
Zd$dZd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zy)%u~  
tests/test_watchdog_chairman_definition.py

task-2405 회귀 테스트 — 회장 정의 FALSE positive 5 case 알람 0건 보장
session-watchdog.sh 4 fix(A/B/C/D) 기반

회장 정의 (2026-05-03): TRUE positive(진짜 죽음)만 알람
FALSE positive 절대 0건 5 case:
  1. 진행 중 작업 (long-running)
  2. 완료 작업 (.done 발급)
  3. 회장 인지 (.escalate / .escalate.acked 발급)
  4. 후속 task 위임됨 (.superseded_by 마커 또는 다른 task md 언급)
  5. 진행 마커 (codex-gate, qc-done, done.merging, pr-creating, external-running)

시나리오:
  OK 케이스 (skip 검증, 알람 0건):
   1. test_escalate_marker_skips_chairman_def
   2. test_escalate_acked_skips_chairman_def
   3. test_escalate_and_acked_both_skips
   4. test_done_file_skips_and_status_promoted
   5. test_done_acked_skips_and_status_promoted
   6. test_done_notified_skips_and_status_promoted
   7. test_done_clear_skips
   8. test_superseded_by_marker_skips
   9. test_other_task_md_mentions_original_skips
  10. test_progress_marker_codex_gate_skips
  11. test_progress_marker_qc_done_skips
  12. test_progress_marker_done_merging_skips
  13. test_progress_marker_pr_creating_skips
  14. test_progress_marker_external_running_skips

  NG 케이스 (TRUE positive 검증, 알람 1건):
  15. test_truly_stalled_no_marker_alerts

  종합 검증:
  16. test_chairman_5_ng_cases_all_zero_alarm
    )annotationsN)Pathz//home/jay/workspace/scripts/session-watchdog.shc                
    d| iS )u   task-timers.json 포맷.tasks )r   s    >/home/jay/workspace/tests/test_watchdog_chairman_definition.py_build_timersr	   6   s    U    c                    t        j                  dt        j                  t        j                          |z               }| |d||dddS )uI   status=running 태스크 항목. start_time은 현재 - start_offset 초.z%Y-%m-%dT%H:%M:%S.000000runningr      )task_idteam_idstatus
start_time	task_fileretry_count	max_retry)timestrftime	localtime)r   r   r   start_offsetstart_tss        r   _running_taskr   ;   sM     }}"tyy{\12H
  r
   c                   dD ]  }| |z  j                  dd        | dz  dz  j                  t        j                  |      d       | dz  j                  d	d       | dz  d
z  j                  dd       t        j                  d      }|j                  dd|  d      }| dz  dz  }|j                  |d       |j                  d       |S )u   
    tmp_path 아래 필수 디렉토리·파일을 생성하고
    WORKSPACE가 tmp_path를 가리키도록 패치된 스크립트를 반환.
    )zmemory/eventszmemory/heartbeatszmemory/taskslogsscriptsT)parentsexist_okmemorytask-timers.jsonutf-8encodingz	.env.keyszANU_BOT_TOKEN=dummy
ztask-timer.pyz#!/usr/bin/env python3
zWORKSPACE="/home/jay/workspace"zWORKSPACE=""r   zsession-watchdog.shi  )mkdir
write_textjsondumpsORIG_SCRIPT	read_textreplacechmod)tmp_pathtimersdorigpatchedscript_paths         r   setup_workspacer4   Q   s   
 : 
ATD9: --99

6W : 
 ''(?''R ?*66"W 7 
   ' 2Dll)
hZq!G Y&)>>K7W5er
   c           	     H   t         j                  j                         }d|d<   |r|j                  |       t	        j
                  dt        |       gddt        |xs |      |d      }|dz  dz  }|j                         r|j                  d	
      nd}|j                  |fS )uZ   
    WATCHDOG_DRY_RUN=1로 스크립트 실행 후 (returncode, log_contents) 반환.
    1WATCHDOG_DRY_RUNbashT   )capture_outputtextcwdenvtimeoutr   zsession-watchdog.logr"   r#    )
osenvironcopyupdate
subprocessrunstrexistsr+   
returncode)r3   r.   	extra_envr<   r=   resultlog_filelog_contents           r   run_watchdogrM   y   s     **//
C!C

9^^	[!"x F & #99H:B//:K($$g$6QSKk))r
   c                    | j                          |dkD  r0t        j                         |z
  }t        j                  | ||f       yy)u<   파일 생성 후 mtime을 (현재 - age_seconds)로 설정.r   N)touchr   r@   utime)pathage_secondsts      r   
touch_filerT      s9    JJLQIIK+%
1v r
   c                t    t        j                  | j                               d   |   j                  dd      S )uM   task-timers.json에서 특정 task의 status 읽기 (Fix B 박제 검증용).r   r   r   )r(   loadsr+   get)timers_filetids     r   _read_statusrZ      s1    ::k++-.w7<@@9UUr
   c                P   d}t        |t        |d      i      }t        | |      }| dz  dz  | dz  }t        |d       t        | dz  dz  | d	z         t	        ||       \  }}|d
k(  sJ d|v sd|v s
J d|        | d|vs
J d|        d|v s| d|vs
J d|        yy)u   
    task-2405 회장 정의 Fix A:
    .escalate 단독 마커 존재 → skip, 로그에 '알람 억제' 포함 (알람 0건).
    회장 승인 대기 상태에서는 절대 알람 없음.
    z
task-cd001	dev2-teamr    
heartbeats
.heartbeat  rR   events	.escalater   u   알람 억제u   회장 승인 대기u   escalate 억제 로그 없음: (team=uK   escalate 단독 상태에서 stalled 알람 발생 (회장 정의 위반): u   알람 없음u    알람 발생 (FALSE positive): Nr	   r   r4   rT   rM   r.   rY   r/   r3   hbrclogs          r   'test_escalate_marker_skips_chairman_defri      s    CCsK!@ABF!(F3K 
H	|	+Z.@	@Brt$ x("X-3%y0AAB;1GB7N7c!%;s%B 0
)#/0BU&>$ \
UVYUZ[\$c!uF^3%> 1
*3%01>%>!r
   c                J   d}t        |t        |d      i      }t        | |      }| dz  dz  | dz  }t        |d       t        | dz  dz  | d	z         t	        ||       \  }}|d
k(  sJ | d|vs
J d|        d|v r!||j                  d      d   vs
J d|        yy)u   
    task-2405 회장 정의 Fix A 핵심:
    .escalate.acked 존재 → 회장이 이미 인지 = 알람 그만 → skip.
    acked = 회장 인지 = 더 이상 알람 불필요.
    z
task-cd002r\   r    r]   r^   r_   r`   ra   .escalate.ackedr   rc   uQ   escalate.acked 상태에서 stalled 알람 발생 (회장 정의 핵심 위반): DRY_RUN   u9   DRY_RUN 알람 본문에 tid 포함됨 (FALSE positive): N)r	   r   r4   rT   rM   splitre   s          r   &test_escalate_acked_skips_chairman_defro      s     CCsK!@ABF!(F3K 
H	|	+Z.@	@Brt$ x("X-3%0GGH;1GB7N7U&>$ b
[\_[`ab$ C#))I.q11 	NGuM	N1 r
   c                &   d}t        |t        |d      i      }t        | |      }| dz  dz  | dz  }t        |d       | dz  dz  }t        || d	z         t        || d
z         t	        ||       \  }}|dk(  sJ | d|vs
J d|        y)ur   
    task-2405 회장 정의 Fix A:
    .escalate + .escalate.acked 둘 다 있어도 → skip (알람 0건).
    z
task-cd003r\   r    r]   r^   r_   r`   ra   rb   rk   r   rc   uN   escalate+acked 모두 있는데 stalled 알람 발생 (회장 정의 위반): Nrd   )r.   rY   r/   r3   rf   
events_dirrg   rh   s           r   "test_escalate_and_acked_both_skipsrr      s    
 CCsK!@ABF!(F3K	H	|	+Z.@	@Brt$H$x/Jzse9--.zse?334;1GB7N7U&>$ _
XY\X]^_$r
   c                H   d}t        |t        |d      i      }t        | |      }| dz  dz  }| dz  dz  | dz  }t        |d       t        | dz  d	z  | d
z         t	        ||       \  }}|dk(  sJ | d|vs
J d|        t        ||      }|dk(  sJ d| d       y)u   
    task-2405 회장 정의 Fix B:
    .done 파일 존재 → 완료 처리 skip + task-timers.json에 status=escalated 박제.
    z
task-cd004r\   r    r!   r]   r^   r_   r`   ra   .doner   rc   u>   .done 있는데 stalled 알람 발생 (회장 정의 위반): 	escalatedu;   .done 후 status 박제 실패 (기대: escalated, 실제: )Nr	   r   r4   rT   rM   rZ   	r.   rY   r/   r3   rX   rf   rg   rh   status_afters	            r   (test_done_file_skips_and_status_promotedrz   
  s    
 CCsK!@ABF!(F3KX%(::K	H	|	+Z.@	@Brt$ x("X-3%u=>;1GB7N7U&>$ O
HNO$  S1L;& V
El^STUV&r
   c                F   d}t        |t        |d      i      }t        | |      }| dz  dz  }| dz  dz  | dz  }t        |d       t        | dz  d	z  | d
z         t	        ||       \  }}|dk(  sJ | d|vs
J d|        t        ||      }|dk(  s
J d|        y)uc   
    task-2405 회장 정의 Fix B:
    .done.acked 존재 → skip + status=escalated 박제.
    z
task-cd005r\   r    r!   r]   r^   r_   r`   ra   z.done.ackedr   rc   u-   .done.acked 있는데 stalled 알람 발생: ru   u&   .done.acked 후 status 박제 실패: Nrw   rx   s	            r   )test_done_acked_skips_and_status_promotedr|   +  s    
 CCsK!@ABF!(F3KX%(::K	H	|	+Z.@	@Brt$x("X-3%{0CCD;1GB7N7U&>$ >
7u=>$  S1L;& @
0?@&r
   c                F   d}t        |t        |d      i      }t        | |      }| dz  dz  }| dz  dz  | dz  }t        |d       t        | dz  d	z  | d
z         t	        ||       \  }}|dk(  sJ | d|vs
J d|        t        ||      }|dk(  s
J d|        y)u   
    task-2405 회장 정의 Fix B 신규 마커:
    .done.notified 존재 → skip + status=escalated 박제.
    notified = 완료 알림 발송됨 = 알람 불필요.
    z
task-cd006r\   r    r!   r]   r^   r_   r`   ra   z.done.notifiedr   rc   uP   .done.notified 있는데 stalled 알람 발생 (Fix B 신규 마커 미처리): ru   u)   .done.notified 후 status 박제 실패: Nrw   rx   s	            r   ,test_done_notified_skips_and_status_promotedr~   J  s     CCsK!@ABF!(F3KX%(::K	H	|	+Z.@	@Brt$ x("X-3%~0FFG;1GB7N7U&>$ a
Z[^Z_`a$  S1L;& C
3L>BC&r
   c                    d}t        |t        |d      i      }t        | |      }| dz  dz  | dz  }t        |d       t        | dz  dz  | d	z         t	        ||       \  }}|d
k(  sJ | d|vs
J d|        y)ue   
    task-2405 회장 정의 Fix B:
    .done.clear 존재 → 완료 처리 skip (알람 0건).
    z
task-cd007r\   r    r]   r^   r_   r`   ra   z.done.clearr   rc   u-   .done.clear 있는데 stalled 알람 발생: Nrd   re   s          r   test_done_clear_skipsr   k  s    
 CCsK!@ABF!(F3K	H	|	+Z.@	@Brt$x("X-3%{0CCD;1GB7N7U&>$ >
7u=>$r
   c                F   d}t        |t        |d      i      }t        | |      }| dz  dz  }| dz  dz  | dz  }t        |d       t        | dz  d	z  | d
z         t	        ||       \  }}|dk(  sJ | d|vs
J d|        t        ||      }|dk(  s
J d|        y)u   
    task-2405 회장 정의 Fix C:
    <task_id>.superseded_by 마커 존재 → 후속 task에 위임됨 → skip + 박제.
    z
task-cd008r\   r    r!   r]   r^   r_   r`   ra   .superseded_byr   rc   uF   .superseded_by 마커 있는데 stalled 알람 발생 (Fix C 위반): ru   u)   .superseded_by 후 status 박제 실패: Nrw   rx   s	            r   test_superseded_by_marker_skipsr     s    
 CCsK!@ABF!(F3KX%(::K	H	|	+Z.@	@Brt$ x("X-3%~0FFG;1GB7N7U&>$ W
PQTPUVW$  S1L;& C
3L>BC&r
   c                   d}t        |t        |d      i      }t        | |      }| dz  dz  }| dz  dz  | dz  }t        |d       | dz  d	z  | d
z  j	                  dd       | dz  d	z  dz  j	                  d| dd       t        ||       \  }}|dk(  sJ | d|vs
J d|        t        ||      }|dk(  s
J d|        y)u   
    task-2405 회장 정의 Fix C 2순위:
    후속 task md 본문에 원본 task_id 언급 → 후속 위임됨으로 판단 → skip + 박제.
    z
task-cd009r\   r    r!   r]   r^   r_   r`   r   z.mdu6   # Original task
---
team: dev2-team
---
작업 내용
r"   r#   ztask-9999.mdu    # 후속 task
## 배경
원본: u    실패 후 재작업
r   rc   uJ   후속 task md 언급인데 stalled 알람 발생 (Fix C 2순위 위반): ru   u0   후속 task md 언급 후 status 박제 실패: N)r	   r   r4   rT   r'   rM   rZ   rx   s	            r   *test_other_task_md_mentions_original_skipsr     s:   
 CCsK!@ABF!(F3KX%(::K	H	|	+Z.@	@Brt$ 7"uC[0<<
E =  7"^3??
,SE1HI @ 
 ;1GB7N7U&>$ [
TUXTYZ[$  S1L;& J
:<.IJ&r
   c                   d}t        |t        |d      i      }t        | |      }| dz  dz  | dz  }t        |d       t        | dz  dz  | d	z         t	        ||       \  }}|d
k(  sJ d|v s
J d|        | d|vs
J d|        y)u   
    task-2405 회장 정의 5번 (진행 마커):
    events/<tid>.codex-gate 존재 + heartbeat 노후 → alive (알람 0건).
    long-running 단계 보호 — Codex G1/G2 검증 중.
    z
task-cd010r\   r    r]   r^   r_   r`   ra   .codex-gater   alive (long-running)u'   codex-gate 마커 alive 로그 없음: rc   u6   codex-gate 진행 마커인데 stalled 알람 발생: Nrd   re   s          r   %test_progress_marker_codex_gate_skipsr     s     CCsK!@ABF!(F3K	H	|	+Z.@	@Brt$x("X-3%{0CCD;1GB7N7!S( 8
1#78(U&>$ G
@FG$r
   c                   d}t        |t        |d      i      }t        | |      }| dz  dz  | dz  }t        |d       t        | dz  dz  | d	z         t	        ||       \  }}|d
k(  sJ d|v s
J d|        | d|vs
J d|        y)u   
    task-2405 회장 정의 5번:
    events/<tid>.qc-done 존재 + heartbeat 노후 → alive (알람 0건).
    QC 진행 중 단계 보호.
    z
task-cd011r\   r    r]   r^   r_   r`   ra   z.qc-doner   r   u$   qc-done 마커 alive 로그 없음: rc   u3   qc-done 진행 마커인데 stalled 알람 발생: Nrd   re   s          r   "test_progress_marker_qc_done_skipsr     s     CCsK!@ABF!(F3K	H	|	+Z.@	@Brt$x("X-3%x0@@A;1GB7N7!S( 5
.se45(U&>$ D
=cUCD$r
   c                   d}t        |t        |d      i      }t        | |      }| dz  dz  | dz  }t        |d       t        | dz  dz  | d	z         t	        ||       \  }}|d
k(  sJ d|v s
J d|        | d|vs
J d|        y)u   
    task-2405 회장 정의 5번:
    events/<tid>.done.merging 존재 + heartbeat 노후 → alive (알람 0건).
    G3 머지 진행 중 단계 보호.
    z
task-cd012r\   r    r]   r^   r_   r`   ra   z.done.mergingr   r   u)   done.merging 마커 alive 로그 없음: rc   u8   done.merging 진행 마커인데 stalled 알람 발생: Nrd   re   s          r   'test_progress_marker_done_merging_skipsr   	  s     CCsK!@ABF!(F3K	H	|	+Z.@	@Brt$x("X-3%}0EEF;1GB7N7!S( :
3C59:(U&>$ I
B3%HI$r
   c                   d}t        |t        |d      i      }t        | |      }| dz  dz  | dz  }t        |d       t        | dz  dz  | d	z         t	        ||       \  }}|d
k(  sJ d|v s
J d|        | d|vs
J d|        y)u   
    task-2405 회장 정의 5번:
    events/<tid>.pr-creating 존재 + heartbeat 노후 → alive (알람 0건).
    PR 생성 중 단계 보호 (신규 마커).
    z
task-cd013r\   r    r]   r^   r_   r`   ra   z.pr-creatingr   r   u(   pr-creating 마커 alive 로그 없음: rc   u7   pr-creating 진행 마커인데 stalled 알람 발생: Nrd   re   s          r   &test_progress_marker_pr_creating_skipsr   &  s     CCsK!@ABF!(F3K	H	|	+Z.@	@Brt$x("X-3%|0DDE;1GB7N7!S( 9
23%89(U&>$ H
A#GH$r
   c                   d}t        |t        |d      i      }t        | |      }| dz  dz  | dz  }t        |d       t        | dz  dz  | d	z         t	        ||       \  }}|d
k(  sJ d|v s
J d|        | d|vs
J d|        y)u   
    task-2405 회장 정의 5번:
    events/<tid>.external-running 존재 + heartbeat 노후 → alive (알람 0건).
    외부 CLI 호출 중 단계 보호 (신규 마커).
    z
task-cd014r\   r    r]   r^   r_   r`   ra   .external-runningr   r   u-   external-running 마커 alive 로그 없음: rc   u<   external-running 진행 마커인데 stalled 알람 발생: Nrd   re   s          r   +test_progress_marker_external_running_skipsr   C  s     CCsK!@ABF!(F3K	H	|	+Z.@	@Brt$x("X-3%7H0IIJ;1GB7N7!S( >
7u=>(U&>$ M
FseLM$r
   c                   d}t        |t        |d      i      }t        | |      }| dz  dz  | dz  }t        |d       t	        ||       \  }}|dk(  sJ d	|v s
J d
|        d|v s
J d|        ||v s
J d|        y)u  
    task-2405 회장 정의 TRUE positive:
    모든 마커 부재 + heartbeat 노후 + events 노후 + PR/worktree 부재 → 알람 1건.
    ★ 이 케이스만이 진짜 죽음 = 알람이 발생해야 정상.

    조건:
    - .escalate 없음
    - .escalate.acked 없음
    - .done 계열 없음
    - .superseded_by 없음
    - 진행 마커 없음
    - heartbeat 2000s 노후 (임계 초과)
    - events 파일 없음 (activity 없음)
    - gh/git worktree 없음 (DRY_RUN 환경)
    z
task-cd015	dev1-teamr    r]   r^   r_   r`   r   STALLEDu5   TRUE positive 케이스에서 STALLED 판정 없음: rl   uH   TRUE positive 케이스에서 알람 미발생 (watchdog 무력화됨): u.   TRUE positive tid가 알람 본문에 없음: Nrd   re   s          r   #test_truly_stalled_no_marker_alertsr   e  s      CCsK!@ABF!(F3K 
H	|	+Z.@	@Brt$ ;1GB7N7ZTUXTYZZmghkglmm#:MGuMM:r
   c                   d}d}d}d}d}t        |t        |d      |t        |d      |t        |d      |t        |d      |t        |d      i      }t        | |      }| dz  dz  }| dz  d	z  }	|||||fD ]  }
t        |	|
 d
z  d        t        || dz         t        || dz         t        || dz         t        || dz         t        || dz         t	        ||       \  }|dk(  sJ |||||fD ]  }
|
 dvrJ d|
 d         dv r:dv rj                  d      d   nd}|||||fD ]  }
|
 d|vrJ d|
 d         t        fd|||||fD              }|dk(  sJ d| d        y)u  
    task-2405 회장 정의 종합 검증:
    5가지 FALSE positive 케이스를 5개 task로 한번에 실행 → 총 알람 0건.

    task-cd020: 진행 중 작업 (long-running, codex-gate 마커)
    task-cd021: 완료 작업 (.done 발급)
    task-cd022: 회장 인지 (.escalate.acked)
    task-cd023: 후속 task 위임됨 (.superseded_by)
    task-cd024: 진행 마커 (external-running)
    z
task-cd020z
task-cd021z
task-cd022z
task-cd023z
task-cd024r\   r    ra   r]   r^   r_   r`   r   rt   rk   r   r   r   rc   u   [종합검증] u:    알람 발생 (FALSE positive — 회장 정의 위반): rl   rm   r?   u(   [종합검증] DRY_RUN 알람 본문에 u    포함됨 (FALSE positive): c              3  F   K   | ]  }j                  | d         yw)rc   N)count).0rY   rh   s     r   	<genexpr>z:test_chairman_5_ng_cases_all_zero_alarm.<locals>.<genexpr>  s(       			SE.!s   !u)   [종합검증] 5 FALSE positive case 중 u   건 알람 발생: N)r	   r   r4   rT   rM   rn   sum)r.   tid_long_runningtid_done	tid_ackedtid_supersededtid_progressr/   r3   rq   hb_dirrY   rg   dry_run_sectionstalled_countrh   s                 @r   'test_chairman_5_ng_cases_all_zero_alarmr     sh    $HI!NL-(8+F-+6=K8nkBmL+> F "(F3KH$x/J </F !(I~|T B6se:..DAB z/0<<= zxj../ zyk99: z~.n==> z|n,=>>?;1GB7N7 !(I~|T cf~S( 	ccU"\]`\ab	c(c
 C5>#5E#))I.q12$h	><X 	cCU&>8 c:3%?\]`\abc8	c
  $h	><X M A \
3M?BUVYUZ[\r
   )r   dictreturnr   )r   r?   i)
r   rF   r   rF   r   rF   r   intr   r   )r.   r   r/   r   r   r   )NN)
r3   r   r.   r   rI   zdict | Noner<   zPath | Noner   ztuple[int, str])r   )rQ   r   rR   r   r   None)rX   r   rY   rF   r   rF   ) __doc__
__future__r   r(   r@   rD   r   pathlibr   r*   r	   r   r4   rM   rT   rZ   ri   ro   rr   rz   r|   r~   r   r   r   r   r   r   r   r   r   r   r   r
   r   <module>r      s"  $L #  	    DE 	  	
 
,%V "	*** * 
	*
 *8V1BNB_8VB@>CB>4CB!JRG:D:I:H:MD"N^F\r
   