
     j                       d Z ddlmZ ddlZddlZddlZddlmZ ddlZ ee	      j                         j                  j                  j                  Z ee      ej                  v r!ej                  j                   ee             ej                  j!                  d ee             ddlmZmZmZmZmZmZmZmZmZmZmZmZmZmZm Z m!Z!m"Z" ddl#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z* ddl+m,Z,m-Z-m.Z.m/Z/ ddl0m1Z1m2Z2 dd	l3m4Z4m5Z5 dd
l6m7Z7 d*d+dZ8d,d-dZ9ddgZ:ddddZ;ddgg dZ<dg ddZ=d.dZ>	 	 	 d/	 	 	 d0dZ?	 	 d1dZ@	 	 d2dZAd3dZBd3dZCd3dZDd3dZEd3dZFd3d ZGd3d!ZHd3d"ZId3d#ZJd3d$ZKd3d%ZLd3d&ZMd3d'ZNd3d(ZOd3d)ZPy)4u  task-2514 end-to-end 회귀 테스트 — 5 모듈 오케스트레이션 14 케이스.

QA 담당: 모리건(Morrigan)
대상: 5 모듈 wiring (merge_queue_executor + replacement_pr_runner +
        auto_gemini_triage + post_merge_smoke_runner + critical_escalation_reporter)

케이스 목록:
  TC-N1  clean PR + 자동 머지 10조건 충족 → AUTO_MERGE_SUCCESS + smoke PASS + 후행 stale 재검증 OK
  TC-N2  Gemini outdated thread × 5 → auto_gemini_triage가 모두 resolve → review_gate_passed → squash merge → smoke PASS
  TC-N3  Gemini quota → fallback_review_passed → review_gate_passed → squash merge → smoke PASS
  TC-N4  clean replacement (오염 PR) → replacement_pr_runner 새 PR 생성 + 원 PR 보존 → 새 PR 자동 머지
  TC-C1  Critical #1 forbidden path → critical_escalation_reporter packet 생성
  TC-C2  Critical #2 replacement_pr_auto_creation_failed → packet 생성
  TC-C3  Critical #3 gemini_real_bug_requires_scope_expansion → packet 생성
  TC-C4  Critical #4 block_override_required → packet 생성
  TC-C5  Critical #5 dependency_cycle_or_serial_only_collision → packet 생성
  TC-C6  Critical #6 replacement_pr_failed → packet 생성
  TC-C7  Critical #7 post_merge_smoke_failed → packet 생성
  TC-A1  false-positive Gemini suppression → auto_gemini_triage dismiss + review_gate_passed → 회장 보고 0건
  TC-A2  style-only Gemini suppression → 동일
  TC-A3  dependency satisfied 자동 판정 → merge_topology_gate ALLOW → 자동 진행

wiring 인터페이스 상태 (2026-05-09 기준):
  - ExecutorContext 신규 필드(replacement_runner, triage_fn, smoke_envelope_fn 등) 미구현 (루 WIP).
  - 현재 테스트는 공개 인터페이스(evaluate_pr / verify_head_lock_then_merge / process_event / triage_pr)
    를 직접 호출하여 wiring 완성 후와 동일한 흐름을 검증한다.
  - ExecutorContext 신규 필드가 추가될 경우 _make_ctx() 헬퍼만 업데이트하면 14 케이스 전부 재사용 가능.
    )annotationsN)Path)AUTO_MERGE_ALLOWEDAUTO_MERGE_SUCCESSBLOCKED_WITH_REASONCI_FAILURE_BLOCKCRITICAL_FORBIDDEN_PATH CRITICAL_DIFF_REPLACEMENT_FAILEDCRITICAL_GEMINI_SCOPE_EXPANSIONCRITICAL_BLOCK_OVERRIDECRITICAL_DEPENDENCY_CYCLECRITICAL_REPLACEMENT_FAILEDCRITICAL_POST_MERGE_SMOKEDIFF_CONTAMINATION_REPLACEMENTExecutorContextQueueDecisionTaskSpecevaluate_prverify_head_lock_then_merge)CriticalEscalationTypeGeminiStatusReviewGateStatusGeminiTriageResultReplacementResultEscalationPacketSmokeResult)TriageVerdictThreadTriageOutcomeTriageReport	triage_pr)PostMergeSmokeRunSmokeStatus)process_eventLEGACY_CRITICAL_MAP)ReplacementPRRunnerc                4    t        j                  g | ||      S )u   CompletedProcess 생성 헬퍼.)args
returncodestdoutstderr)
subprocessCompletedProcess)r(   r)   r*   s      G/home/jay/workspace/tests/regression/test_orchestration_runtime_2514.pycpr.   `   s    &&B:f]cdd    c                2      i  g d fd	}|_         |S )u   args 패턴별 CompletedProcess 반환 fake runner.

    key = tuple of arg tokens to match (all must be present),
    value = CompletedProcess to return.
    Unmatched → returncode=0, empty stdout/stderr.
    c                     j                  t               ||d       j                         D ]  \  }}t         fd|D              s|c S  t	               S )N)r'   cwdtimeoutc              3  &   K   | ]  }|v  
 y wN ).0pr'   s     r-   	<genexpr>z.make_runner.<locals>.runner.<locals>.<genexpr>s   s     .19.s   )appendlistitemsallr.   )r'   r2   r3   pattern	completedcallsreturns_by_argss   `    r-   runnerzmake_runner.<locals>.runnerp   sT    d4jIJ"1"7"7"9 	!GY.g..  	! tr/   N<   )r@   )rA   rB   r@   s   ` @r-   make_runnerrE   e   s(     E FLMr/   utils/merge_queue_executor.py3tests/regression/test_orchestration_runtime_2514.pyCLEANzsha-clean-001mainmergeStateStatus
headRefOidbaseRefNameSUCCESS)statusdetailsrawokrO   
unresolvedhookc                 |    t        dt        t              dg ddddd 	      }|j                  |        t	        di |S )	N	task-2514orchestration_runtimeserial_only   TF)	task_idexpected_files	risk_area
dependencyparallel_policymerge_queue_positionstale_recheck_requiredcherry_pick_allowedsmoke_commandr6   )dictr;   EXPECTED_FILESupdater   )	overridesbases     r-   make_task_specri      sH    N+)%#!
D 	KK	dr/   c                8    | 
t               } t        | |d|      S )uF   기본 ExecutorContext 생성 헬퍼 (현재 wiring 미완성 대응).T)rB   rc   no_auditfixture_main_sha)rE   r   )rB   rc   rl   s      r-   	_make_ctxrm      s)     ~#)	 r/   c                B   t        |      D 	cg c])  \  }}	t        d| t        j                  dddddi      + }
}}	t	        t
        j                  ddddd	
      }t        t
        j                  dddddg       }t        | |
dt        |
      dd||      S c c}	}w )uR   OUTDATED만 있는 케이스 → 모두 auto_resolved → review_gate_passed=True.th-Tz[AUTO-OUTDATED] ...Noutdated)	thread_idverdictauto_resolveddismiss_commentescalation_typeevidencer   Fzall auto_resolved)gemini_statusunresolved_threadsfallback_review_usedfallback_review_passedreview_gate_passedreason)rO   false_positive_countstyle_only_countreal_bug_small_countscope_expansion_countunresolved_countactions_taken)	pr_numberthreadsr   auto_resolved_countblocking_thread_countmerge_readinessreview_gate_statustriage_summary)
	enumerater   r   OUTDATEDr   r   GEMINI_COMPLETEDr   r   len)r   r   pr_head_shafix_commitsr\   forbidden_pathsapplyr[   i_outcomesreview_gatesummarys                r-   fake_triage_fnr      s    ( g&
 Aq 	A3i!**1  $'	

H 
 #"33"$"K !,,G M&	 	9
s   .Bc                h    t        |dt        j                  t        dddddd      ddgddd	|

      S )zsmoke PASS envelope.rW   pytestTr    N)commandpassed	exit_codestdout_tailstderr_tailfailure_reasoni  F)
merge_commitr[   rO   smoke_resultduration_msrc   allow_continuation
escalationstaledry_run)r!   r"   PASSr   )	task_filer   r   rB   r   skip_stale_checks         r-   fake_smoke_envelope_passr      sP     ! 
 j# r/   c            
        ddl g d} t        |       }dfd	}t        |dd|       }d	d
ig|_        t	        d|dt        t              t        t        t        |      }|j                  t        k(  sJ d|j                          t        |d|d d      }|j                  t        k(  s!J d|j                   d|j                          |j                  dk(  sJ d|j                          t!        d |j"                  D              sJ d|j"                          t%        d |j"                  D              }|d   du s
J d|        y)u  TC-N1: clean PR + 자동 머지 10조건 충족 → AUTO_MERGE_SUCCESS + smoke PASS + 후행 stale 재검증 OK.

    시나리오:
      - effective_files == expected_files (오염 없음)
      - CI 통과 / Gemini OK / mergeStateStatus=CLEAN
      - squash merge → returncode=0
      - smoke PASS
      - following_queue PR#201 → CLEAN 상태 → needs_recheck=False
    검증:
      - decision.decision == AUTO_MERGE_SUCCESS
      - smoke_status == "PASS"
      - fixture_pr_replay에 PR#201 상태 기록 (needs_recheck=False)
    r   Nr   z2tests/regression/test_merge_queue_executor_2509.py-qrc   c                    t        |       }d|v rd|v rt        dd      S d|v rt        dd      S d|v r&d	|v r"d
ddd}t        dj                  |            S t               S )Nmerge--squashr   	PR mergedr(   r)   r   z5 passed, 0 failed201--jsonrH   zsha-201-cleanrI   rJ   )r;   r.   dumps)r'   r2   r3   	args_listpayloadjsons        r-   fake_runnerzNtest_tc_n1_clean_pr_auto_merge_success_with_stale_recheck.<locals>.fake_runner  s|    J	iJ)$;;77y +?@@I(i"7$+-%G
 4::g+>??tr/   Tzmain-sha-n1rB   rk   rl   rc   r      e   	sha-pr-n1r   	task_specr   effective_filesmerge_stateci_stategemini_statectxz0evaluate_pr must return AUTO_MERGE_ALLOWED, got c                     y)Nr   r6   ns    r-   <lambda>zKtest_tc_n1_clean_pr_auto_merge_success_with_stale_recheck.<locals>.<lambda>D      r/   Fdecisionr   r   fetch_pr_head_at_merger   z(TC-N1: expected AUTO_MERGE_SUCCESS, got 
 / reason=r   z'TC-N1: expected smoke_status=PASS, got c              3  D   K   | ]  }|j                  d       dk(    ywr   r   Ngetr7   ss     r-   r9   zLtest_tc_n1_clean_pr_auto_merge_success_with_stale_recheck.<locals>.<genexpr>O  s#      &'kc!s    z>TC-N1: PR#201 stale recheck must appear in fixture_pr_replay: c              3  J   K   | ]  }|j                  d       dk(  s|  ywr   r   r   s     r-   r9   zLtest_tc_n1_clean_pr_auto_merge_success_with_stale_recheck.<locals>.<genexpr>R  s!     XQaeeK>PTW>WqXs   ##needs_rechecku5   TC-N1: PR#201 CLEAN → needs_recheck must be False: rC   )r   ri   r   following_queuer   r;   re   CLEAN_MERGE_STATECI_OK	GEMINI_OKr   r   r   r   r|   smoke_statusanyfixture_pr_replaynext)	smoke_cmdspecr   r   r   resultpr201_stater   s          @r-   9test_tc_n1_clean_pr_auto_merge_success_with_stale_recheckr     s    VI	2D$ &	C (-.C^,%	H  22 
:8;L;L:MN2 )4F ??00 
26??2C:fmm_]0 &( 
1&2E2E1FG(  +1+C+C  c	GH`H`Gabc  X&":":XXK'50 
?}M0r/   c            
     l   ddl m} m} t        d      D cg c]  }d| ddg d }} | d|d	g t	        t
              g dd
      }|j                  dk(  sJ d|j                          |j                  dk(  sJ d|j                          |j                  j                  du sJ d       |j                  du sJ d        ||      }|d   dk(  sJ d|d           g d}t        |      }d"d}t        |dd|      }	dg dd}
t        d|d	t	        t
              t        t        |
|	      }|j                   t"        k(  sJ d|j                           t%        |d|	d d      }|j                   t&        k(  sJ d|j                           |j(                  d k(  sJ d!|j(                          yc c}w )#u  TC-N2: Gemini outdated thread × 5 → auto_gemini_triage가 모두 resolve → review_gate_passed → squash merge → smoke PASS.

    시나리오:
      - 5개 outdated thread → triage_pr() → 모두 OUTDATED + auto_resolved=True
      - review_gate_status.review_gate_passed=True
      - to_legacy_gemini_state → status='completed'
      - evaluate_pr (Gemini COMPLETED) → AUTO_MERGE_ALLOWED
      - squash merge + smoke → AUTO_MERGE_SUCCESS
    r   )r    to_legacy_gemini_state   ro   TFid
isOutdated
isResolvedcommentsf   	sha-pr-n2rW   r   r   r   r   r\   r   r   r[   z5TC-N2: 5 outdated threads must all auto_resolve, got zTC-N2: blocking must be 0, got z&TC-N2: review_gate_passed must be Truez#TC-N2: merge_readiness must be TruerO   r?   z.TC-N2: legacy status must be 'completed', got r   r   Nc                x    t        |       }d|v rd|v rt        dd      S d|v rt        dd      S t               S )Nr   r   r   zPR squash mergedr   r   z
all passedr;   r.   r'   r2   r3   r   s       r-   r   zOtest_tc_n2_gemini_outdated_threads_auto_resolve_then_merge.<locals>.fake_runner  sD    J	iJ)$;+=>>y <88tr/   zmain-sha-n2r   rR   rS   r   z7TC-N2: evaluate_pr must return AUTO_MERGE_ALLOWED, got c                     y)Nr   r6   r   s    r-   r   zLtest_tc_n2_gemini_outdated_threads_auto_resolve_then_merge.<locals>.<lambda>  r   r/   r   z(TC-N2: expected AUTO_MERGE_SUCCESS, got r   z TC-N2: expected smoke PASS, got rC   )utils.auto_gemini_triager    r   ranger;   re   r   r   r   r{   r   ri   r   r   r   r   r   r   r   r   r   )r    r   r   outdated_threadsreportlegacy_stater   r   r   r   gemini_completedr   r   s                r-   :test_tc_n2_gemini_outdated_threads_auto_resolve_then_merger   X  sJ    K q QCyErR   N+	F %%* 
?@Z@Z?[\* ''1, 
)&*F*F)GH, $$774? 
0? !!T) 
-)
 *&1L![0 
8h9O8PQ0 WI	2D &	C #'b$G^,%%	H  22 
A(BSBSATU2 )4F ??00 
26??2CD0 &( 
*6+>+>*?@(_s   F1c            
     J   g d} t        |       }dd}t        |dd|       }dg dd	d
igd}t        d|dt        t              t
        t        ||      }|j                  t        k(  s!J d|j                   d|j                          |j                  du sJ d       |j                  du sJ d       |j                  du sJ d       t        |d|d d      }|j                  t        k(  sJ d|j                          |j                  dk(  sJ d|j                          y)u(  TC-N3: Gemini quota → fallback_review_passed → review_gate_passed → squash merge → smoke PASS.

    시나리오:
      - gemini_state.status='unavailable_quota'
      - fallback review 8조건 PASS → review_gate_passed=True
      - squash merge + smoke PASS → AUTO_MERGE_SUCCESS
    r   r   Nc                x    t        |       }d|v rd|v rt        dd      S d|v rt        dd      S t               S )Nr   r   r   r   r   r   r   r   r   s       r-   r   zGtest_tc_n3_gemini_quota_fallback_review_then_merge.<locals>.fake_runner  sC    J	iJ)$;;77y 844tr/   Tzmain-sha-n3r   unavailable_quotamessagezquota exceeded)rO   rT   rU   errorsg   	sha-pr-n3r   u8   TC-N3: fallback should pass → AUTO_MERGE_ALLOWED, got r   z(TC-N3: fallback_review_used must be Truez*TC-N3: fallback_review_passed must be Truez&TC-N3: review_gate_passed must be Truec                     y)Nr  r6   r   s    r-   r   zDtest_tc_n3_gemini_quota_fallback_review_then_merge.<locals>.<lambda>  r   r/   Fr   z(TC-N3: expected AUTO_MERGE_SUCCESS, got r   z TC-N3: expected smoke PASS, got rC   )ri   r   r   r;   re   r   r   r   r   r|   ry   rz   r{   r   r   r   )r   r   r   r   gemini_quotar   r   s          r-   2test_tc_n3_gemini_quota_fallback_review_then_merger    s    WI	2D &	C 2T_hjz^{]|}L^,%!	H  22 
B8CTCTBUU_`h`o`o_pq2 ((D0 
20 **d2 
42 &&$. 
0. )4F ??00 
26??2CD0 &( 
*6+>+>*?@(r/   c            
     :   t               } t               }t        d| dt        t              dgz   t
        t        t        |      }|j                  t        k(  sJ d|j                          t        t               d      }|j                  d|       }|j                  du sJ d	|j                          |j                  du sJ d
       |j                   dk(  sJ d|j                           ddg}t        |      }dd}t#        |dd|      }t        d|dt        t              t
        t        t        |      }	|	j                  t$        k(  sJ d|	j                          t'        |	d|d d      }
|
j                  t(        k(  sJ d|
j                          y)u  TC-N4: clean replacement (오염 PR) → replacement_pr_runner가 새 PR 생성 + 원 PR 보존 → 새 PR 자동 머지.

    시나리오:
      - 원 PR effective_files에 rogue 파일 → DIFF_CONTAMINATION_REPLACEMENT
      - ReplacementPRRunner.execute() dry_run=True → success=True, original_pr_preserved=True
      - replacement PR 존재 → evaluate_pr (clean files) → AUTO_MERGE_ALLOWED
    h   zsha-pr-n4-contaminatedzutils/rogue_extra_file.pyr   zDTC-N4: contaminated PR must get DIFF_CONTAMINATION_REPLACEMENT, got TrB   r   r   z9TC-N4: ReplacementPRRunner.execute dry_run must succeed: z$TC-N4: original PR must be preservedz"TC-N4: source_pr must be 104, got r   r   r   Nc                x    t        |       }d|v rd|v rt        dd      S d|v rt        dd      S t               S )Nr   r   r   zreplacement PR mergedr   r   r   r   r   s       r-   fake_runner_cleanzQtest_tc_n4_contaminated_pr_replacement_then_auto_merge.<locals>.fake_runner_clean'  sD    J	iJ)$;+BCCy 844tr/   zmain-sha-n4r      sha-pr-n4-cleanz4TC-N4: new clean PR must be AUTO_MERGE_ALLOWED, got c                     y)Nr  r6   r   s    r-   r   zHtest_tc_n4_contaminated_pr_replacement_then_auto_merge.<locals>.<lambda>H  r   r/   Fr   z3TC-N4: replacement PR must AUTO_MERGE_SUCCESS, got rC   )ri   rm   r   r;   re   r   r   r   r   r   r%   rE   executesuccessr   original_pr_preserved	source_prr   r   r   r   )r   r   contaminated_decisionreplacement_runnerreplacement_resultr   
spec_cleanr
  	ctx_cleannew_pr_decisionfinal_results              r-   6test_tc_n4_contaminated_pr_replacement_then_auto_merger    s    D +C',^,0K/LL%	 !))-KK 
NOdOmOmNnoK
 -} ,33C43H%%- 
CDVDeDeCfg- 33t; 
.; ''3. 
,-?-I-I,JK.
 4 Ii8J   &	I "%^,%	O ##'99 
>?W?W>XY9 / :L   $66 
=l>S>S=TU6r/   c            
        t               } t               }t        t              dgz   }t	        d| d|t
        t        t        |      }|j                  t        k(  sJ d|j                          |j                  t        k(  sJ d|j                          d|j                  v sJ d|j                          t        ddt        d	d
|j                  iddd      }|d   dk(  sJ d|d           |d   t        j                  j                   k(  sJ d|d           |d   J d       t#        |d   t$              sJ dt'        |d                 y)us  TC-C1: Critical #1 forbidden path → evaluate_pr BLOCKED + process_event packet FORBIDDEN_PATH_INTRUSION.

    시나리오:
      - effective_files에 .github/workflows/foo.yml 포함
      - evaluate_pr → BLOCKED_WITH_REASON + critical_code=CRITICAL_FORBIDDEN_PATH
      - process_event로 LEGACY_CRITICAL_MAP 경유 → escalation_type=FORBIDDEN_PATH_INTRUSION
    z.github/workflows/foo.ymli   z	sha-pr-c1r   z)TC-C1: expected BLOCKED_WITH_REASON, got z;TC-C1: expected critical_code=CRITICAL_FORBIDDEN_PATH, got z2TC-C1: forbidden_paths must contain the invasion: rW   r   r   r[   r   
event_typesourcerv   Trk   r   classificationcriticalz.TC-C1: classification must be 'critical', got ru   z=TC-C1: escalation_type must be FORBIDDEN_PATH_INTRUSION, got packetNzTC-C1: packet must not be Nonez,TC-C1: packet must be EscalationPacket, got )ri   rm   r;   re   r   r   r   r   r   r   critical_coder	   r   r#   r   FORBIDDEN_PATH_INTRUSIONvalue
isinstancer   type)r   r   files_with_forbiddenr   event_results        r-   "test_tc_c1_critical_forbidden_pathr*  T  s    D
+C/3N2OO,%	H  33 
3H4E4E3FG3 !!%<< 
EhF\F\E]^< '(*B*BB 
<X=U=U<VWB
 !"1#*H,D,DE	
 
L ()Z7 
8FV9W8XY7 )*.D.].].c.cc 
GUfHgGhic !-O/OO-l8,.>? 
6tL<R7S6TU?r/   c                    t               } t        dt        dd      i      }t        |d      }|j	                  d|       }|j
                  du sJ d	       |j                  d
u sJ d       |j                  J d       t        ddt        dd|j                  idd
d
      }|d   dk(  sJ d|d           |d   t        j                  j                  k(  sJ d|d           |d   J d       y)um  TC-C2: Critical #2 replacement_pr_auto_creation_failed → packet 생성.

    시나리오:
      - ReplacementPRRunner non-dry_run + fetch_pr_metadata 실패 (gh CLI 차단)
      - ReplacementResult.success=False + failure_reason=REPLACEMENT_PR_AUTO_CREATION_FAILED_FOR_CONTAMINATED_DIFF
      - process_event로 LEGACY_CRITICAL_MAP 경유 → packet 생성
    )ghprview   zAPI rate limit exceededr(   r*   Fr  j   r  z)TC-C2: expected failure, got success=TrueTz4TC-C2: original PR must be preserved even on failureNz!TC-C2: failure_reason must be setrW   replacement_pr_runnerr   r  r  r   r!  z.TC-C2: classification must be 'critical', got ru   zTC-C2: wrong escalation_type: r"  zTC-C2: packet must not be None)ri   rE   r.   r%   r  r  r  r   r#   r
   r   9REPLACEMENT_PR_AUTO_CREATION_FAILED_FOR_CONTAMINATED_DIFFr%  )r   failing_runnerr  r   r)  s        r-   7test_tc_c2_critical_replacement_pr_auto_creation_failedr5    sk    D !bA6OP" N -  ''t'<F>>U" 
3" ''4/ 
>/   ,Q.QQ, !":-)6+@+@A	
 
L ()Z7 
8FV9W8XY7 )*.D.~.~  /E  /E  E 
(6G)H(IJ  E !-O/OO-r/   c            
        t               } t               }ddddgdddgdt        d}t        d| dt	        t
              t        t        ||	      }|j                  t        k(  sJ d
|j                          |j                  t        k(  sJ d|j                          dddddigdg}t        d|dg t	        t
              g dd      }|j                  dk\  sJ d       t        ddt        dddiddd      }|d   dk(  sJ d|d           |d   t        j                  j                   k(  sJ d|d           |d   J d!       y )"u   TC-C3: Critical #3 gemini_real_bug_requires_scope_expansion → packet 생성.

    시나리오:
      - gemini_state.status='critical_scope_expansion' → evaluate_pr BLOCKED
      - process_event → GEMINI_REAL_BUG_REQUIRES_SCOPE_EXPANSION packet
    critical_scope_expansionzsome/external/file.pyzreal bug outside expected)pathbodycritical_escalation_reporter)rO   rT   outsiderU   r#  k   z	sha-pr-c3r   z)TC-C3: expected BLOCKED_WITH_REASON, got z5TC-C3: expected CRITICAL_GEMINI_SCOPE_EXPANSION, got zth-scope-01Fr9  z3This function in other/external_module.py has a bugr   rW   r   r   z+TC-C3: triage report must have valid countsr   rw   r  Tr  r   r!  z.TC-C3: classification must be 'critical', got ru   zTC-C3: wrong escalation_type: r"  NzTC-C3: packet must not be None)ri   rm   r   r   r;   re   r   r   r   r   r#  r    r   r#   r   (GEMINI_REAL_BUG_REQUIRES_SCOPE_EXPANSIONr%  )r   r   gemini_scope_expansionr   scope_threadsr   r)  s          r-   3test_tc_c3_critical_gemini_real_bug_scope_expansionr@    s    D
+C - 7A\]^4>YZ[.8 ^,%+	H  33 
3H4E4E3FG3 !!%DD 
?@V@V?WXD   "WXY		
M N+	F ""a'V)VV' !"9#(*DE	
 
L ()Z7 
8FV9W8XY7 )*.D.m.m.s.ss 
(6G)H(IJs !-O/OO-r/   c            
        t               } t               }dddd}t        d| dt        t              |t
        t        |      }|j                  t        k(  sJ d|j                          |j                  t        k(  sJ d|j                          t        d	dt        d
ddiddd      }|d   dk(  sJ d|d           |d   t        j                  j                  k(  sJ d|d           |d   J d       y)u  TC-C4: Critical #4 block_override_required → packet 생성.

    시나리오:
      - mergeStateStatus=BLOCKED → evaluate_pr BLOCKED + critical_code=CRITICAL_BLOCK_OVERRIDE
      - process_event → BLOCK_OVERRIDE_REQUIRED_OR_REASON_INSUFFICIENT packet
    BLOCKEDz	sha-pr-c4rI   rJ   l   r   z)TC-C4: expected BLOCKED_WITH_REASON, got z-TC-C4: expected CRITICAL_BLOCK_OVERRIDE, got rW   r   merge_state_statusr  Tr  r   r!  z.TC-C4: classification must be 'critical', got ru   zTC-C4: wrong escalation_type: r"  NzTC-C4: packet must not be None)ri   rm   r   r;   re   r   r   r   r   r#  r   r#   r   .BLOCK_OVERRIDE_REQUIRED_OR_REASON_INSUFFICIENTr%  )r   r   blocked_merge_stater   r)  s        r-   +test_tc_c4_critical_block_override_requiredrG    s\    D
+C &! ^,'	H  33 
3H4E4E3FG3 !!%<< 
78N8N7OP< !"1#-y9	
 
L ()Z7 
8FV9W8XY7 )*.D.s.s.y.yy 
(6G)H(IJy !-O/OO-r/   c            
        t        d      } t               }t        d| dt        t              t
        t        t        |      }|j                  t        k(  sJ d|j                          |j                  t        k(  sJ d|j                          t        ddt        d	d
diddd      }|d   dk(  sJ d|d           |d   t        j                  j                  k(  sJ d|d           |d   J d       y)u  TC-C5: Critical #5 dependency_cycle_or_serial_only_collision → packet 생성.

    시나리오:
      - parallel_policy='INVALID_POLICY' → evaluate_pr BLOCKED + CRITICAL_DEPENDENCY_CYCLE
      - process_event → DEPENDENCY_CYCLE_OR_SERIAL_ONLY_COLLISION packet
    INVALID_POLICY_FOR_TEST)r_   m   z	sha-pr-c5r   z)TC-C5: expected BLOCKED_WITH_REASON, got z/TC-C5: expected CRITICAL_DEPENDENCY_CYCLE, got rW   r   r_   r  Tr  r   r!  z.TC-C5: classification must be 'critical', got ru   zTC-C5: wrong escalation_type: r"  NzTC-C5: packet must not be None)ri   rm   r   r;   re   r   r   r   r   r   r#  r   r#   r   )DEPENDENCY_CYCLE_OR_SERIAL_ONLY_COLLISIONr%  )r   r   r   r)  s       r-   $test_tc_c5_critical_dependency_cyclerL  C  sK    *CDD
+C^,%	H  33 
3H4E4E3FG3 !!%>> 
9(:P:P9QR> !"3#*,EF	
 
L ()Z7 
8FV9W8XY7 )*.D.n.n.t.tt 
(6G)H(IJt !-O/OO-r/   c                    t               } dd}t        |d      }|j                  d|       }|j                  du sJ d       |j                  du sJ d	       t        d
dt        dd|j                  iddd      }|d   dk(  sJ d|d           |d   t        j                  j                  k(  sJ d|d           |d   J d       y)u5  TC-C6: Critical #6 replacement_pr_failed → packet 생성.

    시나리오:
      - ReplacementPRRunner non-dry_run, fetch 성공, 오염 감지, branch 생성 실패
      - ReplacementResult.success=False, failure_reason contains REPLACEMENT_PR
      - process_event → REPLACEMENT_PR_FAILED packet
    Nc                   t        |       }d|v rt        d      S d|v r9d|v r5d|v r1dd l}ddd	d
did
did
digdd}t        d|j                  |            S d|v rd|v rt        dd      S d|v rd|v rt        dd      S t               S )Nfetchr   )r(   r-  r.  r   ztask/task-2514-c6z
sha-c6-001rI   r8  rF   rG   zutils/rogue_c6.pyz[task-2514] test C6)headRefNamerL   rM   filestitler   rO   z--porcelainr   checkoutz-br/  zfatal: cannot create branchr0  )r;   r.   r   r   )r'   r2   r3   r   r   r   s         r-   always_fail_runnerzEtest_tc_c6_critical_replacement_pr_failed.<locals>.always_fail_runner|  s    J	i##99!4Y9N2*%<=RS01
 /
G 4::g+>??y ]i%?2.."ty'8+HIItr/   Fr  n   r  z)TC-C6: expected failure, got success=TrueTz+TC-C6: original PR must always be preservedrW   r2  r   r  r  r   r!  z.TC-C6: classification must be 'critical', got ru   zTC-C6: wrong escalation_type: r"  zTC-C6: packet must not be NonerC   )ri   r%   r  r  r  r#   r   r   r   REPLACEMENT_PR_FAILEDr%  )r   rT  r  r   r)  s        r-   )test_tc_c6_critical_replacement_pr_failedrW  r  s,    D8 -!  ''t'<F>>U" 
3" ''4/ 
5/ !"5-)6+@+@A	
 
L ()Z7 
8FV9W8XY7 )*.D.Z.Z.`.`` 
(6G)H(IJ` !-O/OO-r/   c            
        g d} t        |       }dd}t        |dd|       }t        d|d	t        t              t
        t        t        |
      }|j                  t        k(  sJ d|j                          t        |d|d d      }|j                  t        k(  sJ d|j                          |j                  t        k(  sJ d|j                          |j                  dk(  sJ d|j                          t        ddt        ddt        dddd      }|d   dk(  sJ d|d           |d   t         j"                  j$                  k(  sJ d|d           |d   J d       y) u   TC-C7: Critical #7 post_merge_smoke_failed → packet 생성.

    시나리오:
      - squash merge 성공 → smoke FAIL (returncode=1)
      - verify_head_lock_then_merge → BLOCKED_WITH_REASON + CRITICAL_POST_MERGE_SMOKE
      - process_event → POST_MERGE_SMOKE_FAILED packet
    )r   ztests/regressionr   r   Nc                x    t        |       }d|v rd|v rt        dd      S d|v rt        dd	      S t               S )
Nr   r   r   r   r   r   r/  zSMOKE FAILED: 3 tests failedr0  r   r   s       r-   fake_runner_smoke_failzKtest_tc_c7_critical_post_merge_smoke_failed.<locals>.fake_runner_smoke_fail  sD    J	iJ)$;;77y +IJJtr/   Tzmain-sha-c7r   o   	sha-pr-c7r   z7TC-C7: evaluate_pr must return AUTO_MERGE_ALLOWED, got c                     y)Nr\  r6   r   s    r-   r   z=test_tc_c7_critical_post_merge_smoke_failed.<locals>.<lambda>  r   r/   Fr   z6TC-C7: expected BLOCKED_WITH_REASON (smoke fail), got z/TC-C7: expected CRITICAL_POST_MERGE_SMOKE, got FAILz'TC-C7: expected smoke_status=FAIL, got rW   r   )r   r#  r  r  r   r!  z.TC-C7: classification must be 'critical', got ru   zTC-C7: wrong escalation_type: r"  zTC-C7: packet must not be NonerC   )ri   r   r   r;   re   r   r   r   r   r   r   r   r#  r   r   r#   r   POST_MERGE_SMOKE_FAILEDr%  )r   r   rZ  r   r   r   r)  s          r-   +test_tc_c7_critical_post_merge_smoke_failedr`    s    5I	2D %&	C ^,%	H  22 
A(BSBSATU2 )4F ??11 
@@QR1 #<< 
9&:N:N9OP< &( 
1&2E2E1FG( !"33)/B[\	
 
L ()Z7 
8FV9W8XY7 )*.D.\.\.b.bb 
(6G)H(IJb !-O/OO-r/   c            
        dddddigddddddigdg} t        d| d	g t        t              g dd
      }|j                  dk(  sJ d|j                          |j                  dk(  sJ d|j                          |j
                  j                  du sJ d       |j                  D ]`  }|j                  t        j                  k(  s!J d|j                   d|j                          |j                  NJ d|j                           |j                  j                  dk(  sJ d|j                  j                          |j                  j                  dk(  sJ d|j                  j                          y)u  TC-A1: false-positive Gemini suppression → auto_gemini_triage dismiss + review_gate_passed → 회장 보고 0건.

    시나리오:
      - review thread body에 false-positive 패턴 ("wrapper pattern", "이미 처리") 포함
      - triage_pr → FALSE_POSITIVE → auto_resolved=True
      - review_gate_status.review_gate_passed=True
      - escalations 0건 (회장 보고 없음)
    zth-fp-01Fr9  z?This is just a wrapper pattern and is already handled correctlyr   zth-fp-02u<   이미 처리된 케이스입니다. 정상 동작입니다.p   z	sha-pr-a1rW   r      z;TC-A1: 2 false-positive threads must all auto_resolve, got r   z)TC-A1: no blocking threads expected, got TzGTC-A1: review_gate_passed must be True after false-positive suppressionz/TC-A1: all threads must be FALSE_POSITIVE, got  for Nz8TC-A1: FALSE_POSITIVE must have no escalation_type, got uA   TC-A1: scope_expansion_count must be 0 (회장 보고 0건), got z+TC-A1: false_positive_count must be 2, got )r    r;   re   r   r   r   r{   r   rr   r   FALSE_POSITIVErq   ru   r   r   r}   )
fp_threadsr   outcomes      r-   ,test_tc_a1_false_positive_gemini_suppressionrh  
  s     "cde		
  "`ab		
J N+	F %%* 
EfF`F`Eab* ''1, 
3F4P4P3QR, $$774? 
Q? >> 
-">">> 	
=goo=NeT[TeTeSfg	
> &&. 	
FwG^G^F_`	
.	
   66!; 
KFLaLaLwLwKxy;   55: 
5f6K6K6`6`5ab:r/   c            
        dddddigddddddigdddddd	igdg} t        d
| dg t        t              g dd      }|j                  dk(  sJ d|j                          |j                  dk(  sJ d|j                          |j
                  j                  du sJ d       |j                  D ]S  }|j                  t        j                  k(  s!J d|j                   d|j                          |j                  NJ d        |j                  j                  dk(  sJ d|j                  j                          |j                  j                  dk(  sJ d|j                  j                          y)u  TC-A2: style-only Gemini suppression → auto_gemini_triage dismiss + review_gate_passed → 회장 보고 0건.

    시나리오:
      - review thread body에 style-only 패턴 ("naming", "code style", "formatting") 포함 (bug 단어 없음)
      - triage_pr → STYLE_ONLY → auto_resolved=True
      - review_gate_status.review_gate_passed=True
      - 회장 보고 0건
    zth-style-01Fr9  zWThe naming convention here is inconsistent. Consider renaming to follow the convention.r   zth-style-02zAcode style nit: use f-string instead of .format() for readabilityzth-style-03zAMinor formatting issue: consistency with the rest of the codebaseq   z	sha-pr-a2rW   r      z7TC-A2: 3 style-only threads must all auto_resolve, got r   z)TC-A2: no blocking threads expected, got TzCTC-A2: review_gate_passed must be True after style-only suppressionz+TC-A2: all threads must be STYLE_ONLY, got rd  Nz.TC-A2: STYLE_ONLY must have no escalation_typeuA   TC-A2: scope_expansion_count must be 0 (회장 보고 0건), got z'TC-A2: style_only_count must be 3, got )r    r;   re   r   r   r   r{   r   rr   r   
STYLE_ONLYrq   ru   r   r   r~   )style_threadsr   rg  s      r-   (test_tc_a2_style_only_gemini_suppressionrn  H  s      "{|}		
   "efg		
   "efg		
M( N+	F %%* 
A&B\B\A]^* ''1, 
3F4P4P3QR, $$774? 
M? >> 
-":":: 	
9'//9J%PWPaPaObc	
: &&. 	
<	
.	
   66!; 
KFLaLaLwLwKxy;   11Q6 
1&2G2G2X2X1YZ6r/   c            
        ddl m}  t        dgd      }dd} | |j                  t	               |      \  }}|du s
J d	|        |g k(  s
J d
|        t        t	               dd|d      }ddg}t        dgd|      }t        t	        t        dd      t        dd      d      dd||      }t        d|dt        t              t        t        t        |      }	|	j                  t        k(  s!J d|	j                   d|	j                          ddl m}   | dgt	               |      \  }
}|
du s
J d|        t!        |	d|d d      }|j                  t        k(  sJ d|j                          y)u  TC-A3: dependency satisfied 자동 판정 → merge_topology_gate ALLOW → 자동 진행.

    시나리오:
      - dependency=["task-2509.merged"] (선행 PR merged)
      - main_log_grep이 task-2509 존재 → True 반환
      - check_predecessor_merged → (True, [])
      - evaluate_pr → WAITING_FOR_PREDECESSOR가 아닌 AUTO_MERGE_ALLOWED
      - merge_topology_gate도 병렬 충돌 없음 (serial_only, no conflict)
    r   )check_predecessor_mergedztask-2509.mergedrY   )r^   r_   c                    | dk(  S )Nz	task-2509r6   )r[   s    r-   _mergedzCtest_tc_a3_dependency_satisfied_auto_merge_allowed.<locals>._merged  s    +%%r/   )r^   rB   main_log_grepTz+TC-A3: predecessor must be merged, pending=z-TC-A3: no pending predecessors expected, got zmain-sha-a3N)rB   rk   rl   rs  rc   r   r   )r^   r_   rc   r   r   merged))r   )r,  r-  r   114r   r   	sha-pr-a3r   z?TC-A3: expected AUTO_MERGE_ALLOWED (dependency satisfied), got r   z/TC-A3: merge_topology_gate must ALLOW, pending=c                     y)Nrw  r6   r   s    r-   r   zDtest_tc_a3_dependency_satisfied_auto_merge_allowed.<locals>.<lambda>  r   r/   r   z6TC-A3: dry_run=True must keep AUTO_MERGE_ALLOWED, got )r[   strreturnbool)utils.merge_queue_executorrp  ri   r^   rE   r   r.   r   r;   re   r   r   r   r   r   r|   r   )rp  r   rr  rR   pendingr   r   spec_with_smoke	ctx_smoker   ok2pending2r   s                r-   2test_tc_a3_dependency_satisfied_auto_merge_allowedr    s    D&'%D& +??}KB
 :NDWINN:b=SI'SS= }&C 4 I$&'%O
  q:68Ah6W
  &	I !^,%	H  22 
I(J[J[I\\fgogvgvfwx2 D,&'}MC
 $;TI(TT; )4F ??00 
@@QR0r/   c            	        ddl m} m}m}m}m}m}m} | ||||||g}|D ]a  }|t        v s(J d| dt        t        j                                       t        |   }	t        |	t              rMJ d| dt        |	               y)u^   LEGACY_CRITICAL_MAP이 merge_queue_executor의 CRITICAL 7종을 모두 커버하는지 확인.r   )r	   r
   r   r   r   r   r   z"LEGACY_CRITICAL_MAP must contain 'z': zLEGACY_CRITICAL_MAP['z''] must be CriticalEscalationType, got N)r|  r	   r
   r   r   r   r   r   r$   r;   keysr&  r   r'  )
r	   r
   r   r   r   r   r   all_critical_codescodemappeds
             r-   +test_legacy_critical_map_covers_all_7_typesr    s       	 ('!#! # 
** 	
0c$?R?W?W?Y:Z9[\	
* %T*&"89 	
#D6)PQUV\Q]P^_	
9
r/   )r   r   r   )r(   intr)   ry  r*   ry  rz  zsubprocess.CompletedProcessr5   )rA   zdict | None)rz  r   )NNzmain-sha-fixture-001)rl   ry  rz  r   )rz  r   )rz  r!   )rz  None)Q__doc__
__future__r   dataclassesr+   syspathlibr   r   __file__resolveparent	WORKSPACEry  r8  removeinsertr|  r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   utils.automation_contractsr   r   r   r   r   r   r   r   r   r   r   r    utils.post_merge_smoke_runnerr!   r"   "utils.critical_escalation_reporterr#   r$   utils.replacement_pr_runnerr%   r.   rE   re   r   r   r   ri   rm   r   r   r   r   r  r  r*  r5  r@  rG  rL  rW  r`  rh  rn  r  r  r6   r/   r-   <module>r     s  : #   
   N""$++2299	y>SXXHHOOC	N# 3y> "    &   e
2 $9  !  )R@2t<	" 2  	$0 0f FQh]@>BTv6r/PdLP^2Pj,P^DPNJPb;|?DZB
r/   