
    " jHz              
      .   d Z ddlmZ ddlZddlZddlmZ ddlmZm	Z	m
Z
 ddlZ ee      j                         j                  d   Z ee      ej"                  vr"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$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+ dFdGdZ,d	d
ddddeddd		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dHdZ-ddddd	 	 	 	 	 	 	 	 	 	 	 dIdZ.ej^                  dJd       Z0ej^                  dKd       Z1ej^                  dLd       Z2ej^                  dMd       Z3dNdZ4dNdZ5dOdZ6	 	 	 	 	 	 dOdZ7	 	 	 	 	 	 dOdZ8dOd Z9dNd!Z:dNd"Z;dNd#Z<dNd$Z=dNd%Z>dNd&Z?dNd'Z@	 	 	 	 dNd(ZA	 	 	 	 dNd)ZBdPd*ZCdPd+ZDdPd,ZEdPd-ZFdNd.ZGdQd/ZH	 	 	 	 dNd0ZI	 	 	 	 dNd1ZJdNd2ZKdNd3ZL	 	 	 	 dNd4ZM	 	 	 	 dNd5ZNdPd6ZOdOd7ZPdQd8ZQdOd9ZR	 	 	 	 dNd:ZSdQd;ZTdQd<ZU	 	 	 	 dQd=ZVdOd>ZWdQd?ZXdQd@ZYdQdAZZdQdBZ[dQdCZ\dQdDZ]	 	 	 	 dQdEZ^y)Ru  anu_v2.tests.test_merge_queue_executor_2531 — 9 회귀 (회장 §명시 9 기능 1:1).

회귀 케이스 (회장 §명시):
  1. queue_head_evaluate                      — head task 자동 평가 PASS
  2. expected_files_diff_gate_match           — expected_files == PR diff PASS
  3. expected_files_diff_gate_mismatch        — 불일치 시 BLOCK (비critical)
  4. forbidden_path_gate                      — forbidden_paths hit 시 Critical 7종
  5. ci_gemini_clean_sha_lock                 — 모든 gate + CLEAN + SHA lock 검증
  6. bot_identity_squash_merge                — GH_TOKEN process-local injection (mock gh)
  7. post_merge_smoke                         — 회귀 재실행 PASS
  8. downstream_stale_revalidation            — 다른 OPEN PR evidence 재검증 호출 횟수
  9. critical_7_classification + non_critical_auto
                                              — Critical 7종 분류 + 비critical self-resolve

본 회귀는 anu_v2/* 모듈만 import 한다 (one-way isolation).
    )annotationsN)Path)AnyMappingSequence   )AUTO_MERGE_ALLOWEDAUTO_MERGE_SUCCESSBLOCKED_WITH_REASONCI_FAILURE_BLOCKCRITICAL_BLOCK_OVERRIDECRITICAL_CODESCRITICAL_FORBIDDEN_PATHCRITICAL_GEMINI_SCOPE_EXPANSIONCRITICAL_POST_MERGE_SMOKEDIFF_CONTAMINATIONFORBIDDEN_GIT_FLAGSGEMINI_COMPLETEDGEMINI_SCOPE_EXPANSIONGEMINI_UNRESOLVEDGEMINI_UNRESOLVED_BLOCKHEAD_SHA_LOCK_BROKENMERGE_STATE_NOT_CLEANNON_CRITICAL_AUTO_RESOLVEDWAITING_FOR_PREDECESSORGateOutcomeMergeQueueExecutorPRMetaassert_no_forbidden_git_flagsload_task_spec_from_mdc                4    t        j                  g | ||      S )Nargs
returncodestdoutstderr)
subprocessCompletedProcess)r$   r%   r&   s      B/home/jay/workspace/anu_v2/tests/test_merge_queue_executor_2531.py_cpr*   =   s    &&B:f]cdd    Q   deadbeefztask/task-2531-dev4main)anu_v2/__init__.pyanu_v2/merge_queue_executor.pyanu_v2/tests/__init__.py.anu_v2/tests/test_merge_queue_executor_2531.pyTCLEAN	numberhead_shahead_refbase_refchanged_filesci_required_all_successgemini_statusmerge_state_statusqueue_predecessors_openc        	        <    t        | |||t        |      ||||	      S )Nr4   )r   tupler4   s	            r)   _make_prr@   A   s1    " M* 7#- 7
 
r+   	task-2531 F)task_idexpected	forbiddencherryc               T   d|z   dddg}|D ]  }|j                  d| d        |r-|j                  d       |D ]  }|j                  d| d        |j                  d|rd	nd
        |j                  d       | | dz  }|j                  dj                  |      d       |S )Nz#  z```yamlzexpected_files:z  - ""zforbidden_paths:zcherry_pick_allowed: truefalsez```z.md
utf-8encoding)append
write_textjoin)tmp_pathrC   rD   rE   rF   bodyfps           r)   _write_task_mdrW   _   s     7NB	+<=D "eA3aL!"&' 	&AKK%s!%	&KK'&g'FGHKKgYc?"ALL47L3Hr+   c                     g S NrB   rB   r+   r)   gh_callsrZ   z       Ir+   c                     g S rY   rB   rB   r+   r)   pytest_callsr]      r[   r+   c                     g S rY   rB   rB   r+   r)   audit_callsr_      r[   r+   c                L    fd}d }fd}fd}t        |||||       S )Nc                l    j                  t        |       t        |xs i       d       t               S Nr#   envrP   listdictr*   r#   rd   rZ   s     r)   	gh_runnerzexecutor.<locals>.gh_runner   '    dDODEur+   c                     t               S rY   r*   _argss    r)   
git_runnerzexecutor.<locals>.git_runner   	    ur+   c                :    j                  t        |              yNr   )rP   r?   )r#   r]   s    r)   pytest_runnerzexecutor.<locals>.pytest_runner   s    E$K(r+   c                :    j                  t        |              y rY   rP   rg   )recordr_   s    r)   audit_writerzexecutor.<locals>.audit_writer   s    4<(r+   ri   ro   rs   rw   task_md_root)r   )rS   rZ   r]   r_   ri   ro   rs   rw   s    ```    r)   executorrz      s5    ) #! r+   c                    t        d      }| j                  |      }|j                  sJ |j                  t        k(  sJ |j
                  dk(  sJ y )Nr   r=   queue_head_confirmed)r@   evaluate_queue_headpasseddecisionr	   reasonrz   prouts      r)   test_1_queue_head_evaluate_passr      sN    	!	,B

&
&r
*C:::<<----::////r+   c                    t        d      }| j                  |      }|j                  rJ |j                  t        k(  sJ d|j
                  v sJ y )Nr   r|   z2 predecessor)r@   r~   r   r   r   r   r   s      r)   "test_1_queue_head_evaluate_waitingr      sM    	!	,B

&
&r
*Czz><<2222cjj(((r+   c                    t        |      }t        |      }t               }| j                  ||      }|j                  sJ |j
                  t        k(  sJ y rY   )rW   r    r@   check_expected_files_diffr   r   r	   rz   rS   mdspecr   r   s         r)   %test_2_expected_files_diff_gate_matchr      sN    		!B!"%D	B

,
,T2
6C:::<<----r+   c                    t        |      }t        |      }d}t        |      }| j                  ||      }|j                  rJ |j
                  t        k(  sJ d|j                  d   v sJ y )N)r/   r0   r1   r2   utils/merge_queue_executor.pyr9   r   extra)rW   r    r@   r   r   r   r   r   )rz   rS   r   r   contaminatedr   r   s          r)   (test_3_expected_files_diff_gate_mismatchr      ss     
	!B!"%DL 
	-B

,
,T2
6Czz><<----*cii.@@@@r+   c                $   t        |dd      }t        |      }t        d      }| j                  ||      }|j                  rJ |j
                  t        k(  sJ |j                  sJ |j                  t        k(  sJ d|j                  d   v sJ y )N)r0   )utils/**zdispatch/**z
scripts/**)rD   rE   )r0   utils/foo.pyr   r   hits)rW   r    r@   check_forbidden_pathsr   r   r   is_criticalcritical_coder   r   r   s         r)   #test_4_forbidden_path_gate_criticalr      s     
4;
B
 ""%D	 R	SB

(
(r
2Czz><<....??? 7777SYYv....r+   c                    t        |d      }t        |      }t               }| j                  ||      }|j                  sJ y )N)r   )rE   )rW   r    r@   r   r   r   s         r)    test_4_forbidden_path_gate_cleanr      s=    	M	:B!"%D	B

(
(r
2C:::r+   c                ^    t        d      }| j                  |d      }|j                  sJ y )Nabc123r6   head_sha_at_lock)r@   check_ci_gemini_clean_sha_lockr   r   s      r)   (test_5_ci_gemini_clean_sha_lock_all_passr      s-    	8	$B

1
1"x
1
PC:::r+   c                    t        d      }| j                  |d      }|j                  t        k(  sJ |j                  rJ y )NF)r:   r-   r   )r@   r   r   r   r   r   s      r)   'test_5_ci_gemini_clean_sha_lock_ci_failr      sC    	%	0B

1
1"z
1
RC<<++++r+   c                    t        t              }| j                  |d      }|j                  sJ |j                  t
        k(  sJ y N)r;   r-   r   )r@   r   r   r   r   r   r   s      r)   )test_5_ci_gemini_scope_expansion_criticalr      sC    	 6	7B

1
1"z
1
RC??? ????r+   c                    t        t              }| j                  |d      }|j                  t        k(  sJ |j
                  rJ y r   )r@   r   r   r   r   r   r   s      r)   /test_5_ci_gemini_unresolved_blocks_non_criticalr     sD    	 1	2B

1
1"z
1
RC<<2222r+   c                    t        d      }| j                  |d      }|j                  sJ |j                  t        k(  sJ y )NBLOCKEDr<   r-   r   )r@   r   r   r   r   r   s      r)   -test_5_ci_gemini_merge_state_blocked_criticalr     sB    	Y	/B

1
1"z
1
RC??? 7777r+   c                    t        d      }| j                  |d      }|j                  t        k(  sJ |j                  rJ y )NDIRTYr   r-   r   )r@   r   r   r   r   r   s      r)   /test_5_ci_gemini_merge_state_dirty_non_criticalr     sC    	W	-B

1
1"z
1
RC<<0000r+   c                    t        d      }| j                  |d      }|j                  t        k(  sJ |j                  d   dk(  sJ |j                  d   dk(  sJ y )Nnewshar   oldshar   lockedcurrent)r@   r   r   r   r   r   s      r)   %test_5_ci_gemini_head_sha_lock_brokenr     sb    	8	$B

1
1"x
1
PC<<////99X(***99Y8+++r+   c                   |j                  dd       |j                  dd       |j                  dd       t        d      }| j                  |d	
      }|j                  t        k(  sJ t        |      dk(  sJ |d   }|d   d d g dk(  sJ d|d   v sJ d|d   v sJ |d   d   dk(  sJ |d   d   dk(  sJ |d   d   dk(  sJ t        |d         t        z  rJ y )NBOT_GITHUB_TOKENghs_BOT_FAKE_TOKENPATHz/sentinel/path:/usr/binGH_TOKENghs_OWNER_LEAKEDr,   r5   r-   r      r   r#      )r   merge81--squash--match-head-commitrd   GITHUB_TOKEN)setenvr@   execute_bot_squash_merger   r
   lensetr   )rz   rZ   monkeypatchr   r   calls         r)   2test_6_bot_identity_squash_merge_injects_bot_tokenr     s&    )+?@v89z#56		B

+
+B
+
LC<<----x=AA;D<4444f%%% DL000;z"&::::;~&*>>>>;v";;;;DL!$77887r+   c                    |j                  dd       t               }| j                  |d      }|j                  t        k(  sJ |j
                  sJ |j                  t        k(  sJ y )Nr   Fraisingr-   r   )delenvr@   r   r   r   r   r   r   )rz   r   r   r   s       r)   .test_6_bot_identity_blocked_when_token_missingr   7  sh     )59	B

+
+B
+
LC<<....??? 7777r+   c            	         dD ]6  } t        j                  t        d      5  t        dddd| g       d d d        8 y # 1 sw Y   CxY w)N)z--adminz--forcez--force-with-leasez-fz--rebaseFORBIDDEN_GIT_FLAG_BLOCKEDmatchr   r   r   r   pytestraisesRuntimeErrorr   flags    r)   .test_6_bot_identity_rejects_admin_force_rebaser   B  sT    N S]]</KL 	S)4$
D*QR	S 	SS	S 	Ss	   =A	c                     dD ]5  } t        j                  t        d      5  t        ddd| g       ddd       7 y# 1 sw Y   BxY w)u[   Security-High 회귀: `--admin=true`, `--force-with-lease=ref` 등 값 포함형도 차단.)z--admin=truez	--force=1z--force-with-lease=refs/xz--rebase=preserver   r   r   r   r   Nr   r   s    r)   /test_6_assert_no_forbidden_git_flags_value_formr   H  sR    _ G]]</KL 	G)4$*EF	G 	GG	G 	Gs	   <A	c                     dD ]4  } t        j                  t        d      5  t        dd| g       ddd       6 y# 1 sw Y   AxY w)uN   Security-High 회귀: 단축 결합 (`-af`, `-fa`) 도 `-f` 포함 시 차단.)z-afz-faz-xfyr   r   r   r   Nr   )combineds    r)   3test_6_assert_no_forbidden_git_flags_combined_shortr   O  sP    * E]]</KL 	E)4(*CD	E 	EE	E 	Es	   ;A	c                     t        g d       y)u=   정상 인자는 통과해야 한다 (false positive 방지).)
r   r   r   r   r   r   z	--subjectz[task-2531] somethingz-RzJeon-Jonghyuk/dev_workspaceN)r   rB   r+   r)   5test_6_assert_no_forbidden_git_flags_allows_safe_argsr   V  s    ! # r+   c                d    | j                  dg      }|j                  t        k(  sJ |dgk(  sJ y )Nr2   smoke_test_paths)r2   )run_post_merge_smoker   r
   )rz   r]   r   s      r)   test_7_post_merge_smoke_passr   _  sD    

'
'JK ( C <<----OPPPPr+   c                   d }fd}d }fd}t        |||||       }|j                  dg      }|j                  t        k(  sJ |j                  sJ |j
                  t        k(  sJ |j                  d   d	k(  sJ y )
Nc                      y)Nr   rB   rm   s    r)   failing_pytestz@test_7_post_merge_smoke_fail_is_critical.<locals>.failing_pytesth  s    r+   c                l    j                  t        |       t        |xs i       d       t               S rb   re   rh   s     r)   ri   z;test_7_post_merge_smoke_fail_is_critical.<locals>.gh_runnerk  rj   r+   c                     t               S rY   rl   rm   s    r)   ro   z<test_7_post_merge_smoke_fail_is_critical.<locals>.git_runnero  rp   r+   c                :    j                  t        |              y rY   ru   recr_   s    r)   rw   z>test_7_post_merge_smoke_fail_is_critical.<locals>.audit_writerr      49%r+   rx   zanu_v2/tests/x.pyr   pytest_exit_coder   )r   r   r   r   r   r   r   r   )	rS   rZ   r_   r   ri   ro   rw   exr   s	    ``      r)   (test_7_post_merge_smoke_fail_is_criticalr   g  s    & 
$!
B 
!
!4G3H
!
IC<<....??? 999999'(A---r+   c                   |j                  dd       |j                  dd       | j                  dg d      }t        |      dk(  sJ t        d	 |D              sJ t        |      dk(  sJ |D ]W  }|d
   d   dk(  sJ |d
   d   dk(  sJ |d
   d   }d|v sJ d|v sJ |d   d   dk(  sJ |d   d   dk(  sJ |d   d   dk(  rWJ  y )Nr   ghs_BOT_DOWNSTREAMr   z/usr/binrA   )R   S   T   merged_task_iddownstream_pr_numbersr   c              3  &   K   | ]	  }|d      ywokNrB   .0rs     r)   	<genexpr>zItest_8_downstream_stale_revalidation_invokes_gh_per_pr.<locals>.<genexpr>  s     (1qw(s   r#   r   r   r   commentzevidence revalidationrd   r   r   )r   revalidate_downstreamr   all)rz   rZ   r   resultsr   rT   s         r)   6test_8_downstream_stale_revalidation_invokes_gh_per_prr
    s)    )+?@vz*,,"* - G w<1(((((x=A  1F|A$&&&F|A)+++F|Bd"""&$...E{:&*>>>>E{>*.BBBBE{6"j0001r+   c                    |j                  dd       | j                  dddg      }t        |      dk(  sJ t        d	 |D              sJ t        d
 |D              sJ t        |      dk(  sJ y)uG   Security-High 회귀: BOT 토큰 미주입 시 owner_pat 사용 차단.r   Fr   rA   r   r   r   r   c              3  (   K   | ]
  }|d       ywr   rB   r  s     r)   r  zItest_8_downstream_revalidate_blocks_when_token_missing.<locals>.<genexpr>  s     ,q1T7{,s   c              3  ,   K   | ]  }|d    dk(    yw)r   bot_token_unavailableNrB   r  s     r)   r  zItest_8_downstream_revalidate_blocks_when_token_missing.<locals>.<genexpr>  s     G!q{55Gs   r   N)r   r  r   r  )rz   rZ   r   r	  s       r)   6test_8_downstream_revalidate_blocks_when_token_missingr    s     )59,,"!2h - G w<1,G,,,,GwGGGGx=Ar+   c                    t        t        dt              }| j                  |      t        k(  sJ |j                  t
        v sJ y )NrE   )r   r   r   )r   r   r   classify_failurer   r   )rz   criticals     r)   0test_9_classify_critical_7_returns_critical_coder    sE    $-H
 $$X.2IIII!!^333r+   c                Z    t        t        d      }| j                  |      t        k(  sJ y )Nmismatchr   r   )r   r   r  r   )rz   non_crits     r)   2test_9_classify_non_critical_returns_auto_resolvedr    s)    $6zJH$$X.2LLLLr+   c                    t        t        ddgdgd      }| j                  |      }|j                  t        k(  sJ t        |      dk(  sJ |d   }|d   d	k(  sJ |d
   t        k(  sJ |d   dk(  sJ y )Nexpected_files_mismatcha.pyb.py)missingr   )r   r   r   r   r   kindnon_critical_auto_resolvedr   r   )r   r   auto_handle_non_criticalr   r   r   )rz   r_   r  r   r   s        r)   >test_9_auto_handle_non_critical_writes_audit_and_self_resolvesr!    s     #(!(fX6H
 
+
+H
5C<<5555{q   
a.Cv;6666z?0000x=5555r+   c                    t        t        d      }| j                  |      }|j                  t        k(  sJ t        |      dk(  sJ y)uS   WAITING_FOR_PREDECESSOR 는 정상 대기 상태 → audit 노이즈 방지 (skip).z2 predecessors still openr  r   N)r   r   r   r   r   r   )rz   r_   waitingr   s       r)   .test_9_waiting_for_predecessor_skips_audit_logr$    sL     (*G 
+
+G
4C<<5555{q   r+   c                 ,    t        t              dk(  sJ y)uK   회장 §명시: Critical 7종 외 분류 일체 금지 → 정확히 7개.   N)r   r   rB   r+   r)   'test_9_critical_codes_are_exactly_sevenr'    s    ~!###r+   c                    t        |       t        d      }| j                  |d      }|j                  sJ |j                  t
        k(  sJ |j                  dk(  sJ y )N
locked-shar   r   r   all_4_gates_pass)rW   r@   evaluater   r   r	   r   )rz   rS   r   r   s       r)   #test_integration_full_evaluate_passr-    s[    8	<	(B


rL

AC:::<<----::++++r+   c                    ddl m}  |dd      du sJ  |dd      du sJ  |dd      du sJ  |dd      d	u sJ  |d
d      du sJ  |d
d      d	u sJ  |dd      du sJ  |dd      du sJ y)uA   `**/foo.py` 패턴이 루트 파일 `foo.py` 도 매칭하는지.r   )_glob_matchz	**/foo.pyzfoo.pyTza/foo.pyz
a/b/foo.pyzfoo.txtFz
utils/*.pyz
utils/x.pyzutils/sub/x.pyr   zutils/a/b/x.pyN)anu_v2.merge_queue_executorr/  )rS   r/  s     r)   %test_glob_match_double_star_root_filer1    s    7{H-555{J/4777{L1T999{I.%777|\2d:::|%56%???z<0D888z#34<<<r+   c                "   |j                   dz  }|j                  dd       	 t        d      }| j                  |d      }|j                  t
        k(  sJ |j                  sJ 	 |j                  d	
       y# |j                  d	
       w xY w)uY   branch 명에 `..` 가 들어와도 task_md_root 외부 파일을 가리키지 않는다.z	leaked.mdz7expected_files:
  - "x.py"
forbidden_paths:
  - "y.py"
rM   rN   z"task/task-../../../etc/passwd-dev4)r7   r-   r*  T)
missing_okN)parentrQ   r@   r,  r   r   r   unlink)rz   rS   leakedr   r   s        r)   ,test_evaluate_path_traversal_branch_rejectedr7    s     __{*F
I  'CD2
C ||2222&&s   AA: :Bc                   |j                  dd       |j                  dd       |j                  dd       t        d      }| j                  |d	
       |d   d   }|d   dk(  sJ |d   dk(  sJ |d   dk(  sJ |d   dk(  sJ y)u\   High Gemini 회귀: env={...} 로 PATH 누락되면 gh 가 없어 fail 했던 패턴 박제.r   ghs_BOTr   z/x/y/zHOMEz/home/agentc   r   r-   r   r  rd   r   r   N)r   r@   r   )rz   rZ   r   r   env_useds        r)   )test_bot_squash_merge_does_not_strip_pathr=    s     )95vx(v}-		B%%b:%F|E"HFx'''F},,,J9,,,N#y000r+   c                    | dz  }|j                  dd       t        |      }d|j                  v sJ d|j                  v sJ d|j                  v sJ d|j                  v sJ y	)
u^   파일명에 `#` 이 포함된 인용 항목이 주석 시작점으로 오인되지 않는지.task-2531.mdu   expected_files:
  - "src/C#_file.cs"
  - "docs/note.md" # 후행 주석
  - bare_path.py # 비인용도 주석 절단 동작
forbidden_paths:
  - "legacy/#archive/**"
rM   rN   zsrc/C#_file.cszdocs/note.mdzbare_path.pyzlegacy/#archive/**NrQ   r    expected_filesforbidden_pathsrS   r   r   s      r)   0test_yaml_parser_allows_hash_in_quoted_filenamesrD  %  s    	N	"BMM	'    ""%Dt22222T00000T000004#7#7777r+   c                    |j                  dd       fd}fd}t        |d d ||       }t               }|j                  |d	      }|j                  t
        k(  sJ |j                  d
   dk(  sJ y)u>   cp.stderr 가 None 이어도 TypeError 없이 처리하는지.r   r9  c                    j                  t        |       t        |xs i       d       t        j                  g dd d       S )Nrc   r   r"   rP   rf   rg   r'   r(   rh   s     r)   gh_runner_nonezAtest_bot_squash_merge_handles_none_stderr.<locals>.gh_runner_none<  s8    dDODE**qVZ[[r+   c                :    j                  t        |              y rY   ru   r   s    r)   rw   z?test_bot_squash_merge_handles_none_stderr.<locals>.audit_writerA  r   r+   c                     t               S rY   rl   _as    r)   <lambda>z;test_bot_squash_merge_handles_none_stderr.<locals>.<lambda>F      su r+   c                      yrr   rB   rK  s    r)   rM  z;test_bot_squash_merge_handles_none_stderr.<locals>.<lambda>G      r+   rx   r-   r   r&   rH   N)r   r   r@   r   r   r   r   	rS   rZ   r_   r   rH  rw   r   r   r   s	    ``      r)   )test_bot_squash_merge_handles_none_stderrrR  8  s    )95\
& 
 $#!
B 
B

%
%b:
%
FC<<....99X"$$$r+   c                    |j                  dd       fd}fd}t        |d d ||       }t               }|j                  |d	      }|j                  t
        k(  sJ |j                  d
   dk(  sJ y)uT   cp.stdout 이 None (returncode=0) 인 성공 케이스에서도 TypeError 없는지.r   r9  c                    j                  t        |       t        |xs i       d       t        j                  g dd d       S )Nrc   r   r"   rG  rh   s     r)   rH  zLtest_bot_squash_merge_handles_none_stdout_on_success.<locals>.gh_runner_noneX  s8    dDODE**qVZ[[r+   c                :    j                  t        |              y rY   ru   r   s    r)   rw   zJtest_bot_squash_merge_handles_none_stdout_on_success.<locals>.audit_writer\  r   r+   c                     t               S rY   rl   rK  s    r)   rM  zFtest_bot_squash_merge_handles_none_stdout_on_success.<locals>.<lambda>a  rN  r+   c                      yrr   rB   rK  s    r)   rM  zFtest_bot_squash_merge_handles_none_stdout_on_success.<locals>.<lambda>b  rP  r+   rx   r-   r   r%   rH   N)r   r   r@   r   r   r
   r   rQ  s	    ``      r)   4test_bot_squash_merge_handles_none_stdout_on_successrX  R  s     )95\& 
 $#!
B 
B

%
%b:
%
FC<<----99X"$$$r+   c                    |dz  }|j                  dd       t        ddd      }| j                  |d	      }|j                  sJ |j                  t
        k(  sJ y
)u   Security-High 회귀: forbidden_path (Critical) 가 queue/diff (non-critical) 보다
    먼저 평가되어, 비critical 우선 실패로 보안 검사가 누락되지 않는다.r?  zexpected_files:
  - "anu_v2/__init__.py"
  - "anu_v2/merge_queue_executor.py"
  - "anu_v2/tests/__init__.py"
  - "anu_v2/tests/test_merge_queue_executor_2531.py"
forbidden_paths:
  - "utils/**"
rM   rN   r)  r   )r/   r0   r1   r2   zutils/forbidden.py)r6   r=   r9   r*  N)rQ   r@   r,  r   r   r   )rz   rS   r   r   r   s        r)   &test_evaluate_critical_gates_run_firstrZ  l  sx     
N	"BMM	   	 
 !


B 

rL

AC??? 7777r+   c                    | dz  }|j                  dd       t        |      }d|j                  v sJ d|j                  v sJ d|j                  v sJ y)	uS   YAML 작은따옴표 인용 항목도 큰따옴표와 동일하게 추출되는지.r?  zWexpected_files:
  - 'src/single quoted.py'
  - "src/double quoted.py"
  - bare/path.py
rM   rN   zsrc/single quoted.pyzsrc/double quoted.pyzbare/path.pyN)rQ   r    rA  rC  s      r)   'test_yaml_parser_supports_single_quotesr\    so    	N	"BMM	    ""%D!T%8%8888!T%8%8888T00000r+   c                j    | dz  }|j                  dd       t        |      }|j                  du sJ y)uL   cherry_pick_allowed 행 끝 주석 (`true # 사유...`) 이 매칭되는지.r?  u]   ```yaml
expected_files:
  - "a.py"
cherry_pick_allowed: true   # 명시적 허용 사유
```
rM   rN   TNrQ   r    cherry_pick_allowedrC  s      r)   .test_cherry_pick_allowed_with_trailing_commentr`    G    	N	"BMM	
    ""%D##t+++r+   c                j    | dz  }|j                  dd       t        |      }|j                  du sJ y)uN   본문 prose 에 'cherry_pick_allowed' 단어가 있어도 YAML 값만 신뢰.r?  u   ## description
이 task 는 절대 cherry_pick_allowed: true 같은 정책을 허용하지 않는다.

```yaml
expected_files:
  - "a.py"
cherry_pick_allowed: false
```
rM   rN   FNr^  rC  s      r)   3test_cherry_pick_allowed_ignores_prose_outside_yamlrc    sG    	N	"BMM	   
 ""%D##u,,,r+   c                    | dz  }|j                  dd       t        |      }d|j                  v sJ d|j                  v sJ d|j                  vsJ d|j                  v sJ y)	uL   fenced code block 내부 들여쓰기된 expected_files 도 추출되는지.r?  z`## meta
```yaml
  expected_files:
    - "a.py"
    - "b.py"
  forbidden_paths:
    - "x/**"
```
rM   rN   r  r  x/**Nr@  rC  s      r)   /test_extract_block_indented_yaml_in_fenced_coderf    s    	N	"BMM	   
 ""%DT(((((T(((((,,,,,T)))))r+   c                    | dz  }|j                  dd       t        |      }d|j                  v sJ d|j                  v sJ d|j                  v sJ d|j                  v sJ y	)
u\   리스트 중간 빈 줄/주석 라인이 있어도 이후 항목이 누락되지 않는지.r?  u`   expected_files:
  - "a.py"

  # 중간 주석
  - "b.py"
  - "c.py"
forbidden_paths:
  - "x/**"
rM   rN   r  r  zc.pyre  Nr@  rC  s      r)   5test_extract_block_tolerates_blank_lines_and_commentsrh    s    	N	"BMM	   
 ""%DT(((((T(((((T(((((T)))))r+   c                j    | dz  }|j                  dd       t        |      }|j                  du sJ y)uT   들여쓰기된 cherry_pick_allowed (YAML 블록 내부) 가 정상 매칭되는지.r?  zC```yaml
expected_files:
  - "a.py"
  cherry_pick_allowed: true
```
rM   rN   TNr^  rC  s      r)   /test_cherry_pick_allowed_indented_in_yaml_blockrj    ra  r+   c                ,   |j                  dd       fd}fd}t        |d d ||       }t               }|j                  |d	      }|j                  t
        k(  sJ t        |j                  d
   t              sJ d|j                  d
   v sJ y)uH   gh_runner 가 bytes stdout/stderr 반환 시 str 로 정규화되는지.r   r9  c                    j                  t        |       t        |xs i       d       t        j                  g ddd      S )Nrc   r   s   ok-bytess   fail-bytes-한r"   rG  rh   s     r)   gh_runner_byteszDtest_bot_squash_merge_handles_bytes_streams.<locals>.gh_runner_bytes  s>    dDODE**'A
 	
r+   c                :    j                  t        |              y rY   ru   r   s    r)   rw   zAtest_bot_squash_merge_handles_bytes_streams.<locals>.audit_writer  r   r+   c                     t               S rY   rl   rK  s    r)   rM  z=test_bot_squash_merge_handles_bytes_streams.<locals>.<lambda>
  rN  r+   c                      yrr   rB   rK  s    r)   rM  z=test_bot_squash_merge_handles_bytes_streams.<locals>.<lambda>  rP  r+   rx   r-   r   r&   z
fail-bytesN)	r   r   r@   r   r   r   
isinstancer   str)	rS   rZ   r_   r   rm  rw   r   r   r   s	    ``      r)   +test_bot_squash_merge_handles_bytes_streamsrs    s     )95
& 
!$#!
B 
B

%
%b:
%
FC<<....cii)3///399X....r+   )r   rH   rH   )r$   intr%   rr  r&   rr  returnzsubprocess.CompletedProcess)r5   rt  r6   rr  r7   rr  r8   rr  r9   Sequence[str]r:   boolr;   rr  r<   rr  r=   rt  ru  r   )rS   r   rC   rr  rD   rv  rE   rv  rF   rw  ru  r   )ru  zlist[dict[str, Any]])ru  zlist[Sequence[str]])ru  zlist[Mapping[str, Any]])rS   r   ru  r   )rz   r   ru  None)rz   r   rS   r   ru  rx  )ru  rx  )rS   r   ru  rx  )___doc__
__future__r   r'   syspathlibr   typingr   r   r   r   __file__resolveparentsWORKSPACE_ROOTrr  pathinsertr0  r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r*   r@   rW   fixturerZ   r]   r_   rz   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r
  r  r  r  r!  r$  r'  r-  r1  r7  r=  rD  rR  rX  rZ  r\  r`  rc  rf  rh  rj  rs  rB   r+   r)   <module>r     sm  " #  
  ) )  h'')11!4~chh&HHOOAs>*+      :e )$ %))%#$  	
  ! "   !  !B   "  	   
6        20).A A,0A	A(/ /,0/	/$@8,9 9	908 8	8SGEQ.:1 1	14 	"4M
6 6	6$! !	!$,= '(1 1	1&8&%4%%	%48B1 ,-$*,**,//	/r+   