
    i              	      L   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m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.                  j1                  dd	            Zed
z  dz  Zed
z  dz  Zedz  Z ej:                  e      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/dZ0e*e+e,e-e.e/e0hZ1h dZ2d Z3d!Z4d"Z5d#Z6d$Z7d%Z8d&Z9d'Z:d(Z;d)Z<d*Z= e>e7e8e9e:e;e<e=h      Z? e>e9e:e;h      Z@d+ZAd,ZBd-ZC ej                  d.       ej                  d/       ej                  d0       ej                  d1      gZEd2eFd3<    ej                  d4      d5f ej                  d6      d7f ej                  d8      d9f ej                  d:      d;f ej                  d<      d=f ej                  d>      d?fgZGe ZHdZId@ZJdAZKdBZLe G dC dD             ZMe G dE dF             ZNedGej                  f   ZPdqdrdHZQdsdIZR	 dt	 	 	 	 	 	 	 dudJZSdvdKZT	 	 	 	 	 	 	 	 	 	 dwdLZUdxdMZV	 	 	 	 	 	 dydNZW ej                  dO       ej                  dP       ej                  dQ       ej                  dR       ej                  dS      gZX	 dt	 	 	 	 	 	 	 dzdTZYdUdVe
j                  f	 	 	 	 	 	 	 	 	 	 	 d{dWZ[	 	 	 	 	 	 	 	 d|dXZ\dYdZd}d[Z]d~d\Z^ef	 	 	 	 	 dd]Z_	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd^Z`dd_Zadd`ZbddaZc	 	 	 	 	 	 ddbZd	 	 	 	 	 	 ddcZe	 d	 	 	 	 	 	 	 dddZf	 dt	 	 	 	 	 	 	 ddeZg ej                  dfej                        ZiddgZjddhZkddiZle G dj dk             Zm	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddlZn	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 ddmZoddnZpdtddoZqedpk(  r e	j                   eq              yy)u  merge_queue_executor.py — task-2509 5 모듈 #1.

회장 명시: queue 선두 PR이 자동 머지 10조건 만족 시 회장 승인 없이 squash merge +
post-merge smoke + 후행 PR stale 재검증을 수행한다.
산출물은 정책 문서가 아니라 실행 가능한 코드 + 회귀 테스트.

자동 머지 10조건:
  1. queue head 위치 (선행 PR 모두 merged)
  2. origin/main fetch 성공 + main HEAD SHA 잠금
  3. PR base sync (BEHIND → merge sync, rebase/force 금지)
  4. effective diff = expected_files (불일치 → replacement_pr_runner 분기)
  5. forbidden path 0건
  6. CI required all SUCCESS
  7. Gemini reviewThreads unresolved 0
  8. mergeStateStatus == CLEAN
  9. HEAD SHA lock 유지 (검증 시작 == merge 직전)
 10. cherry_pick_allowed != true / serial_only conflict 0

Critical 7종 (회장 §14):
  - FORBIDDEN_PATH_INVASION
  - EFFECTIVE_DIFF_CONTAMINATION_REPLACEMENT_FAILED
  - GEMINI_REAL_BUG_SCOPE_EXPANSION
  - BLOCK_OVERRIDE_REQUIRED_OR_INSUFFICIENT_REASON
  - DEPENDENCY_CYCLE_OR_SERIAL_ONLY_CONFLICT
  - REPLACEMENT_PR_ALSO_FAILED
  - POST_MERGE_SMOKE_FAILURE

CLI:
  python3 utils/merge_queue_executor.py --pr <N> --dry-run
    → AUTO_MERGE_ALLOWED 또는 BLOCKED_WITH_REASON: <code> JSON

후속 모듈 (인터페이스만 박제):
  - replacement_pr_runner (task-2510)
  - auto_gemini_triage (task-2511)
  - post_merge_smoke_runner (task-2512)
  - critical_escalation_reporter (task-2513)
    )annotationsN)	dataclassfieldasdict)datetimetimezone)Path)AnyCallableOptionalWORKSPACE_ROOTz/home/jay/workspacememoryeventszorchestration-auditzmerge-queue.jsonlAUTO_MERGE_ALLOWEDAUTO_MERGE_SUCCESSWAITING_FOR_PREDECESSORBLOCKED_WITH_REASONHEAD_SHA_LOCK_BROKENCI_FAILURE_BLOCKCI_IN_PROGRESSGEMINI_UNRESOLVED_BLOCKMERGE_STATE_NOT_CLEANDIFF_CONTAMINATION_REPLACEMENTFORBIDDEN_PATH_INVASION/EFFECTIVE_DIFF_CONTAMINATION_REPLACEMENT_FAILEDGEMINI_REAL_BUG_SCOPE_EXPANSION.BLOCK_OVERRIDE_REQUIRED_OR_INSUFFICIENT_REASON(DEPENDENCY_CYCLE_OR_SERIAL_ONLY_CONFLICTREPLACEMENT_PR_ALSO_FAILEDPOST_MERGE_SMOKE_FAILURE>   --force--force-with-lease-f--adminreplacement_pr_runnerauto_gemini_triagepost_merge_smoke_runnercritical_escalation_reporterGEMINI_COMPLETEDGEMINI_UNRESOLVEDGEMINI_UNAVAILABLE_QUOTAGEMINI_TIMEOUTGEMINI_STALEGEMINI_REAL_BUGGEMINI_SCOPE_EXPANSIONLOWMEDIUM	HIGH_COREz ^utils/merge_queue_executor\.py$z^utils/merge_topology_gate\.py$z^dispatch\.py$z^teams/shared/verifiers/.+zlist[re.Pattern]HIGH_CORE_FILE_PATTERNSzgit\s+push\s+.*--forcez
force pushzgit\s+push\s+.*-f\bzforce push (-f)zgh\s+pr\s+merge\s+.*--adminzadmin overridezgit\s+cherry-pick\bzcherry-pickzopen\([^)]*"\.done"[^)]*"w"zmanual .done writez Path\([^)]*\)\.touch\(\).*\.donezmanual .done touchCRITICAL_ESCALATIONFALLBACK_REVIEW_FAILED"NON_DRY_RUN_REQUIRES_SMOKE_COMMANDc                     e Zd ZU ded<   dZded<   dZded<   dZded	<   dZded
<   dZded<   dZ	ded<   dZ
ded<    ee      Zded<    ee      Zded<    ee      Zded<   dZded<   dZded<   dZded<   dZded<   dZded<   dZded<   dZded<    ee      Zded<   dZded<   dZd ed!<   dZd ed"<   dZded#<   dZd ed$<   dZded%<   dZded&<    ee      Z d'ed(<    ee      Z!d)ed*<   d,d+Z"y)-QueueDecisionstrdecision reasonNzOptional[int]	pr_numberOptional[str]task_idmain_head_sha_startmain_head_sha_mergepr_head_sha_startpr_head_sha_mergedefault_factory	list[str]expected_fileseffective_filesforbidden_paths	ci_statusr   intgemini_unresolved_countmerge_state_statussmoke_statuscritical_code
audit_path	timestamp
list[dict]fixture_pr_replaygemini_statusFboolfallback_review_usedfallback_review_passed
risk_levelreview_gate_passedfinal_decisioncritical_escalationdictfallback_check_detailsliststatic_scan_violationsc                    t        |       S N)r   )selfs    M/home/jay/workspace/.worktrees/task-2509+2-dev3/utils/merge_queue_executor.pyto_dictzQueueDecision.to_dict   s    d|    )returnr\   )#__name__
__module____qualname____annotations__r<   r=   r?   r@   rA   rB   rC   r   r^   rG   rH   rI   rJ   rL   rM   rN   rO   rP   rQ   rS   rT   rV   rW   rX   rY   rZ   r[   r\   r]   r_   rd    re   rc   r8   r8      sE   MFC#I}#!G]!)--)--'+}+'+}+ %d ;NI;!&t!<OY<!&t!<OY<Is#$S$  L##'M=' $J$Is$)$$?z?#'M='!&$&#(D( $J$$$$(NM()--#(#>D>#(#>D>re   r8   c                  p    e Zd ZU dZded<   ded<   ded<   ded<   ded<   d	ed
<   ded<   d	ed<   dZded<   y)TaskSpecu   task spec metadata 정상화.r9   r?   rF   rG   	risk_area
dependencyparallel_policyr
   merge_queue_positionrU   stale_recheck_requiredcherry_pick_allowedNOptional[list[str]]smoke_command)rg   rh   ri   __doc__rj   ru   rk   re   rc   rm   rm      s>    'LN  )-M&-re   rm   .c                X    t        j                  | |xs t        t              dd|      S )NT)cwdcapture_outputtexttimeout)
subprocessrunr9   	WORKSPACE)argsrx   r{   s      rc   _default_runnerr      s+    >>!3y> re   c                    | D cg c]  }|t         v s|j                  d      s|  }}|rt        d|       d| v rt        d      y c c}w )Nr$   zFORBIDDEN_GIT_FLAGS detected: rebaseREBASE_FORBIDDEN)FORBIDDEN_GIT_FLAGS
startswithRuntimeError)r   abads      rc   assert_no_forbidden_git_flagsr      s]    
Ra#66!,,y:Q1
RC
R
;C5ABB4-.. 	 Ss
   A
A
c           
        g }| sd|fS | D ]  }t        |t              s|dk(  rt        j                  d|j	                               }|s|j                  |       R|j                  d      |j                  d      xs d}}|dk7  r~| ||      s|j                  |        |ddd	d
d| ddg      }|j                  j	                         r|j                  |        t        |      dk(  |fS )uR   dependency 항목 중 `.merged` 상태 task 모두 main에 반영됐는지 확인.Tnonez*^(task-\d+(?:\+\d+)?)(?:\.(merged|done))?$      mergedgitlogorigin/mainz	--onelinez--grep=z-n1r   )	
isinstancer9   rematchstripappendgroupstdoutlen)	ro   runnermain_log_greppendingspecmr?   stateresults	            rc   check_predecessor_mergedr      s     GW} $$$6>HHBDJJLQNN4 QWWQZ%;8H$ )w'}kWWICVX\^abc}}""$NN7#'$( LA''re   c                     | g d        | g d      }|j                   xs dj                         }|st        d      |S )u$   origin fetch + main HEAD SHA 반환.r   fetchoriginz--quiet)r   z	rev-parser   r;   MAIN_HEAD_SHA_FETCH_FAILED)r   r   r   )r   r   shas      rc   fetch_main_headr   
  sA    
0178F==B
%
%
'C788Jre   c                    dddd}|dk7  r|S g d}t        |        |||      }d|d<   d	|d
<   |j                  dk7  r<|j                  xs d|j                  xs dz   }d|v sd|j	                         v rd|d<   |S )u3   BEHIND 시 merge sync. rebase 금지, force 금지.FN)	performedmethodconflictBEHIND)r   merger   z	--no-editrx   Tr   merge_no_editr   r   r;   CONFLICTr   )r   
returncoder   stderrlower)
_pr_branch
pr_workdirr   rM   r   r   proccombineds           rc   sync_pr_baser     s     F
 X%7D!$'$J'DF;&F8!KK%2$++*;<!Z8>>3C%C!%F:Mre   c                j    | D ch c]#  }|j                         s|j                         % c}S c c}w ra   )r   )filesps     rc   _normalize_file_listr   2  s$    $2!	AGGI222s   00c                    t        |      }t        |       }t        ||z
        }t        ||z
        }t        |      dk(  xr t        |      dk(  ||fS )u   effective diff vs expected_files 대칭 비교.

    반환: (equal, extra, missing)
      - extra   = effective - expected (예상 외 파일)
      - missing = expected - effective (누락 파일)
      - equal   = extra == [] and missing == []
    r   )r   sortedr   )rH   rG   expected	effectiveextramissings         rc   compare_effective_diffr   6  sY     $N3H$_5I9x'(EX	)*GJ!O1G 1E7BBre   z^\.github/workflows/z^teams/.*/qc/verifiers/z^utils/task_id_parser\.py$z^scripts/finish_task\.py$z^scripts/qc_verify\.py$c                    t        t              }|r|j                  |       t        |      }g }| D ]2  }||v r|D ]&  }|j	                  |      s|j                  |        2 4 |S )uP   forbidden 파일이 effective diff 안에 있는데 expected 외이면 invasion.)r^   DEFAULT_FORBIDDEN_PATTERNSextendr   searchr   )rH   allowed_expectedextra_patternspatternsr   	invasionsfr   s           rc   detect_forbidden_pathsr   R  sz     ./H'#$45HI = 	Axx{  #	 re   r   g        c           	        t        t        |d            D ]<  } |dddt        |       ddg      }	 t        j                  |j
                  xs d      }|j                  d      xs g }g }	|D ]\  }
|
j                  d      xs( |
j                  d	      xs |
j                  d
      xs d}|	j                  |j                                ^ |	st        g |dc S t        d |	D              rt        |	|dc S t        d |	D              r$|dz   |k  r ||d|z  z         t        |	|dc S t        d |	D              rd|	|dc S t        |	|dc S  t        g g dS # t        j                  $ r i }Y #w xY w)uU   gh pr view --json statusCheckRollup → required all SUCCESS / FAILURE / IN_PROGRESS.r   ghprview--jsonstatusCheckRollup{}r   
conclusionstatusr;   )r   detailsrawc              3  $   K   | ]  }|d v  
 yw)>   ERRORFAILURE	CANCELLED	TIMED_OUTACTION_REQUIREDNrk   .0ss     rc   	<genexpr>z"fetch_ci_status.<locals>.<genexpr>  s     hZ[qUUh   c              3  $   K   | ]  }|d v  
 yw)>   QUEUEDPENDINGWAITINGEXPECTEDIN_PROGRESSNrk   r   s     rc   r   z"fetch_ci_status.<locals>.<genexpr>  s     bTUqOObr   r   c              3  $   K   | ]  }|d v  
 yw)>   NEUTRALSKIPPEDSUCCESS	COMPLETEDNrk   r   s     rc   r   z"fetch_ci_status.<locals>.<genexpr>  s     UqqBBUr   r   )rangemaxr9   jsonloadsr   JSONDecodeErrorgetr   upperr   anyr   all)r=   r   	max_pollsbackoff_secondssleeperattemptr   payloadrollupstatusesitemr   s               rc   fetch_ci_statusr  h  s    Y*+ P$I)
 	jj!6$7G 017R 	+DHHW%[,)?[488HCU[Y[EOOEKKM*	+ .2fMMh_ghh.8FSSbYabb{Y&1<89,&QQUHUU'HVLL*xOO3P4 %B??' ## 	G	s   #E  E98E9c           	         |ddddd|  dg      }	 t        j                  |j                  xs d      }|j	                  d      xs g }t        |t              r<|r:d	j                  d
 |D              }d|v sd|v sd|v rdg d|dS d|v sd|v rdg d|dS |j	                  d      du s|j	                  d      du rdg ddS |j	                  d      xs i }|j	                  d      xs i }|j	                  d      xs i }	|	j	                  d      xs i }
|
j	                  d      xs g }g }|D ]y  }|j	                  d      r|j	                  d      xs i j	                  d      xs g }|r|d   ni }|j                  |j	                  dd       |j	                  d!d       d"       { |sd#g ddS t        |      }|D cg c]  }|j	                  d      |v s| }}|D cg c]  }|j	                  d      |vs| }}|rd$||t        t        d%S d&||t        d'S # t         j                  $ r i }Y w xY wc c}w c c}w )(u  gh api graphql reviewThreads → unresolved 0 필수.

    분기:
      - unresolved == 0 → ok
      - unresolved style/false-positive only & expected_files 안 → AUTO_GEMINI_TRIAGE_HOOK
      - unresolved real bug expected_files 밖 → CRITICAL_GEMINI_SCOPE_EXPANSION
    r   apigraphqlr#   z@query=query{ repository(owner:"x",name:"y"){ pullRequest(number:z_){ reviewThreads(first:50){ nodes{ isResolved comments(first:1){ nodes{ path body } } } } } } }r   errors c              3     K   | ]?  }t        |t              r|j                  d d      n
t        |      j	                          A yw)messager;   N)r   r\   r   r9   r   )r   es     rc   r   z&fetch_gemini_status.<locals>.<genexpr>  s;      
 &04%8QUU9b!c!fKKM
s   AAquotaz
rate limitz
rate-limitunavailable_quotaN)r   
unresolvedhookr  r{   deadlinestaleTpr_head_changed)r   r  r  data
repositorypullRequestreviewThreadsnodes
isResolvedcommentsr   pathr;   body)r  r  okcritical_scope_expansion)r   r  outsider  rO   auto_triage_candidate)r   r  insider  )r   r   r   r   r   r   r^   joinr   r   CRITICAL_ESCALATION_HOOKCRITICAL_GEMINI_SCOPE_EXPANSIONAUTO_GEMINI_TRIAGE_HOOK)r=   r   rG   r   r   r  joinedr  repor   threadsr  r  nr  firstr   ur  r  s                       rc   fetch_gemini_statusr*    s    eY
PQZP[  \G  	H F**V]]2d3
 [["(bF&$F 

 
 f 6,&:P-  	  *"6#  	  {{7t#w{{3D'E'M
 	
 ;;v$"D88L!'RD	-	 	&BBff_%+GKK &BEJ 55EE*%+009?R'RIIfb)IIfb)
 	 b$??#N3H#AAquuV}'@aAFA$FQfX(EqFGF0$,<
 	
 * '	 y  d BFs)   #H" H>H>&I?I"H;:H;Freal_bugc               >   | st         S | j                  d      xs dj                         }| j                  d      xs g }|dk(  rt        |      dk(  rt        S |dk(  rt
        S |dk(  r|rt        S t         S |dk(  rt        S |d	k(  rt        S |d
k(  rt        S t         S )uW  fetch_gemini_status() 결과 + 추가 신호 → enum 7종 중 하나.

    분류 규칙:
      - status == 'ok' AND unresolved == 0 → GEMINI_COMPLETED
      - status == 'critical_scope_expansion' → GEMINI_SCOPE_EXPANSION
      - status == 'auto_triage_candidate' AND real_bug=True → GEMINI_REAL_BUG
      - status == 'auto_triage_candidate' (real_bug=False) → GEMINI_UNRESOLVED
      - status == 'unavailable_quota' → GEMINI_UNAVAILABLE_QUOTA
      - status == 'timeout' → GEMINI_TIMEOUT
      - status == 'stale' → GEMINI_STALE
      - 그 외 → GEMINI_UNRESOLVED (보수적)
    r   r;   r  r  r   r  r  r  r{   r  )
r*   r   r   r   r)   r/   r.   r+   r,   r-   )gemini_stater,  r   r  s       rc   classify_gemini_statusr/    s       x(.B557F!!,/52J~#j/Q.++%%(("*A0AA$$''re   c                p    | xs g D ](  }t         D ]  }|j                  |      st        c c S  * t        S )u$   변경 파일 → risk_level 분류.)r3   r   RISK_LEVEL_HIGH_CORERISK_LEVEL_LOW)rH   r   pats      rc   assess_risk_levelr4    s>    " ,* 	,Czz!}++	,,
 re   c                   g }| xs g D ]  }||z  }|j                         r|j                         s)	 |j                  dd      }t	        |j                         d      D ]U  \  }}d|v sd|v rt        D ]>  \  }}	|j                  |      s|j                  ||	||j                         dd	 d
       @ W  t        |      dk(  |dS # t        $ r Y w xY w)u   HIGH_CORE 시 변경 파일에 대해 위험 패턴 정적 검사.

    Returns:
      {"passed": bool, "violations": [{"file": str, "pattern": str, "line": int, "snippet": str}, ...]}
    utf-8replace)encodingr  r   )startRISKY_PATTERNSstatic_risky_pattern_scanN   )filepatternlinesnippetr   )passed
violations)existsis_file	read_textOSError	enumerate
splitlinesr:  r   r   r   r   )
rH   workspace_rootrB  relr  rz   linenor?  r3  descs
             rc   r;  r;    s      J$" #{{}DLLN	>>79>ED &doo&7qA 	LFD4'+F$+N+ 	T::d#%% ##' &#'::<#5	' 		* *o**EE  		s   C	CCc        	   
     \   t        |       |dk(  |xs dj                         dk(  |xs dj                         dk(  t        |      t        |      t        |      |t        k7  xs t        |      d}	|	j                         D 
cg c]
  \  }
}|r	|
 }}
}t	        |      dk(  |	|dS c c}}
w )u   8조건 검사. 모두 PASS여야 fallback_review_passed=True.

    Returns:
      {"passed": bool, "checks": {각 조건: bool}, "failed": [str, ...]}
    r   r;   r   CLEAN)effective_diff_equals_expectedforbidden_path_zeroci_all_successmerge_state_cleanhead_sha_lock_oksmoke_command_defineddry_run_decision_pass#static_risky_scan_pass_if_high_core)rA  checksfailed)rU   r   r1  itemsr   )diff_okforbidden_countrJ   rM   rS  rT  rU  rX   static_scan_passedrW  kvrX  s                rc   evaluate_fallback_reviewr_  2  s    $ +/w-.!3$?113y@06B==?7J !12!%&;!<!%&;!<..J$7I2JF #LLN4DAq!a4F4&kQ&&FKK 5s   
B(B(c                <    |dddt        |       ddg      }	 t        j                  |j                  xs d      }|j                  d      xs dj                         |j                  d	d      |j                  d
d      dS # t        j                  $ r i }Y ^w xY w)Nr   r   r   r   z'mergeStateStatus,headRefOid,baseRefNamer   mergeStateStatusr;   
headRefOidbaseRefName)ra  rb  rc  r9   r   r   r   r   r   r   )r=   r   r   r   s       rc   fetch_merge_statere  T  s    dFC	N; F**V]]2d3 %[[);<BIIKkk,3{{="5   s   #B BBc                &    t        |       xr | |k(  S ra   )rU   )	start_shacurrent_shas     rc   assert_head_sha_lockri  e  s    	?7yK77re   c                    dddt        |       ddg}t        |        ||      }|j                  |j                  xs ddd  |j                  xs ddd  dS )	Nr   r   r   z--squashz--delete-branchr;   0)r   r   r   )r9   r   r   r   r   )r=   r   r   r   s       rc   execute_squash_mergerl  j  sc    $Y=NOD!$'D\F''==&B/==&B/ re   c                    | sdddS  || d      }|j                   dk(  rd|j                  xs dd	d  d
S d|j                  xs dd	d  |j                  xs dd	d  t        dS )Nskippedzno smoke_command in task spec)r   r   iX  )r{   r   PASSr;   rk  )r   r   FAIL)r   r   r   rO   )r   r   r   CRITICAL_POST_MERGE_SMOKE)ru   r   r   s      rc   run_post_merge_smokerr  v  s~     #0OPPM3/FA V]]-@b%&,IJJ==&B/==&B/2	 re   c                   g }| D ]  }|j                  d      }|t        ||      }|j                  dd      }	 t        ||      }|j                  dg       xs g }|j                  dd      xs |j                  dd      }	|j                  dg       xs g }|j                  d	g       xs g }|r)t        t        |            t        t        |            k7  nd
}| xs# t        |      j                  t        |            }t        t        ||            }t        |j                  d      xr |j                  d      |	k7        }|dk(  xs |}|j                  |||dv xs
 |xs |xs ||dk(  |dk(  |dk(  |||||t!        |      d        |S # t        j                  t
        j                  t        f$ rJ}
t        j                  d||
       |j                  dg       xs g }|j                  dd      }	Y d}
~
d}
~
ww xY w)u  queue 다음 PR들의 BEHIND/conflict/diff 오염 자동 재평가 (task-2509+1 §9 보강).

    queue 항목 = {pr_number, expected_files?, prior_effective_files?,
                  prior_main_sha?, gemini_head_sha_at_last_review?}
    반환 = 각 PR별 state. 기존 키(needs_recheck/behind/conflict/blocked) 보존 +
            신규 키(effective_diff_drift/expected_files_maintained/forbidden_path_present/
                   gemini_stale/ci_rerun_needed/current_effective_files).
    r=   Nra  r;   rH   rb  z!observe_pr fallback for PR %s: %sprior_effective_filesrG   Fgemini_head_sha_at_last_reviewr   >   DIRTYr   BLOCKEDrv  rw  )r=   rM   needs_recheckbehindr   blockedeffective_diff_driftexpected_files_maintainedforbidden_path_presentgemini_staleci_rerun_neededcurrent_effective_files)r   re  
observe_prr|   SubprocessErrorr   r   rF  loggerdebugr   setissubsetrU   r   r   r^   )queuer   statesentryr=   r   msobscurrent_effectivecurrent_headexcprior_effectiverG   
diff_driftexpected_subsetforbidden_presentr~  ci_reruns                     rc   recheck_following_prsr    s>    F 0IIk*	 F3XX("-	6Y/C #(92 > D"77<4Rr8RL
  ))$;R@FB#3R8>B  3()*fS5I.JJ$) 	
   D$%..s>/BC 	 !!78I>!Z[II67 L		:;|K
 (N1z""$44 CC!2C6BHngY$.)8&7(''+,='>
 	A0b MK **D,@,@'J 	6LL<iM %		*A2 F L"88L"5L	6s   AF(H>?HHc                r   |ry t         j                  dd       t        j                  dd       t        j                  t
        j                        j                  d      | _        t        j                  | j                         d      dz   }t        t        dd	      5 }|j                  |       d d d        |r\t        | d
z  }t        |dd	      5 }t        j                  | j                         |dd       d d d        t!        |      | _        |S t        S # 1 sw Y   mxY w# 1 sw Y   -xY w)NT)parentsexist_okz%Y-%m-%dT%H:%M:%S.%fZFensure_ascii
r   r6  r8  z.merge-queue.jsonwr   r  indent)	AUDIT_DIRmkdir
EVENTS_DIRr   nowr   utcstrftimerQ   r   dumpsrd   openGLOBAL_AUDIT_LOGwritedumpr9   rP   )r:   r?   no_auditr?  fhper_tasks         rc   write_auditr    s	   
 OOD4O0TD1!hll3<<=TUH::h&&(u=DD	g	6 "
7)+< ==(C'2 	LbIIh&&("5K	L!(m 	L 	Ls   #D!(D-!D*-D6c                V    | t         vrt        d|        | |_        |
 || |       y y )NzUNKNOWN_CRITICAL_CODE: )CRITICAL_CODES
ValueErrorrO   )coder:   reporter_hooks      rc   emit_critical_escalationr    s<    
 >!24&9::!H dH% !re   z```yaml\s*\n(.*?)```c                   | j                  d      }d}t        j                  |      }|r|j                  d      }t	        |d      }t	        |d      }t        |d      }t        |d      xs d	}t        |d
      }	 |r|dk7  rt        |      n|xs d}	t        |d      xs d}
t        |d      xs d}t        j                  d|t        j                        }|r|j                  d      n| j                  }t        |||xs d|||	t        |
      j                         j                         dk(  t        |      j                         j                         dk(  d	      S # t        $ r |}	Y w xY w)uG   task md에서 expected_files / dependency / parallel_policy 등 추출.r6  r  r;   r   rG   ro   rn   rp   serial_onlyrq   zn/arr   falsers   z^# (task-\d+(?:\+\d+)?)trueN)	r?   rG   rn   ro   rp   rq   rr   rs   ru   )rE  _TASK_FRONTMATTER_REr   r   _extract_yaml_list_extract_yaml_scalarrK   r  r   	MULTILINEstemrm   r9   r   r   )	task_filerz   
yaml_blockr   rG   ro   rn   rp   queue_pos_raw	queue_pos	stale_raw
cherry_rawtask_id_matchr?   s                 rc   load_task_specr    sm   0DJ##D)AWWQZ
'
4DEN#J=J$Z=I*:7HIZ]O(5KLM"/<RWAW]+]j]sns	 %Z1IJUgI%j2GHSGJII8$MM(5m!!!$9>>G%/r'&"9~335;;=G
O11399;vE
 
  "!	"s   >E" "E0/E0c                   dt        j                  |       d}t        j                  || t         j                        }|sg S g }|j	                  d      j                         D ]  }|j                         }|j                  d      s%|dd  j                         }|j                  d      r.|j                  dd      }|dkD  r|d| n|j                  d      }	nq|j                  d      r.|j                  dd      }|dkD  r|d| n|j                  d      }	n2|j                  d	d      d   j                         j                  d      }	|	s|j                  |	        |S )
N^z:\s*\n((?:\s*-\s*.+\n?)+)r   -"r   "''#)r   escaper   r  r   rH  r   r   findsplitr   )
r  keyr>  r   rY  r?  r   r   endvals
             rc   r  r    s7   299S>"";<G
		':r||4A	E
%%' JJL||C ekkm>>#((3"C #a#a*SYYu-=C^^C ((3"C #a#a*SYYu-=C))C#A&,,.44U;CLL Lre   c                    dt        j                  |       d}t        j                  || t         j                        }|sy|j	                  d      j                         j                  d      }|S )Nr  z:\s*([^\n#]+?)(?:\s*#.*)?$r;   r   r  )r   r  r   r  r   r   )r  r  r>  r   r  s        rc   r  r  *  s\    299S>""<=G
		':r||4A
''!*



"
"5
)CJre   c                      e Zd ZU  ed       Zded<   dZded<   dZded	<   d
Zded<   dZ	ded<   dZ
ded<   dZded<    ed       Zded<   dZded<   y)ExecutorContextc                     t         S ra   )r   rk   re   rc   <lambda>zExecutorContext.<lambda>6  s     re   rD   
RunnerTyper   Nr>   r   rt   ru   FrU   r  Optional[Callable[[str], bool]]r   Optional[list[re.Pattern]]extra_forbidden_patternsfixture_main_shac                     y ra   rk   )_ss    rc   r  zExecutorContext.<lambda>=  s    re   )defaultCallable[[float], None]r   .Optional[Callable[[str, QueueDecision], None]]r  )rg   rh   ri   r   r   rj   r   ru   r  r   r  r  r   r  rk   re   rc   r  r  4  sn    /FGFJG $J$)-M&-Hd59M29;?8?&*m*',_'EG$EDHMAHre   r  c                   t        d| |j                  t        |j                        t        |            }t	        |      |_        t        |t              rt        |j                  d            nd}	t        ||	      |_        t        |j                  |j                  |j                        \  }
}|
s7t         |_        ddj%                  |       |_        |j"                  |_        |S h d	}|j*                  |vrft,        |_        d
|j*                  |_        t.        |_        t.        |_        t4         dt.         |_        t7        t.        ||j8                         |S |j:                  }|du xs3 t        |t<              xr! |j?                         jA                         dk(  }|rYt,        |_        d|_        t.        |_        t.        |_        t4         dt.         |_        t7        t.        ||j8                         |S |jB                  r|jB                  }ntE        |j                        }||_#        ||_$        |j                  d      xs djK                         }||_&        |dk(  r|jN                  rtQ        |j                  dd      |jN                  |j                  |      }|j                  d      r>t,        |_        d|_        tR        |_        tR        |_        t4         dtR         |_        |S tU        ||j                        \  }}}|stW        ||j                  |jX                        }|r`t,        |_        d|_        ||_-        t\        |_        t\        |_        t4         dt\         |_        t7        t\        ||j8                         |S t^        |_        g }|r|ja                  d|        |r|ja                  d|        ddj%                  |       dtb         |_        |j"                  |_        |S tW        ||j                  |jX                        }|rEt,        |_        d|_        ||_-        t\        |_        t\        |_        t4         dt\         |_        |S |j                  dd      }||_2        |tf        k(  r7tf        |_        d|j                  d        |_        |j"                  |_        |S |th        k(  r"t,        |_        d!|_        tj         d"|_        |S |j                  dd      }tm        |j                  d#g       xs g       |_7        |d$k(  r>t,        |_        d%|_        tp        |_        tp        |_        t4         dtp         |_        |S |d&k(  r2tr        |_        d'|jn                   |_        |j"                  |_        |S |j                  tt        v rHd|_;        |j
                  tx        k(  rIt{        |      }t        |j                  d(      xs g       |_>        t        |j                  d)            }nd}t        |d*|r|nd|dt        |j                        d|j
                  xs t        |+	      }||_B        t        |j                  d)            |_C        |j                  d)      sgt,        |_        t         ddj%                  |j                  d,      xs g        d-|j                   |_        d|_E        tj         dt         |_        |S d|_E        n!|j                  t        k(  rd|_E        d|_;        |d.k7  r|d/k(  rYt,        |_        d0|_        tR        |_        tR        |_        t4         dtR         |_        t7        tR        ||j8                         |S |dk(  r"t,        |_        d1|_        tj         d2|_        |S t        |_        d3| |_        |j"                  |_        |S |j                  s<t,        |_        d4|j                   d5|jv                   |_        tj         d6|_        |S t        |_        d7|_        |j"                  |_        |S )8uP   10조건 게이트 — 결과 decision 반환 (실제 머지 X, dry-run 가능).UNKNOWN)r:   r=   r?   rG   rH   r,  Fr+  )r   z	pending: ,>   r  parallel_safelimited_parallelzINVALID_PARALLEL_POLICY: : Tr  z=cherry_pick_allowed=true is forbidden (DEPENDENCY_CYCLE risk)ra  r;   r   rc  main)r   r   r   rM   r   MERGE_CONFLICT_DURING_BASE_SYNCFORBIDDEN_PATHzextra=zmissing=zdiff contamination: z; z; hook=FORBIDDEN_PATH_INSIDE_EXPECTEDr   zCI failure: r   r   z: CI_IN_PROGRESSr  r  &GEMINI_REAL_BUG_OUTSIDE_EXPECTED_FILESr  z,unresolved (auto_gemini_triage hook); count=rB  rA  r   )	rZ  r[  rJ   rM   rS  rT  rU  rX   r\  rX  z; gemini_status=rN  rw  MERGE_STATE_BLOCKEDMERGE_STATE_BEHIND_AFTER_SYNCz: MERGE_STATE_BEHIND_AFTER_SYNCzmergeStateStatus=z&REVIEW_GATE_NOT_PASSED: gemini_status=z; fallback_review_used=z: REVIEW_GATE_NOT_PASSEDzall 10 gates PASS)Ir8   r?   r^   rG   r4  rX   r   r\   rU   r   r/  rT   r   ro   r   r   r   r:   r   r<   rZ   rp   r   CRITICAL_DEPENDENCY_CYCLErO   r[   FINAL_CRITICAL_PREFIXr  r  rs   r9   r   r   r  r   r@   rB   r   rM   r   r   CRITICAL_BLOCK_OVERRIDEr   r   r  rI   CRITICAL_FORBIDDEN_PATHr   r   REPLACEMENT_PR_RUNNER_HOOKrJ   r   r   FINAL_BLOCKED_PREFIXr   rL   r"  r   GEMINI_UNAVAILABLE_STATUSESrV   r1  r;  r_   r_  ru   r2  r]   rW   r5   rY   r)   r   r   )r=   	task_specpr_head_sharH   merge_stateci_stater.  ctxr:   _gem_real_bughead_okr   _VALID_PARALLEL_POLICIES_cherry_raw_cherry_boolmain_head_startr  syncrZ  r   r   r   reason_partsrJ   
gem_statusscanr\  fbs                               rc   evaluate_prr  A  s    !!I445_-H ,O<H:D\SW:XD))*56^cM3L=YH 0

''GW
 3%chhw&7%89"*"3"3  T  (@@/5i6O6O5RS!:'@$%:$;2>W=X"Y !:HcFWFWX//Kt 	T{C(R[->->-@-F-F-HF-R  /Y!:'@$%:$;2>W=X"Y !:HcFWFWX ..)#**5#2H !,H //,
-
3	:	:	<B"$H	X~#.."}f=~~::!	
 88J 3H?HO%<H"+BH()>(?rBYAZ&[H#O 5_iF^F^_GUG*Y55s7S7S
	  3H.HO'0H$%<H"+BH()>(?rBYAZ&[H#$%<hHYHYZO:& 01(7) 450<1H0IQkPlm"*"3"3 '1133O3OI /:#, !8'>$%:$;2>U=V"W Xr*I"H$$,(i)@(AB"*"3"3N"/*%9$::J"K !!(B/J'*<+;+;L"+M+SQS'TH$///B!@'F$%:$;2>]=^"_,,3HIiIiHjk"*"3"3 !<<(,%"66,_=D.2488L3I3OR.PH+!%dhhx&8!9!% &#,i"!!"&s'8'8"9"&**<n1

 +-'*.rvvh/?*@'vvh 3H)*"SXXbffX6F6L"-M,NN^_g_u_u^vw O +0H')=(>bAW@X&YH#O&*#			#3	3&*#(-% 
W}? 3H3HO%<H"+BH()>(?rBYAZ&[H#$%<hHYHYZO> 3H=HO)=(>>]&^H#O1-bT2"*"3"3 &&/4X5K5K4L M$$,$A$A#BD 	 &:$::R"S +H)HO&//HOre   c                   | j                   t        k7  r| S  ||      }|| _        t        | j                  xs d|      s5t
        | _         d| j                   d| | _        | j                   | _        | S |^ |       }|| _        | j                  rD|| j                  k7  r5t
        | _         d| j                   d| | _        | j                   | _        | S |s8|j                  s,t        | _         t        | _        t         dt         | _        | S |r| j                   | _        | S t        ||j                        }|d   dk7  r(t        | _         d	|d
    | _        t         d| _        | S |j                   N|j                  g d|j                          |j                  g d|j                         }	|	j"                  dk(  }
nd}
|
du rbd}|| _        t        | _         d| _        t&        | _        t&        | _        t,         dt&         | _        t/        t&        | |j0                         | S |
t3        |j                  |j                        }|j5                  dd      | _        |j5                  d      dk(  rt        | _         d| _        t&        | _        t&        | _        t,         dt&         | _        t/        t&        | |j0                         | S t3        |j                  |j                        }|j5                  dd      | _        |j5                  d      dk(  rYt        | _         d| _        t&        | _        t&        | _        t,         dt&         | _        t/        t&        | |j0                         | S t7        |dg       xs g }|r3t9        ||j                        }t;        | j<                        |z   | _        t>        | _         d| _        | j                   | _        | S )uU   §9 + §10 — head SHA 재확인 후 squash merge (dry_run=False 시 실제 실행).r;   zPR head changed: start=z merge=Nzmain head changed: start=r  r   r   zsquash merge failed: r   z: SQUASH_MERGE_FAILEDr   r   )r   r   z	--ff-onlyr   FFAIL_FAST_FORWARDz:POST_MERGE_SMOKE_FAILURE: fast-forward failed before smoker   rp  z9POST_MERGE_SMOKE_FAILURE (ff-only skipped: no pr_workdir)r    following_queuezmerged + smoke PASS) r:   r   rC   ri  rB   r   r<   rZ   rA   r@   ru   r   r6   r  rl  r   r   r   rN   rq  rO   r[   r  r  r  rr  r   getattrr  r^   rS   r   )r:   r=   r  fetch_pr_head_at_mergefetch_main_head_at_mergedry_runpr_head_nowmain_nowmerge_result	ff_resultff_oksmoke_status_strsmoke_following_queuefollowing_statess                  rc   verify_head_lock_then_merger  /  s    ..(3K!,H : : @b+N0%h&@&@%AV 	 #+"3"3++-'/$''H8T8T,T 4H+H,H,H+IQYPZ[ O '/&7&7H#O3,,/<%9$:"=_<`"a"*"3"3'	3::>LL!Q&/1,x2H1IJ%9$::O"P ~~!

8cnn
MJJ8  
	 $$) ~. 0/V!:'@$%:$;2>W=X"Y !:HcFWFWX	$S%6%6

C %		(B 799X&( 3HYHO%>H"+DH()>(?rB[A\&]H#$%>#J[J[\O$S%6%6

C %		(B 799X&( 3H8HO%>H"+DH()>(?rB[A\&]H#$%>#J[J[\O $+30A2#F#L"01A3::N%)(*D*D%EHX%X"*H+HO&//HOre   c                    |dddt        |       ddg      }	 t        j                  |j                  xs d      }|j                  d      xs g D cg c]&  }|j                  d      s|j                  dd	      ( }}|j                  d
d	      |j                  dd      |j                  d      xs d	j                         |dS # t        j                  $ r i }Y w xY wc c}w )Nr   r   r   r   z-headRefOid,baseRefName,mergeStateStatus,filesr   r   r  r;   rb  rc  r  ra  )rb  rc  ra  rH   rd  )r=   r   r   r   r   r   s         rc   r  r    s    dFC	NA F**V]]2d3 *1W)=)CV1fQUU62VEVkk,3{{=&9$[[);<BIIK 	   Vs   #C C#*C#C C c                  
 t        j                  d      }|j                  dt        dd       |j                  dt        dd	
       |j                  dddd       |j                  dddd       |j                  ddd       |j                  dt        dd
       |j                  dt        t	        t
              d
       |j                  dt        dd
       |j                  dt        dd 
       |j                  |       }|j                  rt        |j                        }n(t        t        j                  t        d!d"d#$             y%|j                         s+t        t        j                  t        d&| d"d#$             y%t        |      }t         
t#        |j$                  
      }t'        |j$                  
|j(                  |j*                  '      }t-        |j$                  
|j.                        }t1        
t	        t
              |j2                  r|j2                  j5                         nd |j6                  (      }t9        |j$                  ||j;                  d)d      |j;                  d*g       |j;                  d+d      |j;                  d,d-      d.|||/      }	t=        |	|j$                  |
fd0
fd1|j>                  2      }	tA        |	|jB                  |j6                  3       t        t        j                  |	jE                         d#d%4             |	jF                  tH        tJ        hv ry5|	jF                  tL        k(  ry6y7)8Nz merge_queue_executor (task-2509))descriptionz--prTu	   PR 번호)typerequiredhelpz--task-filer;   u   queue 선두 task spec md)r  r  r  z	--dry-run
store_truezdry-run (default true))actionr  r  z--no-dry-runr  store_falseu   실제 머지 수행)destr  r  z
--no-auditu'   audit log 기록 안 함 (테스트용))r  r  z--smoke-commandu   post-merge smoke 명령z--workspacezworkspace rootz--ci-max-polls   u+   CI 상태 polling 최대 횟수 (default 5)z--ci-backoff-secondsg      $@u4   CI polling 지수 백오프 기본값 (default 10.0)zmissing --task-file)r:   r<   Fr  r   ztask file not found: )r   r   )r   r   ru   r  rb  rH   ra  rc  r  )ra  rc  )r=   r  r  rH   r  r  r.  r  c                <    t        |       j                  dd      S )Nrb  r;   )r  r   )r'  r   s    rc   r  zmain.<locals>.<lambda>  s    Av)>)B)B<QS)T re   c                     t               S ra   )r   )r   s   rc   r  zmain.<locals>.<lambda>  s    )@ re   )r:   r=   r  r
  r  r  )r  r  r      r   )'argparseArgumentParseradd_argumentrK   r9   r~   float
parse_argsr  r	   printr   r  r   rC  r  r   r  r   r  ci_max_pollsci_backoff_secondsr*  rG   r  ru   r  r  r  r   r  r  r  r?   rd   r:   r   r   r   )argvparserr   	task_pathr   pr_obscigemr  r:   r   s             @rc   r  r    s   $$1STF
S4kJ
CB]^
L$Mef
Y}Sij
\@ij
)RF_`
CYN^_
(sADqr
.UD  PF  GT"D ~~(	 	djj++
  	  djj+-i[9
  	  )$DF(F	&D4E4EW[WnWn	oB
dggvt/B/B
CC
y>484F4Fd((..0D	C ''JJ|R0

#4b9 &

+=r B!::mV<
 H +''T!@H $,,?	$**X%%'eA
FG/1CDD33re   __main__)N<   )r   rF   rx   r>   r{   rK   rf   zsubprocess.CompletedProcess)r   rF   rf   Nonera   )ro   rF   r   r  r   r  rf   ztuple[bool, list[str]])r   r  rf   r9   )
r   r9   r   r9   r   r  rM   r9   rf   r\   )r   rF   rf   zset[str])rH   rF   rG   rF   rf   z!tuple[bool, list[str], list[str]])rH   rF   r   rF   r   r  rf   rF   )r=   rK   r   r  r   rK   r   r(  r   r  rf   r\   )r=   rK   r   r  rG   rF   rf   r\   )r.  r\   r,  rU   rf   r9   )rH   rF   rf   r9   )rH   rF   rI  r	   rf   r\   )rZ  rU   r[  rK   rJ   r9   rM   r9   rS  rU   rT  rU   rU  rU   rX   r9   r\  rU   rf   r\   )r=   rK   r   r  rf   r\   )rg  r9   rh  r9   rf   rU   )ru   rt   r   r  rf   r\   )r  rR   r   r  rf   rR   )F)r:   r8   r?   r>   r  rU   rf   zOptional[Path])r  r9   r:   r8   r  r  rf   r5  )r  r	   rf   rm   )r  r9   r  r9   rf   rF   )r  r9   r  r9   rf   r9   )r=   rK   r  rm   r  r9   rH   rF   r  r\   r  r\   r.  r\   r  r  rf   r8   )NT)r:   r8   r=   rK   r  r  r
  zCallable[[int], str]r  zOptional[Callable[[], str]]r  rU   rf   r8   )r-  rt   rf   rK   )srv   
__future__r   r%  r   loggingosr   r|   systimedataclassesr   r   r   r   r   pathlibr	   typingr
   r   r   environr   r~   r  r  r  	getLoggerrg   r  r   r   r   r   r   r   r   r   r   r   r   CRITICAL_DIFF_REPLACEMENT_FAILEDr"  r  r  CRITICAL_REPLACEMENT_FAILEDrq  r  r   r  r#  POST_MERGE_SMOKE_HOOKr!  r)   r*   r+   r,   r-   r.   r/   	frozensetGEMINI_STATUS_VALUESr  r2  RISK_LEVEL_MEDIUMr1  compiler3   rj   r:  FINAL_AUTO_MERGE_ALLOWEDr  r  r5   r6   r8   rm   CompletedProcessr  r   r   r   r   r   r   r   r   r   sleepr  r*  r/  r4  r;  r_  re  ri  rl  rr  r  r  r  DOTALLr  r  r  r  r  r  r  r  r  exitrk   re   rc   <module>rL     s  $L #    	 	  
  0 0 '  * * 02GHI	!H,
 #88	22 			8	$ * ) 3 + - % !3 / !A  4 #T  "C J F : 6  $# I  5 . 1 9  & ' 5 !#1  ')AL/3I"   (nl)    "  BJJ23BJJ12BJJ !BJJ,-	- )  RZZ)*L9RZZ&'):;RZZ./1ABRZZ&'7RZZ./1EFRZZ346JK . , - 1 %I "      F . . . c:6667
/ 6:((( 3( 	(B  	
 
:3CCC 'C( BJJ&'BJJ)*BJJ,-BJJ+,BJJ)*  26 / 	2  '+zz"@"@"@ "@ 	"@
 %"@ 
"@LSSS S 
	Sl DI D %FFF 
FDLL L 	L
 L L  L  L L L 
LD"8
& 
$>>> >J   	4 EI	&
	&	& B	& 
		& "rzz"9299E B0 	I 	I 	Ikkk k 	k
 k k k 
k kf =Aiii 
i 1	i
 :i i iZ&DN zCHHTV re   