
     jD                      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dl m!Z! ddl"m#Z#m$Z$m%Z% ddl&m'Z(m)Z)m*Z* ddl+m,Z-m.Z. ddl/m0Z0m1Z1m2Z2m3Z3 dZ4e4e!e#e$e%e(e)e*e-e.e0e1e2e3fZ8dZ9dZ:dZ;dZ<dZ=dZ>dZ?dZ@dZAdZBd ZCd!ZDd"ZEd#ZFd$ZGd%ZHd&ZId'ZJd(ZKd)ZLeFeGeHeIeJeKeLhZMh d*ZNd+ZOd,ZPd-ZQd.ZRd/ZSd0ZTd1ZUd2ZVd3ZWd4ZXd5ZY eZeSeTeUeVeWeXeYh      Z[ eZeUeVeWh      Z\d6Z]d7Z^d8Z_ ej                  d9       ej                  d:       ej                  d;       ej                  d<      gZad=ebd><    ej                  d?      d@f ej                  dA      dBf ej                  dC      dDf ej                  dE      dFf ej                  dG      dHf ej                  dI      dJfgZce9ZddZedKZfdLZgdMZhe G dN dO             Zie G dP dQ             ZjedRej                  f   ZldddSZmddTZnddUZo	 d	 	 	 	 	 	 	 ddVZpddWZq	 	 	 	 	 	 	 	 	 	 ddXZrddYZs	 	 	 	 	 	 ddZZt ej                  d[       ej                  d\       ej                  d]       ej                  d^       ej                  d_      gZu	 d	 	 	 	 	 	 	 dd`Zvdadbe
j                  f	 	 	 	 	 	 	 	 	 	 	 ddcZx	 	 	 	 	 	 	 	 dddZyddeddfZzddgZ{deEdh	 	 	 	 	 	 	 	 	 	 	 	 	 ddiZ|ddjZ}ef	 	 	 	 	 ddkZ~	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddlZddmZddnZddoZ	 	 	 	 	 	 ddpZ'	 	 	 	 	 	 ddqZ	 d	 	 	 	 	 	 	 ddrZ	 d	 	 	 	 	 	 	 ddsZ ej                  dtej                        ZdduZddvZddwZe G dx dy             Z	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddzZ	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 dd{Zdd|Zddd}Zed~k(  r e	j                    e              yy# e5$ r9Z6ejo                  de6       dZ4dZ!dZ#dZ$dZ%dZ(dZ)dZ*dZ-i Z.dZ0dZ1dZ2dZ3Y dZ6[6dZ6[6ww xY w)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)ReplacementPRRunner)	triage_prto_legacy_gemini_stateTriageReport)run_post_merge_smokePostMergeSmokeRunSmokeStatus)process_eventLEGACY_CRITICAL_MAP)CriticalEscalationTypeEscalationPacketReviewGateStatusGeminiTriageResultTz#W1 wiring modules not available: %sF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WAITING_FOR_GEMINI_REVIEWOWNER_PAT_FALLBACK_BLOCKEDg     v@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Z"ded+<   dZ#d ed,<   dZ$d-ed.<   dZ%d-ed/<    ee      Z&d)ed0<   dZ'ded1<   dZ(ded2<   dZ)ded3<   dZ*d4ed5<   dZ+d4ed6<   dZ,d4ed7<   dZ-ded8<   dZ.d ed9<   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_violationspipeline_stepreplacement_usedzOptional[dict]triage_summarysmoke_envelopeescalations	pushed_atgemini_submitted_atci_complete_atOptional[float]push_to_ci_complete_secondspush_to_gemini_review_secondsgemini_gate_wait_secondsrerun_countpremature_gate_fail_detectedc                    t        |       S N)r   )selfs    1/home/jay/workspace/utils/merge_queue_executor.pyto_dictzQueueDecision.to_dict  s    d|    )returnrk   )0__name__
__module____qualname____annotations__rK   rL   rN   rO   rP   rQ   rR   r   rm   rV   rW   rX   rY   r[   r\   r]   r^   r_   r`   rb   rc   re   rf   rg   rh   ri   rj   rk   rl   rn   ro   rp   rq   rr   rs   rt   ru   rv   rx   ry   rz   r{   r|   r    r   r   rG   rG      s   MFC#I}#!G]!)--)--'+}+'+}+ %d ;NI;!&t!<OY<!&t!<OY<Is#$S$  L##'M=' $J$Is$)$$?z?#'M='!&$&#(D( $J$$$$(NM()--#(#>D>#(#>D>#'M='"d"%)NN)%)NN)d3K3#I}#)--$(NM(37759!?904o4K). $.r   rG   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 정상화.rH   rN   rU   rV   	risk_area
dependencyparallel_policyr
   merge_queue_positionrd   stale_recheck_requiredcherry_pick_allowedNOptional[list[str]]smoke_command)r   r   r   __doc__r   r   r   r   r   r   r     s>    'LN  )-M&-r   r   .c                X    t        j                  | |xs t        t              dd|      S )NT)cwdcapture_outputtexttimeout)
subprocessrunrH   	WORKSPACE)argsr   r   s      r   _default_runnerr   $  s+    >>!3y> r   c                    | D cg c]  }|t         v s|j                  d      s|  }}|rt        d|       d| v rt        d      y c c}w )Nr3   zFORBIDDEN_GIT_FLAGS detected: rebaseREBASE_FORBIDDEN)FORBIDDEN_GIT_FLAGS
startswithRuntimeError)r   abads      r   assert_no_forbidden_git_flagsr   /  s]    
Ra#66!,,y:Q1
RC
R
;C5ABB4-.. 	 Ss
   A
A
c                    | xs dj                         j                         }|dk(  rdddddS |dk(  rdd	dd
dS |dk(  rdt        dddS dddd| dS )u#  token_source 4 enum 입력 → merge 실행 허용 여부 + 분리 decision.

    회장 §2 정책:
      - GITHUB_APP_INSTALLATION_TOKEN → allow_merge=True, decision='APP_TOKEN_OK'
      - GITHUB_ACTIONS_TOKEN          → allow_merge=True, decision='ACTIONS_TOKEN_OK'
      - OWNER_PAT                     → allow_merge=False, decision=OWNER_PAT_FALLBACK_BLOCKED,
                                         capability_gap=True
      - UNKNOWN                       → allow_merge=False, decision='AUTOMATION_CAPABILITY_GAP',
                                         capability_gap=True (fail-closed)

    회장 §금지: owner_pat을 bot identity로 위장 X. 따라서 OWNER_PAT 시 allow_merge는
    반드시 False. capability_gap=True는 ops 채널 marker이며 Critical 7종 외이다.
    rJ   GITHUB_APP_INSTALLATION_TOKENTAPP_TOKEN_OKFz&GitHub App installation token detected)allow_mergerI   capability_gaprK   GITHUB_ACTIONS_TOKENACTIONS_TOKEN_OKz$GitHub Actions runner token detected	OWNER_PATz<owner_pat fallback detected; autonomy success NOT recognizedAUTOMATION_CAPABILITY_GAPz&token source unknown or unclassified: )stripupperr(   )token_sourcesrcs     r   select_merge_token_decisionr   B  s     2
$
$
&
,
,
.C
--&#>	
 	
 $$*#<	
 	
 k 2"T	
 	
 /:<:JK	 r   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   )	
isinstancerH   rematchr   appendgroupstdoutlen)	r   runnermain_log_greppendingspecmrN   stateresults	            r   check_predecessor_mergedr   p  s     GW} $$$6>HHBDJJLQNN4 QWWQZ%;8H$ )w'}kWWICVX\^abc}}""$NN7#'$( LA''r   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   rJ   MAIN_HEAD_SHA_FETCH_FAILED)r   r   r   )r   r   shas      r   fetch_main_headr     sA    
0178F==B
%
%
'C788Jr   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r   Tr   merge_no_editr   r   rJ   CONFLICTr   )r   
returncoder   stderrlower)
_pr_branch
pr_workdirr   r\   r   r   proccombineds           r   sync_pr_baser     s     F
 X%7D!$'$J'DF;&F8!KK%2$++*;<!Z8>>3C%C!%F:Mr   c                j    | D ch c]#  }|j                         s|j                         % c}S c c}w r~   )r   )filesps     r   _normalize_file_listr     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   )rW   rV   expected	effectiveextramissings         r   compare_effective_diffr     sY     $N3H$_5I9x'(EX	)*GJ!O1G 1E7BBr   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.)rm   DEFAULT_FORBIDDEN_PATTERNSextendr   searchr   )rW   allowed_expectedextra_patternspatternsr   	invasionsfr   s           r   detect_forbidden_pathsr     sz     ./H'#$45HI = 	Axx{  #	 r   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statusrJ   )r  detailsrawc              3  $   K   | ]  }|d v  
 yw)>   ERRORFAILURE	CANCELLED	TIMED_OUTACTION_REQUIREDNr   .0ss     r   	<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_PROGRESSNr   r  s     r   r  z"fetch_ci_status.<locals>.<genexpr>	  s     bTUqOObr  r   c              3  $   K   | ]  }|d v  
 yw)>   NEUTRALSKIPPEDSUCCESS	COMPLETEDNr   r  s     r   r  z"fetch_ci_status.<locals>.<genexpr>  s     UqqBBUr  r  )rangemaxrH   jsonloadsr   JSONDecodeErrorgetr   r   r"   anyr#   all)rL   r   	max_pollsbackoff_secondssleeperattemptr   payloadrollupstatusesitemr   s               r   fetch_ci_statusr+    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graphqlr2   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)messagerJ   N)r   rk   r   rH   r   )r  es     r   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  r6  r7  data
repositorypullRequestreviewThreadsnodes
isResolvedcommentsr   pathrJ   body)rB  rC  okcritical_scope_expansion)r  r6  outsider7  r^   auto_triage_candidate)r  r6  insider7  )r  r  r   r  r   r   rm   joinr   r   CRITICAL_ESCALATION_HOOKCRITICAL_GEMINI_SCOPE_EXPANSIONAUTO_GEMINI_TRIAGE_HOOK)rL   r   rV   r   r'  r/  joinedr;  repor   threadsr?  r6  nrA  firstr   urH  rF  s                       r   fetch_gemini_statusrS    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;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  rJ   r6  rD  r   rE  rG  r5  r   r9  )
r9   r   r   r   r8   r>   r=   r:   r;   r<   )gemini_staterU  r  r6  s       r   classify_gemini_statusrX  k  s       x(.B557F!!,/52J~#j/Q.++%%(("*A0AA$$''r   c                    | sy	 | j                         }|j                  d      r|dd dz   }t        j                  |      j	                         S # t
        t        f$ r Y yw xY w)u8   ISO8601 string → epoch seconds. None/invalid → None.NZz+00:00)r   endswithr   fromisoformatr`   
ValueError	TypeError)value
normaliseds     r   _parse_iso8601rb    sg    [[]
s##CR83J%%j1;;==	" s   AA A#"A#)rv   wait_budget_secondsc                4   t        |       }t        |      }t        |      }||||z
  nd}	||||z
  nd}
|||z
  nd}d}d}d}|	d|	|
|dddS |/|xs d|k  rd}d}d}n-d}|xs d	j                         d
vrd}d}d}n||k  rd}d}d}nd}||	|
|||dS )u/  task-2521 §2 — Gemini async race 박제 + 5 metric.

    분기:
      1. gemini_submitted_at == None  → review 미도착
         a. now - pushed_at <  wait_budget → status="async_pending", premature_gate_fail_detected=True
         b. now - pushed_at >= wait_budget → status="wait_budget_exhausted" (호출자가 quota/timeout/unavailable
            과 구분; 본 함수는 단순 "예산 초과" 신호만 emit)
      2. gemini_submitted_at != None  AND  submitted_at < pushed_at
            → status="async_pending" (stale review — 새 head SHA에 대해 미반영)
              + premature_gate_fail_detected=True
      3. gemini_submitted_at != None  AND  submitted_at >= pushed_at  → status="ok"

    분류는 GEMINI_UNAVAILABLE_QUOTA / GEMINI_TIMEOUT 과 구분되어 있어야 함 (task-2521 §2 명시).
    quota/timeout 신호는 호출자(fetch_gemini_status)가 이미 결정하므로 본 함수는 "async_pending"
    만 책임진다.

    Returns:
      {
        "status": "ok" | "async_pending" | "wait_budget_exhausted",
        "push_to_ci_complete_seconds": float | None,
        "push_to_gemini_review_seconds": float | None,
        "gemini_gate_wait_seconds": float | None,
        "premature_gate_fail_detected": bool,
        "should_block_with_waiting_marker": bool,
      }
    NFrD  )r  rx   ry   rz   r|    should_block_with_waiting_markerr   Tasync_pendingwait_budget_exhaustedrJ   >   r<   r;   r:   )rb  r   )rt   ru   rv   rc   	now_epochrc  pushed_epochsubmitted_epochci_complete_epoch
push_to_cipush_to_gemini	gate_wait	prematurestatus_labelshould_blocks                  r   evaluate_gemini_async_racerr    sF   F "),L$%89O&~6 $):)F 	L(  $)D 	,&  # 	L   ILL +5-;(1,105
 	
 N11I*LL 3L#**, 5   /# 		<	'	&  '1)7$-(1,8 r   c                p    | xs g D ](  }t         D ]  }|j                  |      st        c c S  * t        S )u$   변경 파일 → risk_level 분류.)rB   r   RISK_LEVEL_HIGH_CORERISK_LEVEL_LOW)rW   r   pats      r   assess_risk_levelrw    s>    " ,* 	,Czz!}++	,,
 r   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   )
rW   workspace_rootr  relrB  r   linenor  rv  descs
             r   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   rJ   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)r  checksfailed)rd   r   rt  itemsr   )diff_okforbidden_countrY   r\   r  r  r  rg   static_scan_passedr  kvr  s                r   evaluate_fallback_reviewr  7  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   mergeStateStatusrJ   
headRefOidbaseRefName)r  r  r  rH   r  r  r   r  r   r   )rL   r   r   r'  s       r   fetch_merge_stater  Y  s    dFC	N; F**V]]2d3 %[[);<BIIKkk,3{{="5   s   #B BBc                &    t        |       xr | |k(  S r~   )rd   )	start_shacurrent_shas     r   assert_head_sha_lockr  j  s    	?7yK77r   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-branchrJ   0)r   r   r   )rH   r   r   r   r   )rL   r   r   r   s       r   execute_squash_merger  o  sc    $Y=NOD!$'D\F''==&B/==&B/ r   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   PASSrJ   r  )r  r   FAIL)r  r   r   r^   )r   r   r   CRITICAL_POST_MERGE_SMOKE)r   r   r   s      r   r   r   {  s~     #0OPPM3/FA V]]-@b%&,IJJ==&B/==&B/2	 r   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).
    rL   Nr  rJ   rW   r  z!observe_pr fallback for PR %s: %sprior_effective_filesrV   Fgemini_head_sha_at_last_reviewr   >   DIRTYr   BLOCKEDr  r  )rL   r\   needs_recheckbehindr   blockedeffective_diff_driftexpected_files_maintainedforbidden_path_presentgemini_staleci_rerun_neededcurrent_effective_files)r   r  
observe_prr   SubprocessErrorr  r  r  loggerdebugr   setissubsetrd   r   r   rm   )queuer   statesentryrL   r   msobscurrent_effectivecurrent_headexcprior_effectiverV   
diff_driftexpected_subsetforbidden_presentr  ci_reruns                     r   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   ry  r{  z.merge-queue.jsonwr   r  indent)	AUDIT_DIRmkdir
EVENTS_DIRr   nowr   utcstrftimer`   r  dumpsr   openGLOBAL_AUDIT_LOGwritedumprH   r_   )rI   rN   no_auditr  fhper_tasks         r   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                   | t         vrt        d|        | |_        |
 || |       y t        	 |j                  xs d|j
                  xs d| d|j                  |j                  | dd}t        |t        dd	      }t        |d
      r|j                  g |_
        |j                  j                  |       y y # t        $ r }t        j                  d|       Y d }~y d }~ww xY w)NzUNKNOWN_CRITICAL_CODE: unknownr   merge_queue_executor)rI   rK   r^   )rN   rL   
event_typesourceevidenceTF)r  dry_runr  rs   z7W5 report_critical_event() failed (silent fallback): %s)CRITICAL_CODESr^  r^   report_critical_eventrN   rL   rI   rK   r   hasattrrs   r   	Exceptionr  warning)coderI   reporter_hook_event_result_w5_excs         r   emit_critical_escalationr    s    
 >!24&9::!H dH% !,c'//<9!)!3!3!8q"&4$,$5$5"*//)-!
 0#, "	 x78;O;O;W+-H($$++G4- -.  cXZabbcs   B	B< <	C%C  C%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 등 추출.ry  r  rJ   r   rV   r   r   r   serial_onlyr   zn/ar   falser   z^# (task-\d+(?:\+\d+)?)trueN)	rN   rV   r   r   r   r   r   r   r   )r  _TASK_FRONTMATTER_REr   r   _extract_yaml_list_extract_yaml_scalarrZ   r^  r   	MULTILINEstemr   rH   r   r   )	task_filer   
yaml_blockr   rV   r   r   r   queue_pos_raw	queue_pos	stale_raw
cherry_rawtask_id_matchrN   s                 r   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   r  r   r   findsplitr   )
r  keyr  r   r  r  r  r  endvals
             r   r  r  2  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 Lr   c                    dt        j                  |       d}t        j                  || t         j                        }|sy|j	                  d      j                         j                  d      }|S )Nr  z:\s*([^\n#]+?)(?:\s*#.*)?$rJ   r   r  )r   r  r   r	  r   r   )r  r  r  r   r  s        r   r  r  J  s\    299S>""<=G
		':r||4A
''!*



"
"5
)CJr   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<   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(<    ed)       Zd*ed+<   eZd,ed-<   d.Zd/ed0<   y)1ExecutorContextc                     t         S r~   )r   r   r   r   <lambda>zExecutorContext.<lambda>V  s     r   rS   
RunnerTyper   NrM   r   r   r   Frd   r  Optional[Callable[[str], bool]]r   Optional[list[re.Pattern]]extra_forbidden_patternsfixture_main_shac                     y r~   r   )_ss    r   r$  zExecutorContext.<lambda>]  s    r   )defaultCallable[[float], None]r%  .Optional[Callable[[str, QueueDecision], None]]r  zOptional[Any]replacement_runnerzOptional[Callable]	triage_fnsmoke_envelope_fnOptional[Path]r  zOptional[list]triage_threadstriage_fix_commitstriage_pr_head_sharm   following_queueapply_triagert   ru   rv   c                 d    t        j                  t        j                        j	                         S r~   )r   r  r   r  r`   r   r   r   r$  zExecutorContext.<lambda>m  s    hll8<<>X>b>b>d r   zCallable[[], float]now_providerfloatgemini_wait_budget_secondsr   rZ   r{   )r   r   r   r   r   r   r   r   r  r   r(  r)  r%  r  r/  r0  r1  r  r3  r4  r5  rm   r6  r7  rt   ru   rv   r9  )GEMINI_REVIEW_WAIT_BUDGET_SECONDS_DEFAULTr;  r{   r   r   r   r"  r"  T  s   /FGFJG $J$)-M&-Hd59M29;?8?&*m*',_'EG$EDHMAH(,,$(I!(,0)0 $I~$%)NN))--(,,!$7OT7L$#I}#)--$(NM((-6d(eL%e(QQKr   r"  c                N   t        d| |j                  t        |j                        t        |            }t	        |      |_        t        |t              rt        |j                  d            nd}	t        ||	      |_        |j                  |_        d}
t        |t              r(|j                  d      xs |j                  d      xs d}
|
xs |j                  |_        |j                  |_        |j                  |_        t!        |j"                  |j$                  |j&                  	      \  }}|s7t(        |_        d
dj-                  |       |_        |j*                  |_        |S h d}|j2                  |vrft4        |_        d|j2                  |_        t6        |_        t6        |_        t<         dt6         |_        t?        t6        ||j@                         |S |jB                  }|du xs3 t        |tD              xr! |jG                         jI                         dk(  }|rYt4        |_        d|_        t6        |_        t6        |_        t<         dt6         |_        t?        t6        ||j@                         |S |jJ                  r|jJ                  }ntM        |j$                        }||_'        ||_(        |j                  d      xs djS                         }||_*        |dk(  r|jV                  rtY        |j                  dd      |jV                  |j$                  |      }|j                  d      r>t4        |_        d|_        tZ        |_        tZ        |_        t<         dtZ         |_        |S t]        ||j                        \  }}}|sft_        ||j                  |j`                        }|r`t4        |_        d|_        ||_1        td        |_        td        |_        t<         dtd         |_        t?        td        ||j@                         |S d|_3        ti        |dd      }|`	 |jk                  | |      }|jl                  rd|_7        |jp                  }tr        |_        g }|r|ju                  d|        |r|ju                  d|        |ju                  d| d        d!d"j-                  |       d#tv         |_        |j*                  |_        |S tx        }t4        |_        g }|r|ju                  d|        |r|ju                  d|        |ju                  d$|jz                          d%d"j-                  |       |_        ||_        ||_        t<         d| |_        t?        |||j@                         |S tr        |_        g }|r|ju                  d|        |r|ju                  d|        d!d"j-                  |       d#tv         |_        |j*                  |_        |S t_        ||j                  |j`                        }|rEt4        |_        d'|_        ||_1        td        |_        td        |_        t<         dtd         |_        |S |j                  d(d      }||_A        |t        k(  r7t        |_        d)|j                  d*       |_        |j*                  |_        |S |t        k(  r"t4        |_        d+|_        t         d,|_        |S ti        |d-d      } | 	 d.dlE}!ti        |d/d      xs g }"ti        |d0d      xs |}#ti        |d1d      xs g }$ti        |d2d      }% | | |"|#|$t        |j                        g |%|j                        }&t        |&      }|j                  d(      d3k(  rt        |      }d4|d(<   |&j                  |!j                  |&j                        nd|_G        t        |t              rt        |j                  d            nd}'t        ||'      |_        |j                  d(d      })t        |j                  d6g       xs g       |_J        |j                  r|j                  }*t        |j                  |*|j                  |j                  |j                         |j                  7      }+|+d8   |_N        |+d9   |_O        |+d:   |_P        t        |+d;         |_Q        |+d<   rbt        |_        d=|j                   d>|*xs d? d@|j                  dAdB|j                  dAdC|j                   
|_        |j*                  |_        |S |)dDk(  r>t4        |_        dE|_        t        |_        t        |_        t<         dt         |_        |S |)dFk(  r2t        |_        dG|j                   |_        |j*                  |_        |S |j                  t        v rHd|_V        |j
                  t        k(  rIt        |      },t        |,j                  dH      xs g       |_Y        t        |,j                  dI            }-nd}-t        |d.|r|nd|dt        |j                        d|j
                  xs t        |-J	      }.|.|_]        t        |.j                  dI            |_^        |.j                  dI      sgt4        |_        t         ddj-                  |.j                  dK      xs g        dL|j                   |_        d|_`        t         dt         |_        |S d|_`        n!|j                  t        k(  rd|_`        d|_V        |dMk7  r|dNk(  rYt4        |_        dO|_        tZ        |_        tZ        |_        t<         dtZ         |_        t?        tZ        ||j@                         |S |dk(  r"t4        |_        dP|_        t         dQ|_        |S t        |_        dR| |_        |j*                  |_        |S |j                  s<t4        |_        dS|j                   dT|j                   |_        t         dU|_        |S t        |_        dV|_        |j*                  |_        |S # t|        $ r!}t~        j                  d&|       Y d}~d}~ww xY w# t|        $ r!}(t~        j                  d5|(       Y d}(~(d}(~(ww xY w)WuP   10조건 게이트 — 결과 decision 반환 (실제 머지 X, dry-run 가능).UNKNOWN)rI   rL   rN   rV   rW   rU  FrT  Nsubmitted_atru   )r   z	pending: ,>   r  parallel_safelimited_parallelzINVALID_PARALLEL_POLICY: : Tr  z=cherry_pick_allowed=true is forbidden (DEPENDENCY_CYCLE risk)r  rJ   r   r  main)r   r   r   r\   r   MERGE_CONFLICT_DURING_BASE_SYNCFORBIDDEN_PATHevaluate_prr/  zextra=zmissing=zreplacement PR #z createdzdiff contamination: z; z; hook=zreplacement_failed=z)diff contamination + replacement failed: z*W2 replacement_runner.execute() failed: %sFORBIDDEN_PATH_INSIDE_EXPECTEDr  zCI failure: r  r#   z: CI_IN_PROGRESSr0  r   r3  r5  r4  r7  	completedrD  zW3 triage_fn() failed: %sr6  )rt   ru   rv   rc   rh  rc  rx   ry   rz   r|   re  z9WAITING_FOR_GEMINI_REVIEW: race=async_pending; pushed_at=z; submitted_at=r   z; gate_wait=z.1fz
s; budget=z s; premature_gate_fail_detected=rE  &GEMINI_REAL_BUG_OUTSIDE_EXPECTED_FILESrG  z,unresolved (auto_gemini_triage hook); count=r  r  )	r  r  rY   r\   r  r  r  rg   r  r  z; gemini_status=r  r  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)drG   rN   rm   rV   rw  rg   r   rk   rd   r   rX  rc   rt   ru   rv   r{   r   r   r   r   r   rI   rI  rK   ri   r   r    CRITICAL_DEPENDENCY_CYCLEr^   rj   FINAL_CRITICAL_PREFIXr  r  r   rH   r   r   r)  r   rO   rQ   r   r\   r   r   CRITICAL_BLOCK_OVERRIDEr   r   r(  rX   CRITICAL_FORBIDDEN_PATHro   getattrexecutesuccessrp   replacement_prr&   r   REPLACEMENT_PR_RUNNER_HOOK CRITICAL_DIFF_REPLACEMENT_FAILEDfailure_reasonr  r  r  rY   r"   r#   FINAL_BLOCKED_PREFIXdataclassesr   rq   r   r   r[   rr  r9  r;  rx   ry   rz   r|   r'   rK  r$   GEMINI_UNAVAILABLE_STATUSESre   rt  r~  rn   r  r   ru  rl   rf   rD   rh   r8   r%   r   )/rL   	task_specpr_head_sharW   merge_stateci_staterW  ctxrI   _gem_real_bug_gemini_submitted_from_statehead_okr   _VALID_PARALLEL_POLICIES_cherry_raw_cherry_boolmain_head_startr  syncr  r   r   r   r   replacement_resultrepl_prreason_parts_r
_crit_codereason_parts_f_w2_excreason_partsrY   
_triage_fn_dc_triage_threads_triage_pr_head_sha_triage_fix_commits_apply_triage_triage_report_gem_real_bug2_w3_exc
gem_status_submitted_for_race_racescanr  fbs/                                                  r   rG  rG  r  s    !!I445_-H ,O<H:D\SW:XD))*56^cM3L=YHH26 ,%^,  56 	%
 $@#Z3CZCZH !00H??H 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 "/2D9 V%+^^Iy%I"%--04H-0??G(FH%%'N&--ug.>?&--	.BC")),<WIX*NO(<TYY~=V<WW^_y^z&{HO.6.?.?H+#O "BJ(;H%%'N&--ug.>?&--	.BC")),?@R@a@a?b*cd(QRVR[R[\jRkQl&mHO-7H*3=H01F0Gr*.VH+,Z3CTCTU#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 k40J	A%%c+;TBHbO")#/CT"J"Yk")#/CT"J"Pb#C?M'##Y--.!!	N 2.AL)[8#L1)-X&SaSpSpS|cjj1N1N&O  CGH#CMl\`CaT,"2"2:">?glN%;LSa%bH" !!(B/J'*<+;+;L"+M+SQS'TH$ }}&::*mm 3--"00&&( # > >
 055R/S,167V1W.,12L,M)04U;Y5Z0[-34 9H ]]O?;N;XRX:Y Z%>>sC D88= >0080U0U/V	X O '/&7&7H#O///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OG  VKWUUVN  	ANN6@@	As9   8B1q *B,q  Dq: 	q7q22q7:	r$rr$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        |dd      }t3        |dd      }|||	 ||nt4        } ||| j                  xs | j                  xs dd|j                  |d      }t7        |j8                  d      r|j8                  j:                  nt=        |j8                        | _        |j?                         | _         |jB                  sYt        | _         d| _        t&        | _        t&        | _        t,         dt&         | _        t/        t&        | |j0                         | S nktK        |j                  |j                        }|jM                  dd      | _        |jM                  d      dk(  rt        | _         d| _        t&        | _        t&        | _        t,         dt&         | _        t/        t&        | |j0                         | S t3        |dd      }t3        |dd      }||| 	 ||nt4        } ||| j                  xs | j                  xs dd|j                  |d      }t7        |j8                  d      r|j8                  j:                  nt=        |j8                        | _        |j?                         | _         |jB                  sYt        | _         d| _        t&        | _        t&        | _        t,         dt&         | _        t/        t&        | |j0                         | S ntK        |j                  |j                        }|jM                  dd      | _        |jM                  d      dk(  rYt        | _         d| _        t&        | _        t&        | _        t,         dt&         | _        t/        t&        | |j0                         | S t3        |dg       xs g }|rtO        ||j                        }tQ        | jR                        |z   | _)        |D ]]  }|jM                  d      r	 t/        tT        | |j0                         |jM                  d!      sB	 t/        tV        | |j0                         _ tX        | _         d#| _        | j                   | _        | S # tD        $ r}tF        jI                  d|       tK        |j                  |j                        }|jM                  dd      | _        |jM                  d      dk(  r^t        | _         d| _        t&        | _        t&        | _        t,         dt&         | _        t/        t&        | |j0                         | cY d}~S Y d}~d}~ww xY w# tD        $ r}tF        jI                  d|       tK        |j                  |j                        }|jM                  dd      | _        |jM                  d      dk(  r^t        | _         d| _        t&        | _        t&        | _        t,         dt&         | _        t/        t&        | |j0                         | cY d}~S Y d}~qd}~ww xY w# tD        $ r!}tF        jI                  d |       Y d}~&d}~ww xY w# tD        $ r!}tF        jI                  d"|       Y d}~d}~ww xY w)$uU   §9 + §10 — head SHA 재확인 후 squash merge (dry_run=False 시 실제 실행).rJ   zPR head changed: start=z merge=Nzmain head changed: start=rC  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 smoker1  r  T)r  merge_commitr  r   rL   skip_stale_checkr`  zDPOST_MERGE_SMOKE_FAILURE (ff-only skipped: no pr_workdir) [envelope]z4W4 smoke_envelope_fn() failed (fallback to dict): %sr  r  z9POST_MERGE_SMOKE_FAILURE (ff-only skipped: no pr_workdir)z#POST_MERGE_SMOKE_FAILURE [envelope]r/   r6  r  z)W6 forbidden_path_present emit failed: %sr  zW6 blocked emit failed: %szmerged + smoke PASS)-rI   r   rR   r  rQ   r!   rK   ri   rP   rO   r   r    rE   rX  r  r   r   r   r]   r  r^   rj   rN  r  r  rQ  run_pm_smoke_v2r  r  r`  rH   r   rr   allow_continuationr  r  r  r   r   r  rm   rb   rP  rO  r   )rI   rL   r_  fetch_pr_head_at_mergefetch_main_head_at_merger  pr_head_nowmain_nowmerge_result	ff_resultff_oksmoke_status_str_smoke_envelope_fn_task_file_path_envelope_fnenvelope_w4_excsmoke_smoke_envelope_fn2_task_file_path2_envelope_fn2	envelope2_w4b_exc_following_queuefollowing_states_fstate_w6_exc_w6b_excs                               r   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*=tD!#{D9*o.IOj$5G5S1Yh'-!)!=!=!cA]A]!cac!::'%) BIZaAb(=(=hkltl{l{h|%*2*:*:*<'22(;H%&lHO-FH*3LH01F0GrJcId.eH+,-FRURcRcd#O 3, )):):CJJGE$)IIh$;H!yy"f,$7!"])B&/H,-B,C2F_E`*a'()BHcN_N_` &c+>E"3T:+/?/KQaQm$7J7V 3\k).!)!=!=!cA]A]!cac!::'%)	 CJ)JZJZ\cBd	(8(8(>(>jmnwn~n~j%*3*;*;*=' 33(;H%&KHO-FH*3LH01F0GrJcId.eH+,-FRURcRcd#O 4, )):):CJJGE$)IIh$;H!yy"f,$7!"<)B&/H,-B,C2F_E`*a'()BHcN_N_` $+30A2#F#L"01A3::N%)(*D*D%EHX%X"' 
	KG{{34Y,-DhPSPaPab {{9%K,-DhPSPaPab
	K +H+HO&//HOA  $UW^_,S->->

K(-		(B(?%99X&&0(;H%&aHO-FH*3LH01F0GrJcId.eH+,-FRURcRcd#O 1	$b  $UW_`,S->->

K(-		(B(?%99X&&0(;H%&@HO-FH*3LH01F0GrJcId.eH+,-FRURcRcd#O 1	$H ! YNN#NPWXXY
 ! KNN#?JJKsp   C=Z	 C=] `5a"		]B9]]]	`2(B9`-!`2-`25	a>aa"	b+bb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   rB  rJ   r  r  rD  r  )r  r  r  rW   r  )rL   r   r   r'  r   r   s         r   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                  t8        t9        
|j:                  (      nd t<        t<        nd t>        t>        nd |)      }tA        |j$                  ||jC                  d*d      |jC                  d+g       |jC                  d,d      |jC                  d-d.      d/|||0      }	tE        |	|j$                  |
fd1
fd2|j:                  3      }	tG        |	|jH                  |j6                  4       t        t        j                  |	jK                         d#d%5             |	jL                  tN        tP        hv ry6|	jL                  tR        k(  ry7y8)9Nz merge_queue_executor (task-2509))descriptionz--prTu	   PR 번호)typerequiredhelpz--task-filerJ   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)rI   rK   Fr  r   ztask file not found: )r#  r$  )r   r  )r   r   r   r  r/  r0  r1  r  r  rW   r  r  rD  )r  r  )rL   r[  r\  rW   r]  r^  rW  r_  c                <    t        |       j                  dd      S )Nr  rJ   )r  r   )rP  r   s    r   r$  zmain.<locals>.<lambda>  s    Av)>)B)B<QS)T r   c                     t               S r~   )r   )r   s   r   r$  zmain.<locals>.<lambda>  s    )@ r   )rI   rL   r_  r  r  r  )r  r  r      r   )*argparseArgumentParseradd_argumentrZ   rH   r   r:  
parse_argsr  r	   printr  r  r    r  r  r   r  r   r+  ci_max_pollsci_backoff_secondsrS  rV   r"  r   r  r  r   r  r   r  rG  r   r  r  rN   r   rI   r   r   r   )argvparserr   	task_pathr   pr_obscigemr_  rI   r   s             @r   rD  rD    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WjWv.fdllS  }A(4)$-<-H/d
C ''JJ|R0

#4b9 &

+=r B!::mV<
 H +''T!@H $,,?	$**X%%'eA
FG/1CDD33r   __main__)N<   )r   rU   r   rM   r   rZ   r   zsubprocess.CompletedProcess)r   rU   r   None)r   rH   r   rk   r~   )r   rU   r   r%  r   r&  r   ztuple[bool, list[str]])r   r%  r   rH   )
r   rH   r   rH   r   r%  r\   rH   r   rk   )r   rU   r   zset[str])rW   rU   rV   rU   r   z!tuple[bool, list[str], list[str]])rW   rU   r   rU   r   r'  r   rU   )rL   rZ   r   r%  r#  rZ   r$  r:  r%  r-  r   rk   )rL   rZ   r   r%  rV   rU   r   rk   )rW  rk   rU  rd   r   rH   )r`  rM   r   rw   )rt   rM   ru   rM   rv   rM   rc   rM   rh  r:  rc  r:  r   rk   )rW   rU   r   rH   )rW   rU   r  r	   r   rk   )r  rd   r  rZ   rY   rH   r\   rH   r  rd   r  rd   r  rd   rg   rH   r  rd   r   rk   )rL   rZ   r   r%  r   rk   )r  rH   r  rH   r   rd   )r   r   r   r%  r   rk   )r  ra   r   r%  r   ra   )F)rI   rG   rN   rM   r  rd   r   r2  )r  rH   rI   rG   r  r.  r   r  )r  r	   r   r   )r  rH   r  rH   r   rU   )r  rH   r  rH   r   rH   )rL   rZ   r[  r   r\  rH   rW   rU   r]  rk   r^  rk   rW  rk   r_  r"  r   rG   )NT)rI   rG   rL   rZ   r_  r"  r  zCallable[[int], str]r  zOptional[Callable[[], str]]r  rd   r   rG   )r  r   r   rZ   )r   
__future__r   r  r  loggingosr   r   systimerY  r   r   r   r   r   pathlibr	   typingr
   r   r   environr   r   r  r  r  	getLoggerr   r  utils.replacement_pr_runnerr   utils.auto_gemini_triager   r   r   utils.post_merge_smoke_runnerr   r  r   r   "utils.critical_escalation_reporterr   r  r   utils.automation_contractsr   r   r   r   _WIRING_AVAILABLEImportError_wiring_import_errr  __wiring_exports__r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r<  rP  rV  rK  rO  rM  CRITICAL_REPLACEMENT_FAILEDr  r  r   rU  rL  POST_MERGE_SMOKE_HOOKrJ  r8   r9   r:   r;   r<   r=   r>   	frozensetGEMINI_STATUS_VALUESrZ  ru  RISK_LEVEL_MEDIUMrt  compilerB   r   r}  FINAL_AUTO_MERGE_ALLOWEDrX  rN  rD   rE   rG   r   CompletedProcessr%  r   r   r   r   r   r   r   r   r   r   sleepr+  rS  rX  rb  rr  rw  r~  r  r  r  r  r  r  r  DOTALLr  r  r  r  r"  rG  r  r  rD  exitr   r   r   <module>r     sr  $L #    	 	  
  0 0 '  * * 02GHI	!H,
 #88	22 			8	$"?XX 
  *  & * ) 3 + - % !3 / !A 7  :  -2 ) 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 " / / /d . . . c:6667
/&*b 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$ %) "Kll 'l "	l
 !l l l 
l` %FFF 
FDLL L 	L
 L L  L  L L L 
LD"8
& 
$>>> >J   	4 EI$c
$c$c B$c 
	$cP "rzz"9299E B0   :[[[ [ 	[
 [ [ [ 
[ [F =AAAA 
A 1	A
 :A A AJ&IX zCHHTV G5  
LL68JKI!LOK !s   0P Q
.QQ
