
    TiY                      U 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ZddlZddl	Z	ddl
Z
ddlmZmZ ddlmZ ddlmZmZmZ  eej&                  j)                  dd            Zed	z  d
z  Zed	z  dz  Zedz  dz  Zedz  dz  Zedz  dz  Zedz  dz  dz  ZdZdZded<   dZded<   i dh ddddhdddhddhdh dd dd!hd!d"hd"h d#d$d%d"hd%h d&d'h d(d)d*d"hd+h d,d*h d-d.d/d0hd/d1hd1 e         e         e         e        h d2d"d3hd4Z!d5ed6<   h d7Z"d8ed9<   dtd:Z#dtd;Z$dud<Z%dvd=Z&dvd>Z'dwd?Z(dxd@Z)edwdA       Z*edydB       Z*dCdDdydEZ*dzdFZ+dddCdG	 	 	 	 	 d{dHZ,d|dIZ-d}d~dJZ.ddKZ/ddLddM	 	 	 ddNZ0ddOZ1ddPZ2ddQZ3	 	 	 	 	 	 	 	 	 	 	 	 ddRZ4ddSZ5ddTZ6ddUZ7ddVZ8ddWZ9dwdXZ:ddYZ;ddZZ<dd[Z=	 d	 	 	 dd\Z>dd]Z?dd^Z@dd_ZAdd`ZBddaZCddbZDddcZEdddZFddeZGddfZHddgZIddhZJddiZKddjZLddkZMddlZNddmZOddnZPddoZQddpZRddqZSdddrZTeUdsk(  r e	j                   eT              yy)u_  
taskctl.py — main 진입 단일화 + 상태 enforcement layer (task-2467 Phase A+B 통합)

회장 절대 기준:
    "taskctl을 거치지 않고는 main을 절대 변경할 수 없다."
    "모든 PR은 bot이 생성하고, 인간은 승인만 하며, main 반영은 taskctl만 수행한다."

상태 모델 (14정상 + 5예외 = 19종):
    정상: CREATED → WORKTREE_READY → RUNNING → [HANDOFF_READY →] COMMITTED
          → PR_OPEN → CI_PENDING → GEMINI_PENDING → REVIEW_READY → VERIFIED
          → HUMAN_APPROVED → MERGING → MERGED → DONE
    예외: BLOCKED / CANCELLED / FAILED / ESCALATED / ADMIN_OVERRIDE_USED
    호환: DISPATCHED / ACKED / GUARD_PASS (기존 11상태 backwards-compat)

저장 위치:
    {WORKSPACE}/.tasks/state/<task-id>.json

Evidence:
    {WORKSPACE}/.tasks/evidence/<task-id>/<name>.json

bypass (회장 전용):
    TASKCTL_BYPASS=1 환경변수로 skip. evidence에 강제 기록.

종료 코드:
    0   PASS / 정상 전이
    1   FAIL (가드 차단, 잘못된 전이, evidence 미달, etc.)
    2   internal error (subprocess 실행 실패 등)
    )annotationsN)datetimetimezone)Path)AnyNoReturnoverloadWORKSPACE_ROOTz/home/jay/workspace.tasksstateevidencescriptszguard.shzqc_report_guard.pyzgemini_evidence_verify.pymemoryzorchestration-auditzadmin-override.jsonl)zjonghyuk.jeon@gmail.com)zcancel-kill-switchzqc-checkzhidden-path-auditzlock-in-checkzmerge-safety-checkzgemini-review-gatezci/guardguardztuple[str, ...]REQUIRED_CHECKS)CREATEDWORKTREE_READYRUNNINGHANDOFF_READY	COMMITTEDPR_OPEN
CI_PENDINGGEMINI_PENDINGREVIEW_READYVERIFIEDHUMAN_APPROVEDMERGINGMERGEDDONEBLOCKED	CANCELLEDFAILED	ESCALATEDADMIN_OVERRIDE_USED
DISPATCHEDACKED
GUARD_PASSSTATESr      r&   r%   r   r%   r&   r   r   >   r   r   r   r   r   r   >   r   r   r   r'   r   r   >   r    r   r   r   >   r    r   r   r   r   r'   >   r   r   r   >   r   r   r   r   r   r"   r   >   r"   r   r!   r#   r$   )r!   r"   r$   r    r#   zdict[str, set[str]]ALLOWED_TRANSITIONS>   r   r"   r!   r$   zset[str]TERMINAL_STATESc                 f    t        j                  t        j                        j	                  d      S )N%Y-%m-%dT%H:%M:%SZ)r   nowr   utcstrftime     @/home/jay/workspace/.worktrees/task-2467-dev6/scripts/taskctl.py_nowr4      s!    <<%../CDDr2   c            	     H   	 t        j                         } 	 t        j                  g ddddt        t                    j                  j                         xs d}|  d| d	S # t        $ r# t        j                  j                  dd      } Y yw xY w# t        $ r d}Y Dw xY w)
NUSERunknowngitconfigz
user.emailT   capture_outputtexttimeoutcwdzunknown@localz <>)getpassgetuser	Exceptionosenvironget
subprocessrunstr	WORKSPACEstdoutstrip)useremails     r3   _actorrP      s    1  +dA3y>
 &, , 	 V2eWA  1zz~~fi01    s#   A$ AB $)BBB! B!c                    t         |  dz  S )N.json)	STATE_DIRtask_ids    r3   _state_pathrV      s    '%(((r2   c                    | j                         D ci c]  \  }}|dk7  s|| }}}t        j                  |ddd      S c c}}w )N	_checksumFT),:)ensure_ascii	sort_keys
separators)itemsjsondumps)r   kvpayloads       r3   _canonical_jsonrd      sE     %B1k1Aq!tBGB::gETjYY Cs
   AAc                x    t        j                  t        |       j                  d            j	                         S )Nutf-8)hashlibsha256rd   encode	hexdigest)r   s    r3   _compute_checksumrk      s*    >>/%077@AKKMMr2   c                @    | dg d g d d d i d d d i d
ddd d ddd d d d ddS )Nr   )
git_diff_shachanged_pathsbranch	pr_numberpr_state	ci_checksguard_sh_resultqc_report_guard_resultmerge_timestamp
exit_codesFusedtsactorrx   ry   rz   reasonaudit_log_offset)rU   current_statetransitionsr   human_approvedbypassadmin_overrider1   rT   s    r3   
_new_stater      s[    " #&*#
   t< $
% r2   c                $   t         j                  dd       | j                  dd        t        |       | d<   t	        | d         }|j                  d      }|j                  t        j                  | dd      d	
       |j                  |       y )NTparentsexist_okrX   rU   z	.json.tmpF   r[   indentrf   encoding)
rS   mkdirpoprk   rV   with_suffix
write_textr_   r`   replace)r   ptmps      r3   _saver      st    OOD4O0	IIk4 *51E+E)$%A
--
$CNN4::e%BWNUKKNr2   c                     y Nr1   rT   s    r3   _loadr      s    +.r2   c                    y r   r1   )rU   allow_missings     r3   r   r      s    JMr2   Fr   c          	     ~   t        |       }|j                         s|ry t        d| d|  dd       	 t        j                  |j                  d            }j                  d	d       }t        |      }||k7  rt        d
|  d| d| dd       ||d	<   |S # t        $ r}t        d| d| d       Y d }~_d }~ww xY w)Nu   state 파일 없음: u    (먼저 'taskctl init u	   ' 실행)   rf   r   u   state 파일 파싱 실패:     → rX   uJ   checksum 불일치: 외부 수정 의심 (state file tampered).
  task_id=z

  stored=z
  expected=u0   
  → taskctl만 상태 변경 가능합니다.)	rV   exists_dier_   loads	read_textrD   r   rk   )rU   r   r   r   excstoredexpecteds          r3   r   r      s    GA88:$QC'>wiyQSTU>

1;;;89 YY{D)F 'H 	 "x  " $>?
 	
  E+L  >+A3eC591==>s   %B 	B< B77B<c                r   t         | z  }|j                  dd       dj                  t        j                        t               t               t        j                         d}|j                  |       || dz  }t        j                  t        |      d      \  }}	 t        j                  |dd	
      5 }t        j                  ||dd       ddd       t        j                   |t        |             y# 1 sw Y   )xY w# t"        $ r' 	 t        j$                  |        # t&        $ r Y  w xY ww xY w)uA   9종 evidence를 .tasks/evidence/<task-id>/<name>.json에 기록.Tr    )commandrz   	timestamppidrR   .tmpdirsuffixwrf   r   Fr   r   N)EVIDENCE_DIRr   joinsysargvrP   r4   rE   getpidupdatetempfilemkstemprJ   fdopenr_   dumpr   rD   unlinkOSError)	rU   namerc   ev_dirrecordpathfdtmp_pathfs	            r3   _save_evidencer      s   G#F
LLL-88CHH%Vyy{	F MM'tfEN"D##FFCLB	YYr31 	?QIIfaeA>	?


8SY'	? 	?  	IIh 	  		sH    D 8C:'D :D?D 	D6D&%D6&	D2/D61D22D6rz   metaforcec          
        | d   }|rn{||k(  r|dv rnq|dv r|t         v ret        d| d| dd       nQt        ||       t        j	                  |t                     }||vr#t        d| d| dt        |      xs d	 d
d       || d<   | j	                  dd      }||t               |xs ddj                  t        j                        dt        t        |z        d}|rd|d<   |r||d<   | d   j                  |       y )Nr~   >   r   >   r"   r    r!   r#   u   비정상 전이: r   u&    (terminal 상태에서 전이 불가)r   u
    (허용: none)rU   r7   taskctlr   r   fromtory   rz   r   	exit_codeevidence_pathTforcedr   r   )r+   r   _check_forbidden_transitionsr*   rG   setsortedr4   r   r   r   rJ   r   append)	r   targetrz   r   r   srcallowedrU   entrys	            r3   _transitionr     s,    
 C	36[0	B	B/!%cU%x7]^`ab 	%S&1%))#su5 $SEvhjAZTZ@[[\] $E/ii	9-Gf#)88CHH%\G34E hf	-&r2   c                B   |dk(  r| dvrt        d|  dd       |dk(  r| dvrt        d|  dd       |d	k(  r| dk7  rt        d|  d
d       |dk(  r| dk7  rt        d|  dd       | dk(  r|t               vrt        d| dd       | dk(  r|d	k(  rt        dd       yyy)u<   6개 금지 전이를 명시적으로 차단 (회장 §3.9).r   >   r   r   r'   r   u   금지 전이: uF    → VERIFIED (반드시 REVIEW_READY 또는 GUARD_PASS 상태 필요)r   r      r   r'   u>    → HUMAN_APPROVED (VERIFIED 또는 GUARD_PASS 상태 필요)r   u+    → MERGING (HUMAN_APPROVED 상태 필요)r   r   u     → DONE (MERGED 상태 필요)r!   u   금지 전이: CANCELLED → u    (CANCELLED는 terminal 상태)r    uF   금지 전이: BLOCKED → MERGING (BLOCKED 상태에서 merge 차단)N)r   r   )r   r   s     r3   r   r   ?  s     +` `cU"hi	

 !!c1K&KcU"`a	

 s&66cU"MN	

 C8OcU"BC	

 kfCE1+F83RS	

 iFi/T	
 0r2   c                j    t        d|  t        j                         t        j                  |       y )N
[taskctl] file)printr   stderrexit)msgcodes     r3   r   r   l  s"    	Jse
3::.HHTNr2   c                     t        d|         y )Nr   )r   )r   s    r3   	_print_okr   q  s    	Jse
r2   x   )r@   r?   envc          
         t        j                  | dd|t        |xs t              i t        j
                  |xs i       S )NTr=   r>   r?   r@   r   )rH   rI   rJ   rK   rE   rF   )cmdr@   r?   r   s       r3   _runr   z  sA    >> y!)rzz)ciR) r2   c                    t         j                  j                  d      } | r| S t        dz  }|j	                         r|	 |j                  d      j                         D ]V  }|j                  d      s|j                  dd      d   j                         j                  d      j                  d	      c S  	 y y # t        $ r Y y w xY w)
NBOT_GITHUB_TOKENz	.env.keysrf   r   zBOT_GITHUB_TOKEN==r   "')rE   rF   rG   rK   r   r   
splitlines
startswithsplitrM   rD   )tokenv_keyslines      r3   _load_bot_tokenr     s    
**..+
,C

;&H	 **G*<GGI O??#67::c1-a0668>>sCII#NNO
   		s   4B: 3AB: 6B: :	CCc            	     v   	 t        j                  g ddddt        t                    j                  j                         } t        j                  j                  ddj                  t                    j                  d      }| |D cg c]  }|j                          c}v S # t        $ r d} Y ow xY wc c}w )Nr8   Tr;   r<    CHAIRMAN_EMAILSrY   )rH   rI   rJ   rK   rL   rM   rD   rE   rF   rG   r   r   r   )rO   r   es      r3   _verify_chairmanr     s    +dA3y>
 & 	 jjnn.0IJPPQTUG01QWWY000   1s   AB% 
B6%B32B3c                     t         j                         syt        j                  t        j
                        } d\  }}t         j                  d      j                         D ]  }|j                         s	 t        j                  |      }|j                  dd      }t        j                  |j                  dd            }| |z
  j                  }|d	k  r|d
z  }|dk  r|d
z  } |dk\  r||dfS |dk\  r||dfS ||dfS # t        $ r Y w xY w)zWreturns (soft_count_30d, hard_count_90d, status: OK|SOFT_CAP_WARNING|HARD_CAP_EXCEEDED))r   r   OK)r   r   rf   r   ry   r   Zz+00:00   r   Z   r;   HARD_CAP_EXCEEDED   SOFT_CAP_WARNINGr   )ADMIN_OVERRIDE_LOGr   r   r.   r   r/   r   r   rM   r_   r   rG   fromisoformatr   daysrD   )r.   softhardr   rects_strry   deltas           r3   _check_admin_capr    s   $$&
,,x||
$CJD$",,g,>IIK zz|
	**T"CWWT2&F''sH(EFB2XOOE{	{	 qyT...qyT---t  		s   7A/D	DDc           
     @   t         j                  j                  dd       t               \  }}}t	               | |d||||dz   |dz   d	}t         j                  dd      5 }	|	j                  t        j                  |d	
      dz          d d d        y # 1 sw Y   y xY w)NTr   chairmanr   )	ry   rU   rp   rz   r|   head_shabypassed_checkssoft_count_this_monthhard_count_this_quarterarf   r   Fr[   
)	r  parentr   r  r4   openwriter_   r`   )
rU   rp   r|   r  r  r  r	  _r
  r   s
             r3   _record_admin_overrider    s     ##D4#@$&MD$f*!%#'!8
C 
	 	 w	 	7 <1	

3U3d:;< < <s   !*BBc                 H    t         j                  j                  dd      dk(  S )NTASKCTL_BYPASSr   1)rE   rF   rG   r1   r2   r3   _bypass_activer    s    ::>>*B/366r2   c                   t        dddt        |       ddgd      }|j                  dk7  rd	|j                  d
d j	                         iS 	 t        j                  |j                  xs d      S # t
        j                  $ r d	dicY S w xY w)u   gh pr view로 PR 정보 조회.ghprview--jsonzEstate,mergeable,mergeStateStatus,statusCheckRollup,author,headRefNamer   r?   r   errorN{}json_parse_failed)	r   rJ   
returncoder   rM   r_   r   rL   JSONDecodeError)rp   procs     r3   _gh_pr_viewr-    s    dFC	NY D !TU+11344.zz$++-.. .,--.s   "A/ /B	B	c            
        t        g d      j                  j                         } t        g d      }|j                  j                         D cg c]  }|j                         s| }}t        g d      j                  j                         }t        g d      j                  }| xs d |xs d |t	        |j                         D cg c]  }|j                         sd c}      dS c c}w c c}w )N)r9   	rev-parsez--abbrev-refHEAD)r9   diffzorigin/main..HEADz--name-only)r9   r/  r0  )r9   statusz--porcelainr   )ro   rm   rn   git_status_porcelain_lines)r   rL   rM   r   len)ro   r1  r   changeddiff_sha	porcelainlns          r3   _collect_git_evidencer9    s    >?FFLLNFCDD++002@Qaggiq@G@0188>>@H56==I.D (D &)y7K7K7M*\QSQYQYQ[1*\&]	  A +]s   C,%C,	C1C1c                &   | sd i d d ddS t        dddt        |       ddgd	      }|j                  d
k7  r'd i d d |j                  dd  j	                         xs ddS 	 t        j                  |j                  xs d      }|j                  d      xs g }i }|D ]m  }|j                  d      xs |j                  d      xs d}|j                  d      xs( |j                  d      xs |j                  d      xs d}|si|||<   o t        D 	ci c]  }	|	|j                  |	d       }
}	|j                  d      |
||j                  d      |j                  d      dS # t
        j                  $ r}d i d d d| dcY d }~S d }~ww xY wc c}	w )Nno_pr_number)rq   rr   	mergeablemerge_state_statuspr_view_errorr!  r"  r#  r$  z2state,mergeable,mergeStateStatus,statusCheckRollupr   r%  r   r'  gh_errorr(  zjson_parse: statusCheckRollupr   contextr   
conclusionr   r2  UNKNOWNMISSINGr<  mergeStateStatus)rq   rr   ci_checks_allr<  r=  )r   rJ   r*  r   rM   r_   r   rL   r+  rG   r   )rp   r,  datar   rollupci_mapchkr   rB  nrequired_maps              r3   _collect_pr_evidencerM  
  s    r&*^M 	MdFC	NF D ! r&*!%TU!3!9!9!;!IzK 	KSzz$++-. XX)*0bFF &wwv:#'')"4:ggl+ 8swww/? 8*8.7 	%F4L& :IIAAvzz!Y//ILIHHW%!XXk*"hh'9:   S r&*|C5=QS 	SS Js$   #E# F#F6
F FFc                    t         j                         sddddS t        dt        t               | |gd      }|j                  dk(  rd	nd
|j                  |j
                  dd  |j                  dd  dS )NrD     zguard.sh not foundresultr   r   bash   r%  r   PASSFAILrQ  r   stdout_tailstderr_tail)GUARD_SHr   r   rJ   r*  rL   r   )stagerU   r,  s      r3   _run_guard_shr\  -  sp    ??##AUVVXw7ED OOq0&f__{{45){{45)	 r2   c           
        t         j                         sddddS t        dt        t               d| dt        t              gd	      }|j
                  d
k(  rdnd|j
                  |j                  dd  |j                  dd  dS )NrD  rO  zqc_report_guard.py not foundrP  python3z	--task-idz--workspacer   r%  r   rT  rU  rV  rW  )QC_REPORT_GUARDr   r   rJ   rK   r*  rL   r   )rU   r,  s     r3   _run_qc_report_guardr`  9  s    !!###A_``	C(+wsS\~^D
 !OOq0&f__{{45){{45)	 r2   c                H    | syt        d | j                         D              S )NFc              3  &   K   | ]	  }|d k(    yw)SUCCESSNr1   ).0rb   s     r3   	<genexpr>z,_all_required_checks_pass.<locals>.<genexpr>K  s     :!qI~:s   )allvalues)rr   s    r3   _all_required_checks_passrh  H  s"    :y'7'7'9:::r2   c                   | j                   j                  dd       t        j                  t	        | j                         d      \  }}	 t        j                  |dd      5 }t        j                  ||dd	
       ddd       t        j                  |t	        |              y# 1 sw Y   )xY w# t        $ r' 	 t        j                  |        # t        $ r Y  w xY ww xY w)u1   tempfile + os.replace 를 이용한 atomic write.Tr   r   r   r   rf   r   Fr   r   N)r  r   r   r   rJ   rE   r   r_   r   r   rD   r   r   )r   rG  r   r   r   s        r3   _atomic_writerj  S  s    KKdT2##DKK(8HLB	YYr31 	=QIIdAE!<	=


8SY'	= 	=  	IIh 	  		sH   B2 $B&>'B2 &B/+B2 2	C"<CC"	CC"CC"c                   t        | j                        }|j                         rt        d| j                          yt	        | j                        }|d   j                  d dt               t               dj                  t        j                        dt        t        | j                  z        d       t        |       t               }t        | j                  ddj                  t        j                        t               t               |j!                  d      |j!                  d	      d
d
d|j!                  d	      d d
       t        d| j                   d| d       y)Nzalready initialized: r   r   r   r   r   startro   rm   r   )
r   rz   ry   ro   r  rL   r   r   sharp   zinit u    → CREATED (r   )rV   rU   r   r   r   r   r4   rP   r   r   r   rJ   r   r   r9  r   rG   )argsr   r   git_evs       r3   cmd_initrp  h  s   DLL!Axxz)$,,89t||$E	-ITVfh88CHH%A\DLL89! 
 
%L"$F4<<88CHH%f**X&JJ~.zz.)+  dll^>!A67r2   c                    t        | j                        }t        ||t               |       t	        |       t        | j                   d|        y)Nrz   r   u   : → r   r   rU   r   rP   r   r   )rn  r   r   r   s       r3   _simple_transition_cmdrt    sA    $,,EvVXD9	%LfVH-.r2   c                    t        | d      S )Nr%   rt  rn  s    r3   cmd_dispatchrx    s    !$55r2   c                    t        | d      S )Nr&   rv  rw  s    r3   cmd_ackrz    s    !$00r2   c                &   t        | j                        }|d   }|dv r:t        |dt                      t	        |       t        | j                   d       yt        |dt                      t	        |       t        | j                   d       y)Nr~   r)   r   rz   u   : → RUNNINGr   rs  rn  r   r   s      r3   cmd_runr~    sy    $,,E

 C
77E9FH5eT\\N-01y1	%Lm,-r2   c                    t        | d      S )u<   worktree-ready: CREATED/DISPATCHED/ACKED → WORKTREE_READY.r   rv  rw  s    r3   cmd_worktree_readyr    s    !$(899r2   c                    t        | j                        }|d   dk7  rt        d|d    dd       t        |dt	                      t        |       t        | j                   d       y	)
u#   handoff: RUNNING → HANDOFF_READY.r~   r   u   handoff 불가: 현재 상태=u    (RUNNING 필요)r   r   r|  u   : → HANDOFF_READYr   r   rU   r   r   rP   r   r   rn  r   s     r3   cmd_handoffr    se    $,,E_*-eO.D-EEVWYZ[fh7	%L123r2   c                .   t        | j                        }|d   }|dvrt        d| dd       t               }|j	                  d      xs d}t        | j                  d||j	                  d	g       ||j	                  d
      ddd||d   j	                  d      d	       ||d   d<   |j	                  d
      |d   d
<   |j	                  d	g       |d   d	<   t        |dt                      t        |       t        | j                   d|dd  d       y)uC   commit: RUNNING/HANDOFF_READY → COMMITTED + commit.json evidence.r~   >   r   r   u   commit 불가: 현재 상태=u&    (RUNNING 또는 HANDOFF_READY 필요)r   rm   r   commitrn   ro   r   r   rp   )	rm   rn   commit_hashro   rL   r   r   rm  rp   r   r|  u   : → COMMITTED (sha=N   r   )
r   rU   r   r9  rG   r   r   rP   r   r   )rn  r   r   ro  r  s        r3   
cmd_commitr    s#   $,,E

 C
..,SE1WXZ[\"$Fzz.)/RH4<< OR8**X&:&**;7
, 
 )1E*n%"(**X"6E*h)/OR)HE*o&{&(3	%L3HRaL>CDr2   c                F   t        | j                        }|d   }|dvrt        d| dd       d}d}d}d}d}d}d	}	t               }
|
j	                  d
      xs d}|
j	                  d      xs d}t        | dd      r8t               }|st        dt        j                         | j                  }d| j                   d| }d| j                   d}i }|r||d<   d}	dddd|d|g}t        ||d      }|j                  j                         }|j                  j                         }|j                  }|j                  dk7  rt        ddd|ddg|d       }|j                  dk(  rj	 t        j                  |j                        }|j	                  d!      }|j	                  d"d      }|j	                  d#      xs i j	                  d$d      }d}|t#        | j                  d%d&| |j                  |||dd'       t        d&| d       n|}t        ddd|ddg|d       }|j                  dk(  rh	 t        j                  |j                        }|j	                  d!      }|j	                  d"|      }|j	                  d#      xs i j	                  d$d      }|s@d(|d)   d*<   d(|d)   d+<   d,|d)   d-<   n't        | dd      st        d.d       | j$                  }d	}	|r||d)   d/<   t'        |d0t)               d|i1       t        g d2      j                  j                         xs d}t#        | j                  d%| j                  ||||||xs |	|	||||d3       t+        |       t-        | j                   d4| d5       y# t         $ r Y w xY w# t         $ r Y w xY w)6uy   pr-open: COMMITTED → PR_OPEN.
    --pr <int>: 기존 PR 번호 입력
    --auto: bot token으로 직접 PR 생성
    r~   >   r   r   r   r   u   pr-open 불가: 현재 상태=u"    (COMMITTED 또는 RUNNING 필요)r   Nr   r   manualrm   ro   autoFuk   [taskctl] WARNING: BOT_GITHUB_TOKEN 미설정 — 현재 사용자 token으로 PR 생성 (ESCALATED 후보)r   [z] zTask z% PR (auto-created by taskctl pr-open)GH_TOKENbotr!  r"  createz--titlez--body<   r   r?   r#  r$  znumber,url,authorr   numberurlauthorloginpr-openu   PR 생성 실패: )r&  r   rL   r   rm  rp   Tr   bot_token_missingescalated_candidatecurrent_user	pr_authoru+   pr-open: --pr <번호> 또는 --auto 필요rp   r   rr  r9   r/  origin/main)rU   ro   base_shar  rp   pr_urlr  
created_byrL   r   r   rm  u   : → PR_OPEN (PR #r   )r   rU   r   r9  rG   getattrr   r   r   r   r   rL   rM   r*  r_   r   rD   r   r"  r   rP   r   r   )rn  r   r   rp   r  r  
stdout_str
stderr_strr   r  ro  r  ro   	bot_token
short_desctitlebodyenv_override
create_cmdr,  	find_procpr_info	view_procvir  s                            r3   cmd_pr_openr    s    
 $,,E

 C FF-cU2TUWXY IFIJJIJ"$Fzz.)/RHZZ!'RFtVU##%	}ZZ
 \\
DLL>J<0t||n$IJ')'0L$J $ud


 JL"=[[&&(
[[&&(
OO	??atVVX7JK "I ##q("jj)9)9:G 'H 5I$[[3F!(X!6!<" A A'2 NI !I  t||Y1*>!%((#!%9  )*6:  FtVVX7JK "I ##q(I$4$45B "x 0IVVE62F!#!1!7R < <Wb II 59E*127;E*34-;E*k* tT4(>BGG	
)2j+&yi7HI 78??EEGM2H4<<<<,* -  
%L1)A>? ! 4 ! s&   )A)N 5A'N 	NN	N N c                   t        | j                        }|d   }|dk7  rt        d| dd       |d   j                  d      }t	        |      }|d   |d   d<   |d	   |d   d	<   t               }|j                  d
      xs d}t        | j                  d||d	   t        |d	         |d|j                  dd      d|d       t        |dt               d|i       t        |       t        | j                   d| d       y)uH   ci-check: PR_OPEN → CI_PENDING. 8 required CI checks 수집 + ci.json.r~   r   u   ci-check 불가: 현재 상태=u    (PR_OPEN 필요)r   r   rp   rq   rr   rm   r   cir>  r   )rp   rr   all_passr  rL   r   r   rm  r   r"  rr  u   : → CI_PENDING (PR #r   )r   rU   r   rG   rM  r9  r   rh  r   rP   r   r   )rn  r   r   pr_npr_evro  r  s          r3   cmd_ci_checkr  U  s   $,,E

 C
i.se3DEqI  -D &E$)*$5E*j!%*;%7E*k""$Fzz.)/RH4<<;'-eK.@A))OR0	( 	 |684,G	%L4TF!<=r2   c                (   t        | j                        }|d   }|dk7  rt        d| dd       |d   j                  d      }t	               }|j                  d      xs d	}t
        j                  j                  d
d      }d|d}t        j                         rt        t        dz        }|t        j                  vr t        j                  j                  d|       	 ddlm}	  |	|||      }
t!        |
t"              r|j%                  |
       nt        |
      |d<   n(t)        dt         dt        j*                         d|d<   t-        | j                  d||d|j                  dd      |j                  dd      d	|j                  dd	      d|d	       t/        |dt1               d |i!       t3        |       t5        | j                   d"       y# t&        $ r0}t)        d| t        j*                         d| |d<   Y d}~d}~ww xY w)#uS   gemini-evidence: CI_PENDING → GEMINI_PENDING. evaluate_gate 호출 + gemini.json.r~   r   u&   gemini-evidence 불가: 현재 상태=u    (CI_PENDING 필요)r   r   rp   rm   r   GH_REPOJeon-Jonghyuk/dev_workspaceSKIP)hold_block_passr  r   r   )evaluate_gate
raw_resultu@   [taskctl] WARNING: evaluate_gate 호출 실패 (graceful skip): r   u   evaluate_gate 실패: warningNz[taskctl] WARNING: u%    없음 — gemini gate graceful skipu    gemini_evidence_verify.py 없음geminizgemini-code-assistseverity_countr  )	rp   r  app_slugr  r  rL   r   r   rm  r   r"  rr  u   : → GEMINI_PENDING)r   rU   r   rG   r9  rE   rF   GEMINI_EVIDENCE_VERIFYr   rJ   rK   r   r   insertgemini_evidence_verifyr  
isinstancedictr   rD   r   r   r   r   rP   r   r   )rn  r   r   r  ro  r  repogemini_resultscripts_dirr  gate_resultr   s               r3   cmd_gemini_evidencer  q  s   $,,E

 C
l5cU:NOQRS  -D"$Fzz.)/RH::>>)%BCD8>H$UM$$&)i/0chh&HHOOA{+		F<'h=K+t,$$[1.1+.>l+
 	!"8!99^_	
 $Fi 4<<('++,<a@(,,->G##Ir2
, 
 'vxtTlK	%L234/  	FTUXTYZadakakl)?u'EM)$	Fs   !A G 	H!&HHc                    t        | j                        }|d   }|dk7  rt        d| dd       t        |dt	                      t        |       t        | j                   d       y	)
u.   review-ready: GEMINI_PENDING → REVIEW_READY.r~   r   u#   review-ready 불가: 현재 상태=u    (GEMINI_PENDING 필요)r   r   r|  u   : → REVIEW_READYr   r  r}  s      r3   cmd_review_readyr    se    $,,E

 C
23%7OPRST~VX6	%L012r2   c                6   t        | j                        }|d   }|t        v rt        d| dd       t	               }|d   |d   d<   |d   |d   d<   |d   |d   d<   |j                  d      xs d	}|d   j                  d
      }t        |      }|d   |d   d<   |d   |d   d<   |j                  d      |d   d<   |j                  d      |d   d<   d|v r|d   |d   d<   t        d| j                        }|d   |d   d<   ||d   d<   t        | j                        }|d   |d   d<   ||d   d<   |d   |d   d   d<   |d   |d   d   d<   t               }	|d   dk(  xr |d   dk(  }
t        | j                  d|d   |d   |	||j                  dd	      |j                  dd	      |
rdnd||d	       |
r|d v rt        |d!t               ddd"#       nt        |d!t               ddd"#       d|d   d   d<   t        |       t        | j                   d$       | j                  r!t!        t#        j$                  |d%d&'             y|d(v rt        |d)t               d*d+i#       d|d   d   d<   t        |       g }|d   dk7  r|j'                  d,|d           |d   dk7  r|j'                  d-|d           t        | j                   d.d/j)                  |       d0       | j                  r!t!        t#        j$                  |d%d&'             y)1Nr~   u   verify 불가: 현재 상태=z (terminal)r   ro   r   rm   rn   r   rp   rq   rr   r<  r=  r>  pre-pushrQ  rs   guard_sh_detailrt   qc_report_guard_detailr   rv   verify_guard_shverify_qc_report_guardrT  verifyrX  rY  r   )	rs   rt   hidden_path_auditr  rL   r   r   rm  rp   >   r&   r   r   r   r   r%   r'   r   r   r   r   r'   )guard_shqc_report_guardrr  u)   : verify PASS → GUARD_PASS (= VERIFIED)Fr   r   >   r   r'   r   r   r|   z"verify failed, demoting to PR_OPENz	guard.sh=zqc_report_guard=z: verify FAIL [z, ])r   rU   r+   r   r9  rG   rM  r\  r`  _hidden_path_audit_internalr   r   rP   r   r   machiner   r_   r`   r   r   )rn  r   r   ro  r  r  r  guard_evqc_evaudit_resultr  fail_reasonss               r3   
cmd_verifyr    s   $,,E

 C
o,SE=qA"$F"("2E*h(.~(>E*n%)/)@E*o&zz.)/RH  -D &E$)*$5E*j!%*;%7E*k"%*YY{%;E*k".3ii8L.ME**+%-2?-Cj/*Z6H+3H+=E*'(+3E*'( .E27/E*./27E*./9A+9NE*l#$56@Ek@RE*l#$<= /0L 	f$ 	&(Ov%  4<<#H-"'/),,}b1,,}b1"Q
, 
   ! ! |68*0VLN |68*0VLN45j,'1eT\\N"KLM<<$**UqAB
::E9FH"$HI	K01E*l#H-	%L LV#i(:';<=X& .uX.?@Aodii.E-FaHI||djjU1=>r2   c                   t        | j                        }|d   }|dvrt        d| dd       t        | dd      xs
 t	               }|d   j                  d	      }d}|r3t        |      }|j                  d
      xs i j                  d      xs d}d|v r|j                  d      d   n|}t               }|j                  d      xs d}	|rZ||k(  rUt        | j                  ddd||ddd|	|d	       t        |dt	               ddi       t        |       t        d| dd       d|d<   t        | j                  d|xs d|dt        |d   j                  di             d|	ddd|	|t               d        t        |d!t	               d"|i       d|d   d#   d$<   t        |       t        | j                   d%| d       y)&uL   approve: VERIFIED 또는 GUARD_PASS → HUMAN_APPROVED. self-approve 차단.r~   r   u   approve 불가: 현재 상태=u$    (GUARD_PASS 또는 VERIFIED 필요)r   byNr   rp   r  r  r   r   rm   r   approvalrU  zself-approve detectedu   self-approve 차단)	rQ  r|   r  approverrL   r   r   rm  rp   r#   r|   zself-approverr  u,   self-approve 차단: PR author == approver (r   Tr   r7   rT  rr   )r  r  rQ  ci_passgemini_passr  rL   r   r   rm  rp   ry   r   r  rv   approveu   : → HUMAN_APPROVED (by: )r   rU   r   r  rP   rG   r-  r   r9  r   r   r   rh  r4   r   )
rn  r   r   r  r  r  pr_dataapprover_loginro  r  s
             r3   cmd_approver    s   $,,E

 C
,,,SE1UV	

 tT4(4FHH  -D Id#[[*0b55g>F$	/2hX^^C(+HN"$Fzz.)/RHY.0t||Z-"&+
2
 
	 	E;fh"N3	5e;I;aH!L"E
4<<+)",U:->-B-B;PR-STf.  'vx .1312E*l#I.	%L88HJKr2   c                    t        | j                        }t        |dt               dt	        | dd       i       t        |       t        | j                   d       y)Nr!   r|   rr  u   : → CANCELLEDr   )r   rU   r   rP   r  r   r   r  s     r3   
cmd_cancelr  N  sO    $,,E{&(h =>@	%Lo./r2   c                    t        | j                        }t        |dt               d| j                  i       t        |       t        | j                   d| j                   d       y)Nr"   r|   rr  u   : → FAILED (r   r   )r   rU   r   rP   r|   r   r   r  s     r3   cmd_failr  W  sS    $,,Exvx,.	%LnT[[M;<r2   c                   t        | j                  d      }|U| j                  r/t        t	        j
                  | j                  d ddd             yt        d| j                   d       y| j                  r"t        t	        j
                  |dd	
             yt        d|d           t        d|d           t        dt        |d                 |d   }t        d|j                  d              t        d|j                  d              t        d|j                  d              t        d|j                  d              t        d|d           t        d|d           y)NTr   )rU   r~   missingFr  r   z: state file missingr   r   r   ztask: rU   zstate: r~   ztransitions: r   r   zbranch: ro   zpr: rp   z
guard_sh: rs   zqc_report_guard: rt   zhuman_approved: r   zbypass: r   )r   rU   r  r   r_   r`   r4  rG   )rn  r   evs      r3   
cmd_statusr  `  sl   $,,d3E}<<$**)-/=BD E  Jt||n,@AB||djjU1=>  	uY'()*o./01c%"6789::)*+,RVVK()*+
266"34567!"&&)A"B!CDE '7!8 9:;x)*+r2   c                   t        | j                        }t               }t        | dd      }t        | dd      }|r6dt	               t               d|d<   t        dt        j                         n|r`t               st        d	d
       t               \  }}}|dk(  rt        d| dd
       |dk(  rYt        d| dt        j                         n8|d   dk7  r6d
|d   d   d<   t        |       t        d|d    d| j                   dd
       |d   dk(  r"d
|d   d   d<   t        |       t        dd
       |d   dk(  r"d
|d   d   d<   t        |       t        dd
       t        d| j                        }|d   |d   d<   ||d   d <   |d   d!k7  r)d
|d   d   d<   t        |       t        d"|d#    d$d
       t        | j                        }	|	d   |d   d%<   |	|d   d&<   |	d   d!k7  r)d
|d   d   d<   t        |       t        d'|	d#    d$d
       |d   j                  d(      }
|
rt!        |
      }|d)   |d   d)<   |d*   |d   d*<   |j                  d+      |d   d+<   |j                  d,      |d   d,<   |j                  d+      d-vrE|j                  d+      4d
|d   d   d<   t        |       t        d.|j                  d+       d
       t#        |d*         s(d
|d   d   d<   t        |       t        d/|d*    d
       |d   j                  d(      }
|
s"d
|d   d   d<   t        |       t        d0d
       t%               }|j                  d1      xs d2}|rt	               }||d   d3<   d|d   d4<   d5|d   d   d<   |d   dk(  s|s|rBt'        |d6t               d||d7|8       t        |       t'        |d9t               ddi|8       nt'        |d9t               d|d:|8       t)        | j                  dd;j+                  t        j,                        d5dd|d2d2||
dd<
       t        |       t/        | j                   d=|
 d$       y5|d   dk(  r+t'        |d6t               ||d>|xs |8       t        |       n*|s|r&t'        |d6t               ||d>d8       t        |       |rJt        | d?d@      xs d@}t1        | j                  |
||dAgB       dt	               dC|d dD|dE<   t        |       t2        j4                  j                  dFdG      }dHdIdt7        |
      dJdKdL|g}|r|j9                  dM       t;        |dNdOidPQ      }|j<                  |j>                  dRd  |j                  dRd  dS|d   dT<   d2}|j<                  d5k7  r|j<                  |d   d   d<   t'        |dUt               d?dV|j<                   id8       t)        | j                  dd;j+                  t        j,                        |j<                  d2dU||j>                  dRd  |j                  dRd  ||
dW	       t        |       t        dX|j<                   dY|j                  dZd   |j<                  xs d
       t	               }||d   d3<   d5|d   d   d<   |}t;        dHd[d\| d]gd^_      }|j<                  d5k(  r2	 tA        jB                  |j>                        }|j                  d`d2      }t'        |d9t               |
|||da|xs |8       |rt'        |dbt               d?dcid8       t)        | j                  dd;j+                  t        j,                        d5|d9||j>                  dRd  |j                  dRd  ||
|dd
       t        |       |rt/        | j                   de|
 df       y5t/        | j                   dg|
 dh       y5# tD        $ r d2}Y w xY w)iNadminFdry_runTrw   r   u3   ★★★ TASKCTL BYPASS USED — Chairman overrider   u<   admin override 차단: 회장(chairman) 자격 검증 실패r   r  u1   admin override 차단: HARD_CAP_EXCEEDED (분기 u   회 사용 ≥ 5회)r  u3   [taskctl] WARNING: SOFT_CAP_WARNING — 이번 달 u   회 사용 (soft limit 3회)r~   r   r   rv   mergeu   merge 차단: 현재 상태=u*    (HUMAN_APPROVED 필요. 'taskctl approve u	   ' 먼저)r!   u   merge 차단: state=CANCELLEDr    u=   merge 차단: state=BLOCKED (HOLD/CONFLICT 시 머지 차단)r  rQ  rs   guard_sh_detail_mergerT  u+   merge 차단: guard.sh pre-push FAIL (exit=r   r   rt   qc_report_guard_detail_mergeu)   merge 차단: qc_report_guard FAIL (exit=rp   rq   rr   r<  r=  >   N	MERGEABLEu   merge 차단: PR mergeable=u1   merge 차단: 8 required CI checks 미통과 — u7   merge 차단: PR 번호 없음 (taskctl pr-open 먼저)rm   r   ru   merge_dry_runr   r   )r  r   r  r   r   )r  r   r   )
r   r   merge_commit_sharq   r  rL   r   rm  rp   r  u,   : dry-run merge → MERGING → MERGED (PR #)r   r  r|   zadmin overrideself_approve_constraint)rU   rp   r|   r  r  r  r{   r   r  r  r!  r"  z--mergez--delete-branchz--repo--adminTASKCTL_INVOKEDr  r   r  rV  )r   rX  rY  merge_subprocessr"   zgh pr merge exit=)	r   r   r  rq   r  rL   r   rm  rp   u   merge 실패: gh pr merge exit=z stderr=r'  api/repos//commits/mainr   r%  rm  )r"  r   r  r  r$   zadmin override used)
r   r   r  rq   r  rL   r   rm  rp   r   z: admin-override merge PR #u/    → MERGING → MERGED → ADMIN_OVERRIDE_USEDz: merged PR #u-    → MERGING → MERGED (taskctl done 필요))#r   rU   r  r  r4   rP   r   r   r   r   r   r  r   r\  r`  rG   rM  rh  r9  r   r   r   r   r   r  rE   rF   rJ   r   r   r*  rL   r_   r   rD   )rn  r   r   r  r  r  r	  
cap_statusr  r  r  r  ro  r  merge_tsr|   r  	merge_cmdr,  r  
owner_repoapi_procapi_datas                          r3   	cmd_merger  ~  s   $,,EFD'5)EdIu-G&X
h
 	C#**U	!OQRS!1!3dJ,,& 46
 ++EdVKghZZ !%5578E*l+G4%L.u_/E.F G<<@LL>T ![078E*l+G4%L0!4!Y.78E*l+G4%LPRST T\\:/7/Aj+,5=j12H'78E*l+G4%L!+./q2 %T\\26;Hoj23<Aj89?f$78E*l+G4%L{+,A/ Z $$[1(.E,1*,=E*j)-2;-?E*k*-2YY{-CE*k*6;ii@T6UE*23yy%-@@99[)5?@E*%l3G<%L5eii6L5MN -U;-?@;<j!,/8eG[)*,   -D34j,'0eFJ"$Fzz.)/RH6/7j+,-1j/*34j,'0!%555y)-%P$& %Lxvx'.$& xvx)-@$& 	t||Wxx) )! /
 	 	eT\\N"NtfTUVW _!11E9FH$*U; /E	+ 	e	5E9FH$*U;	  	e x)9:N>NLL67	
 & $#
 	e ::>>)%BCDtWc$i<MxY]^I#$D __{{45){{45)-E*()
 !37??j,'0E868"&77H$IJ	  	t||Wxx) "  kk$%(kk$%(
/
 
	 	e-doo-> ?kk$%()+OO q	
 vH+3E*'(/0E*l#G, J	u
|=9:H a	"zz(//2H'||E26
 xvx FU*:<o' E0"$9:	  4<<88CHH%,++de$++de$+  
%LT\\N"=dVCrst  	T\\N-v5bcdA  	"!	"s   <1_ __c                R   t        | j                        }|d   dk7  rt        d|d    dd       t        j                  j                  dd      }d}t        d	d
d| dgd      }|j                  dk(  r2	 t        j                  |j                        }|j                  dd      }t        dz  dz  }|j                  dd       || j                   dz  }|j                  t        j                  | j                  t!               |ddd      d       t#        | j                  d|t%        |      t!               ddd||d   j                  d      d       t'        |d t)               !       t+        |       t-        | j                   d"| d#       y# t        $ r d}Y w xY w)$u<   done: state == MERGED 검증 + .done 생성 → DONE 전이.r~   r   u   done 불가: 현재 상태=u    (MERGED 필요)r   r  r  r   r!  r  r  r  r   r%  r   rm  r   eventsTr   z.done)rU   ry   r  Fr   r   rf   r   doner   rp   )r  	done_pathry   rL   r   r   rm  rp   r   r|  u   : → DONE (.done: r   )r   rU   r   rE   rF   rG   r   r*  r_   r   rL   rD   rK   r   r   r`   r4   r   rJ   r   rP   r   r   )rn  r   r  r  r  r  
events_dir	done_files           r3   cmd_doner    s   $,,E_))%*@)AAQR	

 ::>>)%BCD	uv]34H a	"zz(//2H'||E26
 X%0JTD1~U33I

t||46(8:HMVW	Y   4<<,^f:&**;7	* 	 vVX.	%L1)A>?9  	"!	"s   71F F&%F&c                 d   g d} g d}d}g }g }| D ]d  }	 t        j                  ddd|gt        t              ddd	      }|j                  d
k(  r%|j
                  j                         D ]  }|j                  dd      }|r|d
   n|t        |      dk\  r|d   nddv r9t        fd|D              rNj                  d      r`j                         }	|	j                  d      xsJ |	j                  d      xs7 |	j                  d      xs$ |	j                  d      xs |	j                  d      }
t        fd|D              }|
s|s|j                  |       |j                  |       
 g |sdnd}|||dS # t        $ r}|j                  d|        Y d}~d}~ww xY w)u%  repo 전체 grep으로 금지 패턴 검색. PASS/FAIL 반환.

    회장 §3.8: 주석/docstring/문자열 단순 언급은 violation 아님. 실제 subprocess 호출만 차단.
    code_call_markers: subprocess.run / _run([ / 리스트 형태로 인자 전달 — 실제 호출 패턴.
    )zgh pr createzgh pr mergezgit push origin mainzgit push --force origin mainz&worktree_manager finish --action merge)z.gittestsfixtures
.worktreesnode_modules__pycache__)
zsubprocess.z_run(z_run([z"gh", "pr", "create"z'gh', 'pr', 'create'z"gh", "pr", "merge"z'gh', 'pr', 'merge'
check_callcheck_outputzPopen(r9   grepz-nTr   )r@   r=   r>   r?   r   rZ   r   r  r   zscripts/taskctl.pyc              3  &   K   | ]  }|v  
 y wr   r1   )rd  r   r   s     r3   re  z._hidden_path_audit_internal.<locals>.<genexpr>  s     ;33$;;   )z.mdz.txtrR   z.logz.jsonlz.ymlz.yaml#z- z* z"""z'''c              3  &   K   | ]  }|v  
 y wr   r1   )rd  mcontents     r3   re  z._hidden_path_audit_internal.<locals>.<genexpr>  s     )R1!w,)Rr  zaudit_error: NrT  rU  )rQ  
violationswarnings)rH   rI   rJ   rK   r*  rL   r   r   r4  anyendswithrM   r   r   rD   )forbidden_patternsexcludescode_call_markersr  r  patternr,  r   partsstripped
is_commenthas_call_markerr   rQ  r  r   s                 @@r3   r  r    s    ZH JH% %5$	5>>g.	N#$D
 !# KK224 ,D JJsA.E',58$D*-e*/eAhrG+t3 ;(;; }}%`a &}}H !++C0 6#..t46#..t46 $..u56 $..u5  '*)R@Q)R&RO! - %%d+7,%5L &V6FJHMM  	5cU344	5s   E F	F/F**F/c                    ~ t               }|d   dk(  rt        d       yt        dt        |d          dt        j
                         |d   D ]   }t        d	| t        j
                         " y
)u@   audit-hidden-paths: repo 전체 grep으로 우회 경로 감지.rQ  rT  u*   hidden-path-audit PASS: 우회 경로 0건r   z"[taskctl] hidden-path-audit FAIL: r  u
   건 발견r   z  VIOLATION: r   )r  r   r   r4  r   r   )rn  rQ  rb   s      r3   cmd_audit_hidden_pathsr*    sx    (*Fh6!>?23vl7K3L2MZX::	% 	8AM!%CJJ7	8r2   c                
   | j                   | j                  | j                  t        t        dz        }|t
        j                  vr t
        j                  j                  d|       	 ddlm} t        d	z  d
z  z  t        j                  t        j                        }|j                  d      |j                  d      	 dM	 	 	 dNfd}t        dz  dz   dz  j!                         s |d d       t        d d        dt              \  }}|s<dj#                  |      } |ddj#                  |       d       t        d| d       t%        dddg      }	|	j&                  dk7  rR |d d|	j(                  j+                          d       t        d d|	j(                  j+                          d       j-                  d d!      t        d"z   d# z  j!                         r |d$ d%       t        d& d       d' d# t%        dddg      }
|
j&                  dk(  r |d( d)       t        d* d+d       t%        g d,      }|j&                  dk7  r't        d-|j(                  j+                          d       |j.                  j+                         t        d	z  d
z  z  }|d. dz  dOfd/}t%        dd0d1t              d2d3g      }|j&                  dk7  r1d4|j(                  j+                          } ||       t        |d       dz  d5z  }|j!                         st        dz  d5z  }|j!                         sAt%        dd0d6d7t              g       t%        dd8d9g       d:| } ||       t        |d       t1        j2                  t
        j4                  t        |      d;d<gddd=t              i t6        j8                  d>t        t              i?      }|j&                  dk7  rit%        dd0d6d7t              g       t%        dd8d9g       d@|j&                   dA|j(                  dBd j+                          } ||       t        |d       j-                  dC      t              t              dD|j.                  dEd dF}t;        |       t=        dG dHj-                  dC       dI dJ dK dL        y# t        $ r}t        d| d| dd       Y d}~d}~ww xY w)Puo   takeover: handoff 검증 → 새 worktree+branch 생성 → start_task_guard 자동 호출 → evidence 저장.r   r   )validate_handoffu'   validate_handoff 모듈 import 실패: z
  u9   /validate_handoff.py 파일이 있는지 확인하세요.r   Nr   r   z%Y%m%dT%H%M%SZr-   c                    	 j                  dd       |xs i j                  d      d d 	d| |d
}t        d d	z  |       y # t        $ r Y y w xY w)
NTr   previous_bottask/-failed)
rU   r.  new_botfrom_branch
new_branch
started_atts_filenametakeover_statusfailure_reasonfailure_check	takeover-rR   )r   rG   rj  rD   )
r|   r9  handoff_data_partialr  evidence_dir_earlyr3  r2  rU   r6  ts_isos
       r3   _save_early_failurez)cmd_takeover.<locals>._save_early_failure.  s    	$$TD$A"!5!; @ @ P"* %gYay9$*#+"(!.B ,;-u/MMrR 		s   AA 	AAr   handoffsrR   u   handoff 파일 없음: 1_handoff_existsr   T)rU   ro   check_head_shaworkspace_rootu   handoff 검증 실패: z; 2_validate_handoffu   handoff 검증 실패:
  r9   r/  z--verifyzfrom-branch 'u   ' 존재하지 않음: 3_from_branch_existsr  r   r  r0  u#   새 worktree 경로 이미 존재: 5_worktree_path_collisionu/   새 worktree 경로가 이미 존재합니다: r/  u   새 branch 이미 존재: 6_branch_collisionu   새 branch 'u_   '가 이미 존재합니다. 다른 bot ID를 사용하거나 기존 branch를 삭제하세요.r  u    origin/main HEAD 조회 실패: r:  c                    	 j                  d      
t              t        	      d| d}t        |       y # t        $ r Y y w xY w)Nr.  r1  )rU   r.  r2  r  r  handoff_pathr3  r4  new_worktree_pathr5  r6  r7  r8  )rG   rJ   rj  rD   )r|   r  r  evidence_filer3  handoff_datarH  r2  r4  rI  recorded_headrU   r6  r=  s     r3   _save_failed_evidencez+cmd_takeover.<locals>._save_failed_evidence  sj    	" , 0 0 @"$) #L 1*(%():%;$*#+"(B -, 		s   =A 	AAworktreeaddz-br  u   git worktree add 실패: zstart_task_guard.pyremovez--forcero   z-Du   start_task_guard.py 없음: z--task--botr   r
   r   u   start_task_guard 실패 (exit=z): r'  r.  successrV  )rU   r.  r2  r  r  rH  r3  r4  rI  r5  r6  r7  start_guard_stdoutu   takeover 성공: z
  previous_bot=u    → new_bot=z
  new branch:   z
  new worktree: z
  evidence:     r   )r|   rJ   r9  rJ   r;  zdict | NonereturnNone)r|   rJ   rT  rU  )rU   r3  r  rJ   rK   r   r   r  r,  ImportErrorr   r   r.   r   r/   r0   r   r   r   r*  r   rM   rG   rL   rH   rI   
executablerE   rF   rj  r   ) rn  r  r,  r   now_utcr>  okerrors	err_linesr,  proc_branch	proc_mainevidence_dirrM  proc_wtr|   start_guard_script
proc_guardr   r  r<  rJ  r3  rK  rH  r2  r4  rI  rL  rU   r6  r=  s                       @@@@@@@@@@@@@r3   cmd_takeoverrb    s   <<G''K88G i)+,K#((";'
5 #X-
:WDll8<<(G""#34K23F AE2=IM ( x'*4'%7HHL 5l^DFXY&|n5q9/ 	 B KK'	5dii6G5HI0(	* 	))5q9Z=>D!K=(?@Q@Q@S?TU"	

 	K=(?@Q@Q@S?TU	

 !$$Z4M!L0gYay3II!12C1DE'	

 	=>O=PQ	

 	7),J{J
CDK"(5 	

 	:, 'Q R	
 89Iq /	0@0@0F0F0H/IJAN%%'Hx'*4w>L Y{m5#AAM  * z5j	 G Q,W^^-A-A-C,DEf%VQ*Y69NN$$&&25JJ$$&eZ9c:K6LMNeXtZ01/0B/CDf%VQ	/0(GWgV!"<rzz<+S^<J !eZ9c:K6LMNeXtZ01,Z-B-B,C3  '--/02 	 	f%VQ $((8!L)"  !23"$(//6H -*
G9 %&**>:;=	 R%, ',- .(/		+ k  
5cU ;VX	
 	

s   7T 	U "T;;U c                 	   t        j                  dd      } | j                  dd      }d }|j                  dd	
      } ||       |j	                  t
               |j                  dd
      } ||       |j	                  t               |j                  dd
      } ||       |j	                  t               |j                  dd
      } ||       |j	                  t               |j                  dd
      } ||       |j                  dt        d d       |j                  ddd       |j	                  t               |j                  dd
      } ||       |j                  ddd       |j	                  t               |j                  dd 
      } ||       |j                  d!d d"#       |j	                  t               |j                  d$d%
      } ||       |j                  d&dd'       |j                  d(dd)       |j                  d*d d+#       |j	                  t               |j                  d,d-
      } ||       |j                  d*d .       |j	                  t               |j                  d/d0
      } ||       |j                  d*d1       |j	                  t                |j                  d2d3
      } ||       |j                  ddd4       |j	                  t"               |j                  d5d6
      } ||       |j                  d7d8dd9d:;       |j                  d<dd=>       |j	                  t$               |j                  d?d@
      } ||       |j	                  t&               |j                  dAdB
      } ||       |j	                  t(               |j                  dCdD
      } ||       |j	                  t*               |j                  dEdF
      } ||       |j	                  t,               |j                  dGdH
      } ||       |j	                  t.               |j                  dIdJ
      } ||       |j	                  t0               |j                  dKdL
      } ||       |j	                  t2               |j                  dMdN
      }|j	                  t4               | S )ONr   uh   task 상태 enforcement layer + main 진입 단일 경로 (task-2467: 14+5 state machine + PR lifecycle))progdescriptionr   T)destrequiredc                *    | j                  dd       y )NrU   u   task ID (예: task-2467)help)add_argument)sps    r3   _add_taskidz!build_parser.<locals>._add_taskid  s    
	(BCr2   initu   CREATED 상태 생성ri  )funcdispatchu    DISPATCHED 전환 (compat alias)acku   ACKED 전환 (compat alias)rI   u   RUNNING 전환r  u<   PR_OPEN 전환 (bot token PR 생성 또는 PR 번호 입력)z--pru   PR 번호 (수동 입력))typedefaultrj  z--auto
store_trueu    bot token으로 직접 PR 생성)actionrj  r  uS   evidence 자동 수집 + guard.sh + qc_report_guard, PASS 시 GUARD_PASS(=VERIFIED)z	--machineu   state JSON 출력r  u+   HUMAN_APPROVED 전환 (self-approve 차단)z--byu6   승인자 (human login). 미지정 시 _actor() 사용)rs  rj  r  u.   main 진입 단일 경로 (MERGING → MERGED)z	--dry-runu,   actual gh pr merge skip — 상태만 전이r  u1   chairman admin override (audit log 자동 기록)z--reasonu   admin override 사유cancelu   CANCELLED 전환)rs  failu   FAILED 전환)rg  r2  u   현재 상태 + evidence 출력u   JSON 출력takeoveruQ   handoff evidence 기반 봇 인계 — 새 worktree + branch + start_guard 자동z--fromr3  BRANCHu/   이전 봇의 branch (예: task/task-2458-dev4))rf  rg  metavarrj  rQ  u   새 봇 ID (예: dev5))rg  rj  zworktree-readyu*   WORKTREE_READY 전환 (dispatch/ack alias)handoffu0   HANDOFF_READY 전환 (RUNNING → HANDOFF_READY)r  u6   COMMITTED 전환 (RUNNING/HANDOFF_READY → COMMITTED)zci-checku/   CI_PENDING 전환 + 8 required CI checks 수집zgemini-evidenceu,   GEMINI_PENDING 전환 + evaluate_gate 호출zreview-readyu5   REVIEW_READY 전환 (GEMINI_PENDING → REVIEW_READY)r	  u3   DONE 전환 (MERGED → DONE + .done 파일 생성)zaudit-hidden-pathsuV   repo 전체 grep으로 우회 경로 감지 (gh pr create/merge, git push origin main))argparseArgumentParseradd_subparsers
add_parserset_defaultsrp  rx  rz  r~  rk  intr  r  r  r  r  r  r  rb  r  r  r  r  r  r  r  r*  )r   subrm  rl  s       r3   build_parserr    s_   =	A 

	D

9CD 
%<	=BOR__(_3	
)K	LBOR__,_7	$A	BBOR__'_2	$4	5BOR__'_2		(f	gBOOOFd9TOUOOH\8ZO[OOO%	b 
 
dBOOOK;NOOOOO$		(U	VBOOOFD/gOhOOO%	&V	WBOOOKG  IOOIlL  NOOJ3JOKOOO#	'9	:BOOOJO-OOO$	_	5BOOOJO.OOO"	'H	IBOOOK=OIOOO$	` 
 
B OOO}tX>   OOGd1IOJOOO& 
(/[	\BOR__*<_=		(Z	[BOR__+_6	'_	`BOR__*_5	
)Z	[BOR__,_7	)0^	_BOR__*=_>	-d	eBOR__*:_;	%Z	[BOR__(_3	,e 
 
gBOO/O0Hr2   c                D   t               }|j                  |       }	 |j                  |      }xs dS # t        $ r  t        j
                  $ r}t        d| d       Y d }~6d }~wt        $ r/}t        dt        |      j                   d| d       Y d }~ld }~ww xY w)Nzsubprocess timeout: r   zinternal error: z: r   )
r  
parse_argsro  
SystemExitrH   TimeoutExpiredr   rD   rr  __name__)r   parserrn  rcr   s        r3   mainr  K  s    ^FT"D@YYt_ 7N  $$ .#C5)1-- @S	 2 232cU;Q??@s!   4 BA$$B0%BB__main__)rT  rJ   )rU   rJ   rT  r   )r   dict[str, Any]rT  rJ   )rU   rJ   rT  r  )r   r  rT  rU  )rU   rJ   r   boolrT  dict[str, Any] | None)rU   rJ   r   rJ   rc   r  rT  rU  )r   r  r   rJ   rz   
str | Noner   r  r   r  rT  rU  )r   rJ   r   rJ   rT  rU  )r   )r   rJ   r   r  rT  r   )r   rJ   rT  rU  )
r   	list[str]r@   zPath | Noner?   r  r   zdict[str, str] | NonerT  zsubprocess.CompletedProcess)rT  r  )rT  r  )rT  ztuple[int, int, str])rU   rJ   rp   
int | Noner|   rJ   r  rJ   r  r  rT  rU  )rp   r  rT  r  )rT  r  )rp   r  rT  r  )r[  rJ   rU   rJ   rT  r  )rr   zdict[str, str]rT  r  )r   r   rG  r  rT  rU  )rn  argparse.NamespacerT  r  r   )rn  r  r   rJ   r   r  rT  r  )rT  zargparse.ArgumentParser)r   zlist[str] | NonerT  r  )W__doc__
__future__r   r|  rB   rg   r_   rE   rH   r   r   r   r   pathlibr   typingr   r   r	   rF   rG   rK   rS   r   rZ  r_  r  r  r   r   __annotations__r(   r   r*   r+   r4   rP   rV   rd   rk   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r-  r9  rM  r\  r`  rh  rj  rp  rt  rx  rz  r~  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r*  rb  r  r  r  r   r1   r2   r3   <module>r     s  8 #     	  
  '  * *  02GHI	 7*	8#j0y :-i'*>>"Y.1LL ),AADZZ .	$ 	 :,8, 7,-, i)*	,
 yk, 8, i-, ), B, #Y/, <, 6, !9-, ;, 7,  (#!," vh#,$ CE%,( e5>233, ( : S RE()Z
N: 
 . 
 .	 M 
 M16 <> LP.2#%'+%'%'(,%'P%
Z
 04C&*	#	/J	"(	16<<'<14<<$-< 
<47.& F	;*> ;?"7CF61 :
:~B8.b	"Uz;|<DX/n>NB(ARiX zCHHTV r2   