
    +j                       d Z ddlmZ ddlZddlmc 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mZ  ee      j%                         j&                  d   Zedz  dz  Zej,                  j/                  d ee             ddlmZmZmZ d!d	Z	 	 	 	 	 	 	 	 	 	 d"d
Z G d d      Z G d d      Z  G d d      Z! G d d      Z" G d d      Z# G d d      Z$ G d d      Z% G d d      Z& G d d      Z' G d d      Z( G d d       Z)y)#u  task-2726 회귀 테스트 — finish-task.sh worktree 격리 strict mode.

테스터: 모리건(Morrigan), 개발3팀
대상: FINISH_TASK_WORKTREE_STRICT feature flag 및 연관 bash 함수들

6개 회귀 케이스:
  회귀1: test_resolver_finds_scheduler_worktree
  회귀2: test_unresolved_emits_marker_no_fallback
  회귀3: test_external_dirty_zero_with_worktree_isolation
  회귀4: test_forbidden_diff_still_blocks
  회귀5: test_merge_base_scope_independent_of_local_main
  회귀6: test_flag_off_preserves_legacy
    )annotationsN)Path   scriptszfinish-task.sh)EXTERNAL_DIRTY_BLOCKEROWN_DIRTY_FAILclassify_blockerc                   t         j                  d      }|j                  |  d      }d}|j                  d|      }d}t        |t	        |            D ]*  }||   dk(  r|dz  }||   dk(  s|dz  }|dk(  s%|dz   } n d}||u}|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }	t        j                  d|  d      dz   d|	iz  }
t        t        j                  |
            dx}}||| S )uF   finish-task.sh 에서 `name() { ... }` 함수 정의 블록을 추출.utf-8encodingz() {r   {N   }is notz%(py0)s is not %(py3)sendpy0py3u   함수 u    끝 찾기 실패
>assert %(py5)spy5)FINISH	read_textindexrangelen
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanation)namesrcstartdepthir   j@py_assert2@py_assert1@py_format4@py_format6s              P/home/jay/workspace/tests/regression/test_finish_task_worktree_isolation_2726.pyextract_funcr3   -   s   


G

,CIIen%EE		#uA
C1c#h q6S=QJEVs]QJEz!e >3d?>>>3d>>>>>>3>>>3>>>d>>>gdV+=>>>>>>>uS>    c                   t        |       }dj                  d |D              }d| d| d| d|  d| d}t        j                  ddd	
      5 }|j	                  |       |j
                  }ddd       	 t        j                  dgdd      }	|	j                  j                         |	j                  ft        j                  |       S # 1 sw Y   _xY w# t        j                         w xY w)uT   추출한 함수를 controlled WORKSPACE/EVENTS_DIR 로 실행, (stdout, rc) 반환. c              3  (   K   | ]
  }d | d   yw)"N ).0as     r2   	<genexpr>zrun_func.<locals>.<genexpr>I   s     .A1#Qx.s   z#!/bin/bash
WORKSPACE="z"
EVENTS_DIR="z"

wz.shF)suffixdeleteNbashTcapture_outputtext)r3   jointempfileNamedTemporaryFilewriter(   
subprocessrunstdoutstrip
returncodeosunlink)
	func_nameargs	workspace
events_dirbodyarg_strharnessfhprs
             r2   run_funcrZ   @   s     	"Dhh...G; L  
1WI 	G 
	$	$Su	E 	VVNNFB<4Hxx~~-
		"  			"s   C
5?C 
CC-c                  "    e Zd ZdZd Zd Zd Zy)"TestResolverFindsSchedulerWorktreeuP   회귀1: _resolve_task_worktree 가 .worktrees/*<num>* 패턴으로 경로 echo.c                   t        |      }t        |dz        }t        j                  |d       |dz  dz  }|j                  d       t	        ddg||      \  }}d	}||k(  }|st        j                  d
|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}}t        |      }||k(  }|s@t        j                  d
|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  t               rt        j                  t               nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }
t        j                  d| d|d      dz   d|
iz  }t        t        j                  |            dx}}y)uL   task-timers.json 없이 .worktrees/wt-9001-dev3 만 있어도 경로 반환.eventsTexist_ok
.worktreeswt-9001-dev3parents_resolve_task_worktree	task-9001r   ==%(py0)s == %(py3)srcr   assert %(py5)sr   Nz0%(py0)s == %(py5)s
{%(py5)s = %(py2)s(%(py3)s)
}outstrwt_pathr   py2r   r   u   resolver 가 u    를 반환해야 하지만     반환
>assert %(py7)spy7)ro   rN   makedirsmkdirrZ   r   r    r!   r"   r#   r$   r&   r'   r%   )selftmp_pathrR   rS   rp   rn   rk   r.   r/   r0   r1   @py_assert4@py_format8s                r2   +test_finds_local_worktree_by_number_patternzNTestResolverFindsSchedulerWorktree.test_finds_local_worktree_by_number_patterna   s   M	H,-

J. \)N:d#3k]IzZRrQwrQrrQ'l 	
sl" 	
 	
 	
sl 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
  " 	
 	
 		 " 	
 	
 		 # 	
 	
  G9$@wO	
 	
 	
 	
 	
r4   c                   t        |      }t        |dz        }t        j                  |d       |dz  dz  }|j                  d       |dz  dz  }|j                  d       |dz  }|j                          d	d
dt        |      iii}|dz  j	                  t        j                  |      d       t        dd
g||      \  }}	d}
|	|
k(  }|st        j                  d|fd|	|
f      dt        j                         v st        j                  |	      rt        j                  |	      ndt        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}}
t        |      }||k(  }|s=t        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  t               rt        j                  t               nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                   d|d      dz   d |iz  }t        t        j                  |            dx}}y)!uM   task-timers.json worktree_path 가 존재 시 .worktrees 패턴보다 우선.r^   Tr_   ra   rb   rc   zexplicit-9001memorytasksrf   worktree_pathtask-timers.jsonr   r   re   r   rg   ri   rk   r   rl   r   Nrm   rn   ro   wt_explicitrq   u8   timers.json worktree_path 가 우선되어야 하지만 rs   rt   ru   )ro   rN   rv   rw   
write_textjsondumpsrZ   r   r    r!   r"   r#   r$   r&   r'   r%   )rx   ry   rR   rS   wt_fallbackr   
memory_dirtimersrn   rk   r.   r/   r0   r1   rz   r{   s                   r2   -test_timers_json_worktree_path_takes_priorityzPTestResolverFindsSchedulerWorktree.test_timers_json_worktree_path_takes_priorityr   sC   M	H,-

J. ->$' -?$'(
#S%5
 
(	(44JJv 	5 	
 3k]IzZRrQwrQrrQ+& 	
s&& 	
 	
 	
s& 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
  & 	
 	
 		 & 	
 	
 		 ' 	
 	
  GsgWU	
 	
 	
 	
 	
r4   c                T   t        |      }t        |dz        }t        j                  |d       t        ddg||      \  }}d}||k(  }|st	        j
                  d|fd||f      d	t        j                         v st	        j                  |      rt	        j                  |      nd	t	        j                  |      d
z  }dd|iz  }	t        t	        j                  |	            dx}}d}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      d
z  }t	        j                  d|d      dz   d|iz  }	t        t	        j                  |	            dx}}y)u9   해당하는 worktree 가 없으면 빈 문자열 반환.r^   Tr_   re   z	task-9999r   rg   ri   rk   r   rl   r   N rn   u4   worktree 없으면 빈 문자열이어야 하지만 rs   r   )ro   rN   rv   rZ   r   r    r!   r"   r#   r$   r&   r'   r%   )
rx   ry   rR   rS   rn   rk   r.   r/   r0   r1   s
             r2   "test_empty_when_no_worktree_existszETestResolverFindsSchedulerWorktree.test_empty_when_no_worktree_exists   s    M	H,-

J.3k]IzZRrQwrQrrQ_sby___sb______s___s___b___PQTPWW^_______r4   N)__name__
__module____qualname____doc__r|   r   r   r9   r4   r2   r\   r\   ^   s    Z
" 
D	`r4   r\   c                  4    e Zd ZdZd Zd Zd Zd Zd Zd Z	y)	#TestUnresolvedEmitsMarkerNoFallbacku\   회귀2: worktree-base.json 마커 존재/부재로 기대 판정, unresolved 마커 발행.c                `   t        |      }t        |dz        }t        j                  |d       |dz  dz  }|j                  t	        j
                  ddi      d       t        d	d
g||      \  }}d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }	t        j                  d      dz   d|	iz  }
t        t        j                  |
            dx}}y)u*   worktree-base.json 존재 시 rc=0 (true).r^   Tr_   ztask-9002.worktree-base.jsonbase_shadeadbeefr   r   _task_expects_worktree	task-9002r   rg   ri   rk   r   u7   worktree-base.json 존재 시 rc=0 (true) 이어야 함r   r   N)ro   rN   rv   r   r   r   rZ   r   r    r!   r"   r#   r$   r%   r&   r'   )rx   ry   rR   rS   marker_rk   r.   r/   r0   r1   s              r2   0test_expects_worktree_true_when_base_json_existszTTestUnresolvedEmitsMarkerNoFallback.test_expects_worktree_true_when_base_json_exists   s    M	H,-

J. H$'EE$**j*%=>Q1K=)ZX2QrQwQQQrQQQQQQQrQQQrQQQQQQQQQQQQQQr4   c                    t        |      }t        |dz        }t        j                  |d       t        ddg||      \  }}d}||k(  }|st	        j
                  d|fd||f      d	t        j                         v st	        j                  |      rt	        j                  |      nd	t	        j                  |      d
z  }t	        j                  d      dz   d|iz  }	t        t	        j                  |	            dx}}y)u=   worktree-base.json 없고 timers.json 없으면 rc=1 (false).r^   Tr_   r   r   r   rg   ri   rk   r   u+   마커 없으면 rc=1 (false) 이어야 함r   r   N)ro   rN   rv   rZ   r   r    r!   r"   r#   r$   r%   r&   r'   )
rx   ry   rR   rS   r   rk   r.   r/   r0   r1   s
             r2   *test_expects_worktree_false_when_no_markerzNTestUnresolvedEmitsMarkerNoFallback.test_expects_worktree_false_when_no_marker   s    M	H,-

J.1K=)ZX2ErQwEEErQEEEEEErEEErEEEQEEEEEEEEEEr4   c                   t        |      }t        |dz        }t        j                  |d       |dz  dz  }|j                  d       |dz  }|j                          dd	d
t        |      iii}|dz  j	                  t        j                  |      d       t        dd	g||      \  }}d}	||	k(  }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |	      dz  }t        j                  d      dz   d|iz  }t        t        j                   |            dx}
}	y)uB   task-timers.json worktree_path 비어있지 않으면 rc=0 (true).r^   Tr_   ra   zwt-9002-dev3rc   r~   r   r   r   r   r   r   r   r   rg   ri   rk   r   u>   timers.json worktree_path 존재 시 rc=0 (true) 이어야 함r   r   N)ro   rN   rv   rw   r   r   r   rZ   r   r    r!   r"   r#   r$   r%   r&   r'   )rx   ry   rR   rS   rp   r   r   r   rk   r.   r/   r0   r1   s                r2   8test_expects_worktree_true_when_timers_has_worktree_pathz\TestUnresolvedEmitsMarkerNoFallback.test_expects_worktree_true_when_timers_has_worktree_path   s   M	H,-

J.\)N:d#(
#S\
 
(	(44JJv 	5 	
 1K=)ZX2XrQwXXXrQXXXXXXrXXXrXXXQXXXXXXXXXXr4   c                   t        |      }t        |dz        }t        j                  |d       t        dddg||       |dz  dz  }|j                  } |       }|st        j                  d      d	z   d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}t        j                  |j                  d            }|d   }	d}|	|k(  }
|
st        j                   d|
fd|	|f      t        j                  |	      t        j                  |      dz  }t        j                  d|j#                  d             dz   d|iz  }t        t        j                  |            dx}	x}
}|d   }	d}|	|k(  }
|
slt        j                   d|
fd|	|f      t        j                  |	      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}	x}
}d}	|	|v }
|
st        j                   d|
fd|	|f      t        j                  |	      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            dx}	}
y) uA   _emit_worktree_unresolved 실행 후 마커 파일 생성 확인.r^   Tr_   _emit_worktree_unresolvedr   ztest-regression-reasonz"task-9002.worktree-unresolved.jsonu=   worktree-unresolved.json 마커 파일이 생성되어야 함C
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}marker_pathr   rr   py4Nr   r   classificationWORKTREE_UNRESOLVEDrg   z%(py1)s == %(py4)spy1r   u;   classification 이 WORKTREE_UNRESOLVED 이어야 하지만 
>assert %(py6)spy6task_idassert %(py6)sreasoninz%(py1)s in %(py3)sdatar   r   rl   r   ro   rN   rv   rZ   existsr   r%   r!   r"   r#   r$   r&   r'   r   loadsr   r    get)rx   ry   rR   rS   r   r/   @py_assert3@py_format5r   @py_assert0r.   @py_format7r0   r1   s                 r2   ,test_emit_worktree_unresolved_creates_markerzPTestUnresolvedEmitsMarkerNoFallback.test_emit_worktree_unresolved_creates_marker   s!   M	H,-

J.'23		
 ),PP!!d!#d#dd%ddddddd{ddd{ddd!ddd#ddddddzz+///AB$% 	
)> 	
%)>> 	
 	
%)> 	
 	
 		 & 	
 	
 		 *? 	
 	
  J$((ScJdIef	
 	
 	
 	
 	
 I-+-+----+------+-------x4x4x44r4   c                   t        |      }t        |dz        }t        j                  |d       d}t        dd|g||       |dz  dz  }|j                  } |       }|st        j                  d      d	z   d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}t        j                  |j                  d            }	|	d   }
d}|
|k(  }|slt        j                   d|fd|
|f      t        j                  |
      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}
x}}|	d   }
d}|
|k(  }|slt        j                   d|fd|
|f      t        j                  |
      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}
x}}|	d   }
|
|k(  }|st        j                   d|fd|
|f      t        j                  |
      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d|	j#                  d            dz   d|iz  }t        t        j                  |            dx}
}y)uS  HIGH-2 회귀: reason 에 작은따옴표가 있어도 marker 생성 PASS (heredoc injection 방지).

        구 코드는 python -c 내부에 '$reason' 직접 보간 → 작은따옴표 시 SyntaxError → marker 미생성.
        sys.argv 전달로 수정 후에는 작은따옴표가 원문 그대로 보존되어야 한다.
        r^   Tr_   z8git-gate: can't resolve PROJECT_PATH for 'worktree' taskr   z	task-9003z"task-9003.worktree-unresolved.jsonu^   작은따옴표 포함 reason 에서도 worktree-unresolved.json 마커가 생성되어야 함r   r   r   Nr   r   r   r   rg   r   r   r   r   r   r   z%(py1)s == %(py3)stricky_reasonr   uF   작은따옴표 reason 이 원문 그대로 보존되어야 하지만 r   r   r   )rx   ry   rR   rS   r   r   r/   r   r   r   r   r.   r   r0   r1   s                  r2   )test_emit_marker_with_single_quote_reasonzMTestUnresolvedEmitsMarkerNoFallback.test_emit_marker_with_single_quote_reason   sx    M	H,-

J.R'-(		
 ),PP!! 	
!# 	
# 	
  m	
 	
	6	
 	
   	
 	
 		  	
 	
 		 " 	
 	
 		 $ 	
 	
 	
 	
 	
 zz+///AB$%>)>>%)>>>>>%)>>>>%>>>)>>>>>>>>I-+-+----+------+-------H~ 	
~. 	
 	
~ 	
 	
 		  	
 	
	6	
 	
  "/ 	
 	
 		 "/ 	
 	
  UUYU]U]^fUgTjk	
 	
 	
 	
 	
r4   c           	     H   t        |      }t        |dz        }t        j                  |d       g d}t        |      D ]  \  }}d| }t	        d||g||       |dz  | dz  }|j
                  }	 |	       }
|
st        j                  d|d	      d
z   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |	      t        j                  |
      dz  }t        t        j                  |            dx}	}
t        j                  |j!                  d            }|d   }||k(  }|st        j"                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d|d|j%                  d            dz   d|iz  }t        t        j                  |            dx}} y)u  HIGH-2 회귀: 빈 문자열/유니코드/작은따옴표·특수문자 reason 에서도 crash 0, marker 생성·원문 보존.

        run_func 하니스가 인자를 큰따옴표로 감싸므로 command-substitution 및 백틱·큰따옴표는
        bash 레벨에서 변형된다(하니스 한계, finish-task.sh 무관). 실제 HIGH-2 벡터인 작은따옴표·세미콜론·
        퍼센트·유니코드·빈문자만으로 marker crash 0 및 원문 보존을 검증한다.
        r^   Tr_   )r   u   한글 사유 100% 완료z	a'b;d=e:fzit's a 'nested' oneztask-910r   z.worktree-unresolved.jsonzreason=u(    에서도 마커가 생성되어야 함r   r   r   Nr   r   r   rg   r   r   u$   reason 원문 보존 실패: 기대 u	   , 실제 r   r   )ro   rN   rv   	enumeraterZ   r   r   r%   r!   r"   r#   r$   r&   r'   r   r   r   r    r   )rx   ry   rR   rS   casesidxr   tidr   r/   r   r   r   r   r.   r0   r1   s                    r2   .test_emit_marker_with_empty_and_special_reasonzRTestUnresolvedEmitsMarkerNoFallback.test_emit_marker_with_empty_and_special_reason  s    M	H,-

J.U$U+ 	KCSE"C+f	 #X-3%7P0QQK%% %' '   &#KL v     I   I &  I (      ::k33W3EFD> >V+  >V  I "  v   &,  I &,    7vj	$((S[J\I_`    	r4   N)
r   r   r   r   r   r   r   r   r   r   r9   r4   r2   r   r      s&    fRFY4 .
:r4   r   c                  (    e Zd ZdZd Zd Zd Zd Zy)*TestExternalDirtyZeroWithWorktreeIsolationuQ   회귀3: worktree 격리 시 main 누적 dirty 가 차단하지 않음을 검증.c                p   dg}dg}t        ||      }|d   }|t        k7  }|st        j                  d|fd|t        f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                  d      dz   d	|iz  }t        t        j                  |            d
x}}|d   }|t        k(  }|st        j                  d|fd|t        f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                  d|d          dz   d	|iz  }t        t        j                  |            d
x}}y
)uJ   worktree 자기 변경 → OWN_DIRTY_FAIL (EXTERNAL_DIRTY_BLOCKER 아님).scripts/finish-task.shr   !=z%(py1)s != %(py3)sr   r   uO   자기 expected 파일의 dirty 는 EXTERNAL_DIRTY_BLOCKER 가 아니어야 함r   r   Nrg   r   r   u;   자기 파일 dirty 는 OWN_DIRTY_FAIL 이어야 하지만 )r	   r   r   r    r$   r!   r"   r#   r%   r&   r'   r   )rx   expected_filesdirty_pathsresultr   r.   r0   r1   s           r2   -test_own_dirty_is_own_dirty_fail_not_externalzXTestExternalDirtyZeroWithWorktreeIsolation.test_own_dirty_is_own_dirty_fail_not_external2  sz   23/0!.+>&' 	
'+AA 	
 	
'+A 	
 	
 		 ( 	
 	
	6	
 	
  ,B 	
 	
 		 ,B 	
 	
  ^	
 	
 	
 	
 	
 &' 	
'>9 	
 	
'> 	
 	
 		 ( 	
 	
	6	
 	
  ,: 	
 	
 		 ,: 	
 	
  J&QaJbIcd	
 	
 	
 	
 	
r4   c                T   dg}dg}t        ||      }|d   }g }||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j                  d      dz   d|iz  }t        t        j                  |            d	x}x}}y	)
uB   자기 expected 파일만 dirty 시 unrelated_dirty 비어야 함.r   unrelated_dirtyrg   r   r   u?   자기 파일만 dirty 시 unrelated_dirty 가 [] 이어야 함r   r   N)r	   r   r    r$   r%   r&   r'   )	rx   r   r   r   r   r   r.   r   r   s	            r2   /test_own_dirty_unrelated_is_empty_when_only_ownzZTestExternalDirtyZeroWithWorktreeIsolation.test_own_dirty_unrelated_is_empty_when_only_own@  s    23/0!.+>'( 	
B 	
(B. 	
 	
(B 	
 	
 		 ) 	
 	
 		 -/ 	
 	
  N	
 	
 	
 	
 	
 	
r4   c                   dg}t        d      D cg c]  }d| d
 c}g dz   }t        ||      }|d   }|t        k(  }|st        j                  d|fd|t        f      t        j
                  |      d	t        j                         v st        j                  t              rt        j
                  t              nd	d
z  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}}|d   }g }	||	k(  }|slt        j                  d|fd||	f      t        j
                  |      t        j
                  |	      dz  }
dd|
iz  }t        t        j                  |            dx}x}}	yc c}w )u   shared main 누적 dirty(worktree 와 무관) → EXTERNAL_DIRTY_BLOCKER.

        격리 시 이 dirty 들이 dirty_paths 에 안 들어오므로 차단 0.
        이 테스트는 '격리 덕분에 main dirty 차단 없음'의 대조 검증.
        r   d   zmemory/specs/xz.md)zutils/other.pyzdocs/README.mdzmemory/tasks/task-1234.mdr   rg   r   r   r   u   main 누적 dirty 가 포함되면 EXTERNAL_DIRTY_BLOCKER 여야 함 (격리 시엔 이게 dirty_paths에 안 들어와서 차단 0)r   r   N	own_dirtyr   r   r   r   )r   r	   r   r   r    r$   r!   r"   r#   r%   r&   r'   )rx   r   r,   r   r   r   r.   r0   r1   r   r   r   s               r2   4test_main_accumulated_dirty_becomes_external_blockerz_TestExternalDirtyZeroWithWorktreeIsolation.test_main_accumulated_dirty_becomes_external_blockerK  sJ    338=c
C1s#.C G
 
 ".+>&' 	
'+AA 	
 	
'+A 	
 	
 
	 ( 	
 	
 
6	
 	
  ,B 	
 	
 
	 ,B 	
 	
 N	
 	
 	
 	
 	

 k"(b("b(((("b((("(((b((((((( Ds   Fc                   dg}dg}t        ||      }|d   }|t        k7  }|st        j                  d|fd|t        f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                  d      dz   d	|iz  }t        t        j                  |            d
x}}|d   }g }||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	t        j                  d      dz   d|	iz  }
t        t        j                  |
            d
x}x}}y
)u   worktree 격리 시: dirty_paths 가 자기 expected 만 → EXTERNAL_DIRTY_BLOCKER 없음.

        이것이 task-2726 의 핵심: shared main 1238 dirty 가 dirty_paths 에
        들어오지 않으므로 EXTERNAL_DIRTY_BLOCKER 0건.
        r   r   r   r   r   r   uQ   격리 시 자기 파일만 dirty 면 EXTERNAL_DIRTY_BLOCKER 가 아니어야 함r   r   Nr   rg   r   r   uA   격리 시 unrelated_dirty 는 [] (main dirty 가 차단 안 함)r   r   r	   r   r   r    r$   r!   r"   r#   r%   r&   r'   rx   r   r   r   r   r.   r0   r1   r   r   r   s              r2   /test_isolated_worktree_has_zero_external_blockszZTestExternalDirtyZeroWithWorktreeIsolation.test_isolated_worktree_has_zero_external_blocksb  sZ    33/0!.+> &' 	
'+AA 	
 	
'+A 	
 	
 		 ( 	
 	
	6	
 	
  ,B 	
 	
 		 ,B 	
 	
  `	
 	
 	
 	
 	
 '( 	
B 	
(B. 	
 	
(B 	
 	
 		 ) 	
 	
 		 -/ 	
 	
  P	
 	
 	
 	
 	
 	
r4   N)r   r   r   r   r   r   r   r   r9   r4   r2   r   r   /  s    [
	
).
r4   r   c                  "    e Zd ZdZd Zd Zd Zy)TestForbiddenDiffStillBlocksuP   회귀4: worktree 내 out-of-scope/forbidden 변경 탐지 + fail-closed 원칙.c                   dg}dg}t        ||      }|d   }|t        k(  }|st        j                  d|fd|t        f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}d}|d   }||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}y)uQ   expected 외 파일(terminal_state_callback.py) dirty → EXTERNAL_DIRTY_BLOCKER.r   .scripts/harness/v36/terminal_state_callback.pyr   rg   r   r   r   u8   out-of-scope 변경은 EXTERNAL_DIRTY_BLOCKER 여야 함r   r   Nr   r   z%(py1)s in %(py4)sr   r   r   r   r   s              r2   0test_out_of_scope_file_is_external_dirty_blockerzMTestForbiddenDiffStillBlocks.test_out_of_scope_file_is_external_dirty_blocker~  s   23GH!.+>&' 	
'+AA 	
 	
'+A 	
 	
 		 ( 	
 	
	6	
 	
  ,B 	
 	
 		 ,B 	
 	
  G	
 	
 	
 	
 	
 @\6J[C\\?C\\\\\?C\\\\?\\\C\\\\\\\\r4   c                   dg}ddg}t        ||      }|d   }|t        k(  }|st        j                  d|fd|t        f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd	|iz  }t        t        j                  |            d
x}}d}|d   }||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            d
x}x}}y
)uN   자기 파일 + forbidden 파일 동시 dirty → OWN_DIRTY_FAIL (own 우선).r   r   r   rg   r   r   r   rl   r   Nr   r   r   r   r   r   )
r	   r   r   r    r$   r!   r"   r#   r&   r'   r   s              r2   )test_mixed_own_and_forbidden_detects_bothzFTestForbiddenDiffStillBlocks.test_mixed_own_and_forbidden_detects_both  s    23$<

 ".+> &'9'>9999'>999'999999>999>9999999?\6J[C\\?C\\\\\?C\\\\?\\\C\\\\\\\\r4   c                   t         j                  d      }d|v }|j                  d      }|j                  d|      }|dkD  r||kD  r
||| }d|v }nd}g }|}|s|}|sd	d
dt        j                         v st        j                  |      rt        j                  |      ndiz  }	|j                  |	       |sXdddt        j                         v st        j                  |      rt        j                  |      ndiz  }
|j                  |
       t        j                  |d      i z  }t        j                  d| d|       dz   d|iz  }t        t        j                  |            dx}}y)u   finish-task.sh GIT-GATE 가 dirty 시 fail-closed(exit 1) 원칙 존재 확인.

        정적 grep: '차단 유지 (fail-closed)' 또는 분류 무관 exit 1 패턴 검증.
        r   r   u   차단 유지 (fail-closed)	REAL_DIFFu    uncommitted 변경 없음 확인r   exit 1Fz%(py2)srr   has_failclosed_commentz%(py4)sr   has_exit1_in_dirty_blockr   u\   GIT-GATE dirty 블록에 fail-closed(exit 1) 원칙이 존재해야 함. failclosed_comment=z, exit1_in_dirty_block=rt   ru   N)r   r   findr!   r"   r   r#   r$   append_format_boolopr%   r&   r'   )rx   r)   r   dirty_block_startdirty_block_enddirty_blockr   r/   r   @py_format3r   r1   r{   s                r2   "test_fail_closed_pattern_in_sourcez?TestForbiddenDiffStillBlocks.test_fail_closed_pattern_in_source  s   
 0 "?#!E  HH[1((#EGXYq _7H%H/@K'/;'>$',$	
% 	
%)A 	
 	
 
6		
 	
 	 & 	
 	
 
		 & 	
 	
 
6		
 
	 & 	
 
6		
 	
 	 *B 	
 	
 
		 *B 	
 	
 
6		
 
		
 		
 	
 ""8!9 :$$<#=?	
 	
 	
 		
 	
r4   N)r   r   r   r   r   r   r   r9   r4   r2   r   r   {  s    Z
]]
r4   r   c                  *    e Zd ZdZddZd Zd Zd Zy)(TestMergeBaseScopeIndependentOfLocalMainuP   회귀5: scope diff 가 merge-base..HEAD 기준이면 로컬 main 위치 무관.c                   |dz  j                          i t        j                  dddddfd} |ddd        |d	d
d        |d	dd       dz  j                  d        |dd        |ddd       t	        j
                  ddt              ddgddd      j                  j                         } |ddd       dz  j                  d        |dd        |ddd       |fS )u0   임시 git 저장소 생성, 커밋 2개 추가.testrepotestt@t.comGIT_AUTHOR_NAMEGIT_AUTHOR_EMAILGIT_COMMITTER_NAMEGIT_COMMITTER_EMAILc                 h    t        j                  ddt              gt        |       z   ddd      S Ngit-CTrC   rD   envcheckrI   rJ   ro   listrQ   r  repos    r2   r   zITestMergeBaseScopeIndependentOfLocalMain._make_temp_git_repo.<locals>.git  s7    >>c$i(4:5# r4   init-bmainconfig
user.email	user.namebase.txtbaseaddcommit-mzbase commit Ar   r   	rev-parseHEADTrC   rD   r  checkouttask-branchwork.txtworkzwork commit B)	rw   rN   environr   rI   rJ   ro   rK   rL   )rx   ry   r   r   r  r  s       @@r2   _make_temp_git_repoz<TestMergeBaseScopeIndependentOfLocalMain._make_temp_git_repo  s	   *$

O OI%+IO	 	FD&!HlI.Hk6* 

	&&v.E:HdO, >>D#d)[&9d$
 & 	 	Jm,	
	&&v.E:HdO,X~r4   c                    | j                  |      \  }}t        j                  ddt        |      d|dgdd      }|j                  j                         }|j                  }d}||k(  }|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d|dd  d|dd        dz   d|iz  }t        t        j                  |            d}y)u/   merge-base(base, HEAD) 가 base SHA 와 동일.r   r   
merge-baser  TrB   r   rg   z2%(py2)s
{%(py2)s = %(py0)s.returncode
} == %(py5)srY   r   rr   r   assert %(py7)sru   N)z%(py0)s == %(py2)smerge_base_shar   r   rr   u   merge-base 가 base commit SHA    u    여야 하지만 
>assert %(py4)sr   )r  rI   rJ   ro   rK   rL   rM   r   r    r!   r"   r#   r$   r&   r'   r%   )rx   ry   r  r   rY   r!  r/   rz   r   r1   r{   r   r   s                r2    test_merge_base_returns_base_shazITestMergeBaseScopeIndependentOfLocalMain.test_merge_base_returns_base_sha  s   11(;hNND#d)\8VDd
 )|| q |q    |q      q   q   |   q       ) 	
 	
~ 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
  "* 	
 	
 		 "* 	
 	
  .hrl^;Mn]_^_N`Mab	
 	
 	
 	
 	
r4   c           
       
 | j                  |      \  }i t        j                  ddddd

fd} |d|d      j                  j	                         } |ddd	d        |d|d      j                  j	                         }||k(  }||k(  }|r|s1t        j                  d
||fd|||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d|dd  d|dd  d|dd        dz   d|iz  }	t        t        j                  |	            dx}}y)uL   로컬 main 브랜치가 어디 있든 merge-base(base, HEAD) 결과 동일.r   r   r   c                 f    t        j                  ddt              gt        |       z   dd      S )Nr   r   TrC   rD   r  r  r  s    r2   r   zhTestMergeBaseScopeIndependentOfLocalMain.test_merge_base_independent_of_local_main_position.<locals>.git  s2    >>c$i(4:5#$C r4   r  r  branchz-fr
  )rh   rh   )rj   z%(py3)s == %(py4)smb1mb2r   )r   r   r   u6   로컬 main 위치 무관하게 merge-base 는 항상 Nr#  u    여야 함. mb1=z, mb2=r   r   )r  rN   r  rK   rL   r   r    r!   r"   r#   r$   r%   r&   r'   )rx   ry   r   r   r*  r+  r/   r.   r   r   r  r  s             @@r2   2test_merge_base_independent_of_local_main_positionz[TestMergeBaseScopeIndependentOfLocalMain.test_merge_base_independent_of_local_main_position  s   11(;hO OI%+IO	 ,&188>>@ 	HdFF+ ,&188>>@c% 	
cX% 	
 	
 	
scX 	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
6	
 	
  & 	
 	
 
	 & 	
 	
  EXbq\N Sr7)6#bq',	
 	
 	
 	
 	
r4   c           	        | j                  |      \  }}t        j                  ddt        |      dd| dgdd      }|j                  j                         D cg c]#  }|j                         s|j                         % }}d}||v }|st        j                  d	|fd
||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }	t        j                  d      dz   d|	iz  }
t        t        j                  |
            dx}}d}||v}|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }	t        j                  d      dz   d|	iz  }
t        t        j                  |
            dx}}yc c}w )u<   merge-base..HEAD diff 가 브랜치 추가 파일만 포함.r   r   diffz--name-onlyz..HEADTrB   r  r   r   
diff_filesr   uC   브랜치에서 추가한 work.txt 가 diff 에 포함되어야 함r   r   Nr  not inz%(py1)s not in %(py3)su3   base commit 의 base.txt 는 diff 에 없어야 함)r  rI   rJ   ro   rK   
splitlinesrL   r   r    r$   r!   r"   r#   r%   r&   r'   )rx   ry   r  r   rY   rW   r/  r   r.   r0   r1   s              r2   1test_merge_base_diff_captures_only_branch_commitszZTestMergeBaseScopeIndependentOfLocalMain.test_merge_base_diff_captures_only_branch_commits  sD   11(;hNND#d)V]xj<OPd
 *+)<)<)>LA!'')aggiL
LnzZ'nnnzZnnnznnnnnnZnnnZnnnn)nnnnnnnbz+bbbzbbbzbbbbbbbbbbbbb-bbbbbbb Ms   G<1G<N)ry   r   returnztuple[Path, str])r   r   r   r   r  r%  r,  r4  r9   r4   r2   r   r     s    Z%N

8cr4   r   c                  6    e Zd ZdZd	dZd Zd Zd Zd Zd Z	y)
TestFlagOffPreservesLegacyuV   회귀6: FINISH_TASK_WORKTREE_STRICT 미설정(default 0) 시 레거시 경로 보존.c                .    t         j                  d      S )Nr   r   )r   r   rx   s    r2   _get_srcz#TestFlagOffPreservesLegacy._get_src!  s    11r4   c                   | j                         }d}||v }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }t        j                  d      dz   d|iz  }t        t        j                  |            d	x}}y	)
u=   FINISH_TASK_WORKTREE_STRICT 기본값 0 설정 라인 존재.z?FINISH_TASK_WORKTREE_STRICT="${FINISH_TASK_WORKTREE_STRICT:-0}"r   r   r)   r   u0   feature flag 기본값 0 설정 라인이 없음r   r   N
r:  r   r    r$   r!   r"   r#   r%   r&   r'   rx   r)   r   r.   r0   r1   s         r2   test_default_flag_is_zeroz4TestFlagOffPreservesLegacy.test_default_flag_is_zero$  s    mmoP 	
PTWW 	
 	
PTW 	
 	
 		 Q 	
 	
	6	
 	
  UX 	
 	
 		 UX 	
 	
  ?	
 	
 	
 	
 	
r4   c                   | j                         }d}t        j                  ||t        j                        }d}||u}|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }t	        j                  d      dz   d	|iz  }t        t	        j                  |            dx}}y)
uM   else 분기(strict OFF)에 SCOPE_PROJ_DIR=${PROJECT_PATH:-$WORKSPACE} 존재.z<else\b[^}]*?SCOPE_PROJ_DIR="\$\{PROJECT_PATH:-\$WORKSPACE\}"Nr   r   matchr   uP   else 분기에 SCOPE_PROJ_DIR="${PROJECT_PATH:-$WORKSPACE}" 가 존재해야 함r   r   )r:  researchDOTALLr   r    r!   r"   r#   r$   r%   r&   r'   )rx   r)   patternr@  r.   r/   r0   r1   s           r2   )test_legacy_scope_proj_dir_in_else_branchzDTestFlagOffPreservesLegacy.test_legacy_scope_proj_dir_in_else_branch+  s    mmo R		'3		2  	
uD  	
 	
uD 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 ! 	
 	
  a	
 	
 	
 	
 	
r4   c                   | j                         }|j                  d      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d| d      d	z   d
|iz  }t        t        j                  |            dx}}y)uS   SCOPE_PROJ_DIR=${PROJECT_PATH:-$WORKSPACE} 가 정확히 1회 존재 (else 분기).z,SCOPE_PROJ_DIR="${PROJECT_PATH:-$WORKSPACE}"r   rg   ri   countr   uB   SCOPE_PROJ_DIR 레거시 할당이 정확히 1회여야 하지만 u
   회 발견r   r   N)r:  rG  r   r    r!   r"   r#   r$   r%   r&   r'   )rx   r)   rG  r.   r/   r0   r1   s          r2   /test_legacy_scope_proj_dir_exactly_once_in_elsezJTestFlagOffPreservesLegacy.test_legacy_scope_proj_dir_exactly_once_in_else6  s    mmo		HI 	
uz 	
 	
u 	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
  QQVPWWab	
 	
 	
 	
 	
r4   c                   | j                         }d}||v }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }t        j                  d      dz   d|iz  }t        t        j                  |            d	x}}y	)
u;   else 분기에 WORK_DIR=${PROJECT_PATH:-$WORKSPACE} 존재.z&WORK_DIR="${PROJECT_PATH:-$WORKSPACE}"r   r   r)   r   uJ   else 분기에 WORK_DIR="${PROJECT_PATH:-$WORKSPACE}" 가 존재해야 함r   r   Nr<  r=  s         r2   #test_legacy_work_dir_in_else_branchz>TestFlagOffPreservesLegacy.test_legacy_work_dir_in_else_branch>  s    mmo7 	
73> 	
 	
73 	
 	
 		 8 	
 	
	6	
 	
  <? 	
 	
 		 <? 	
 	
  [	
 	
 	
 	
 	
r4   c                D   t        j                  ddt        t              gdd      }|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d	z  }t        j                  d
|j                   d|j                         dz   d|iz  }t        t        j                  |            dx}x}}y)u1   bash -n 으로 finish-task.sh 구문 검사 rc=0.rA   z-nTrB   r   rg   r  rY   r  u!   bash -n 구문 검사 실패 (rc=z):
rt   ru   N)rI   rJ   ro   r   rM   r   r    r!   r"   r#   r$   r%   stderrr&   r'   )rx   rY   r/   rz   r   r1   r{   s          r2   test_bash_syntax_checkz1TestFlagOffPreservesLegacy.test_bash_syntax_checkE  s    NNT3v;'

 || 	
q 	
|q  	
 	
|q 	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
 		  ! 	
 	
  0~T!((L	
 	
 	
 	
 	
 	
r4   N)r5  ro   )
r   r   r   r   r:  r>  rE  rH  rJ  rM  r9   r4   r2   r7  r7    s#    `2
	


	
r4   r7  c                  J    e Zd ZdZddZd ZddZd Zd Zd Z	d Z
d	 Zd
 Zy)$TestMainBranchDetectionMasterDefaultua   회귀7: origin/main 하드코딩 제거. master-default repo 에서도 merge-base 계산 동작.c                v    t        j                  ddt        |      dddgdd      j                  }|dk(  rdS d	S )
u]   finish-task.sh 의 감지 로직과 동일: 로컬 main ref 있으면 main, 없으면 master.r   r   r  z--verifyr
  TrB   r   master)rI   rJ   ro   rM   )rx   r  rk   s      r2   _detect_main_branchz8TestMainBranchDetectionMasterDefault._detect_main_branchY  sF    ^^D#d)[*fEd
 * 	 qv.h.r4   c                4    i t         j                  dddddS )Nr   r   r   )rN   r  r9  s    r2   _git_envz-TestMainBranchDetectionMasterDefault._git_enva  s)    P"** PY&,YP 	Pr4   c           
     f   | j                         fd}|dz  }|j                          t        j                  dddd|t	        |      gddd       |d	z  }|j                          t        j                  ddd|t	        |      gddd        ||d
dd        ||d
dd       |dz  j                  d        ||dd        ||ddd        ||dddt	        |              ||dd|       |dz  }t        j                  ddt	        |      t	        |      gddd        ||d
dd        ||d
dd       t        j                  ddt	        |      ddgddd      j                  j                         } ||ddd       |dz  j                  d         ||dd        ||ddd!       ||fS )"uW   origin(bare) + clone 구성. default_branch=main|master. (clone_repo, base_sha) 반환.c                h    t        j                  ddt        |       gt        |      z   ddd      S r   r  )r  rQ   r  s     r2   gzFTestMainBranchDetectionMasterDefault._make_repo_with_origin.<locals>.gi  s6    >>5$D	":T$Z"G15DcQUW Wr4   z
origin.gitr   r  z--barer	  Tr  seedr  r  r   r  r   r  r  r  r  r  zbase commitremoteoriginpushcloner   r  r  r  r  r  r  r  zwork commit)rT  rw   rI   rJ   ro   r   rK   rL   )	rx   ry   default_branchrW  rZ  rX  r\  r   r  s	           @r2   _make_repo_with_originz;TestMainBranchDetectionMasterDefault._make_repo_with_origine  s   mmo	W L(vx~s6{S&*3d	L & 

vt^SYG&*3d	L	$,	2	$+v.	
	&&v.	$z"	$$.	$%3v;7	$.17"wFSZ@&*3d	L	%<3	%;/>>5$E
K"P15DNNTfUZUZU\ 	 	
%T=1		''/	%
#	%4/hr4   c                ~   | j                  |d      \  }}| j                  } ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            d	x}x}x}}y	)
uG   master-default repo (로컬 main 없음) → MAIN_BRANCH=master 감지.rQ  rg   zY%(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s._detect_main_branch
}(%(py3)s)
} == %(py8)srx   r\  r   rr   r   r   py8assert %(py10)spy10N
r^  rR  r   r    r!   r"   r#   r$   r&   r'   
rx   ry   r\  r   r/   rz   @py_assert7@py_assert6@py_format9@py_format11s
             r2   #test_detect_master_when_main_absentzHTestMainBranchDetectionMasterDefault.test_detect_master_when_main_absent  s    ..xBq'':'.:(:.(::::.(::::::t:::t:::'::::::::::::.:::(:::::::r4   c                ~   | j                  |d      \  }}| j                  } ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            d	x}x}x}}y	)
u.   main-default repo → MAIN_BRANCH=main 감지.r
  rg   r`  rx   r\  ra  rc  rd  Nre  rf  s
             r2   test_detect_main_when_presentzBTestMainBranchDetectionMasterDefault.test_detect_main_when_present  s    ..x@q''8'.8&8.&8888.&888888t888t888'888888888888.888&8888888r4   c                V   | j                  |d      \  }}| j                         }t        j                  ddt	        |      ddgdd|      j
                  }d}||k7  }|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d      dz   d|iz  }	t        t        j                  |	            dx}}| j                  |      }
d}|
|k(  }|st        j                  d|fd|
|f      dt        j                         v st        j                  |
      rt        j                  |
      ndt        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}}t        j                  ddt	        |      dd|
 dgdd|      }|j
                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	t        j                  d|
 d|j                          dz   d|	iz  }t        t        j                  |            dx}x}}|j"                  }|j$                  } |       }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndd z  }t        j                  d!      d"z   d#|iz  }t        t        j                  |            dx}x}x}}y)$uf   master-default repo: origin/main 부재여도 origin/${MAIN_BRANCH}=origin/master 로 merge-base PASS.rQ  r   r   r  origin/mainTr(  r   r   )z%(py0)s != %(py3)src_mainr   u9   master-default repo 에 origin/main 이 있으면 안 됨r   r   Nrg   ri   mbrl   r  origin/r  r  rY   r  u    merge-base 실패: rt   ru   z`%(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.stdout
}.strip
}()
} == %(py8)sr   r   rr   r   r   rb  u,   merge-base 가 base SHA 와 일치해야 함z
>assert %(py10)srd  )r^  rT  rI   rJ   ro   rM   r   r    r!   r"   r#   r$   r%   r&   r'   rR  rL  rK   rL   )rx   ry   r\  r   r  rp  r.   r/   r0   r1   rq  rY   rz   r   r{   @py_assert5rg  ri  rj  s                      r2   :test_merge_base_with_origin_master_when_origin_main_absentz_TestMainBranchDetectionMasterDefault.test_merge_base_with_origin_master_when_origin_main_absent  s   55hIxmmo..%s5z;!V044SJJT* 	Xw!|XXXw!XXXXXXwXXXwXXX!XXXXXXXXXX%%e,rX~rXrrXNNE4U\WRD>SYZ*.TsD||NqN|q NNN|qNNNNNNqNNNqNNN|NNNqNNNGB4/CAHH:"NNNNNNNNxx[x~~[~[8+[[[8[[[[[[q[[[q[[[x[[[~[[[[[[[[[8[[[8[[[[-[[[[[[[[r4   c                   | j                  |d      \  }}| j                         }| j                  |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}}t        j                  d	d
t        |      dd| dgdd|      }
|
j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |
      rt        j                  |
      ndt        j                  |      t        j                  |      dz  }	dd|	iz  }t        t        j                  |            dx}x}}|
j                  }|j                   } |       }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |
      rt        j                  |
      ndt        j                  |      t        j                  |      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            dx}x}x}}y)uM   main-default repo: origin/main 으로 merge-base PASS (기존 동작 유지).r
  rg   ri   rq  r   rl   r   Nr   r   r  rr  r  Tr(  r   r  rY   r  r   ru   rs  r   rt  rc  rd  )r^  rT  rR  r   r    r!   r"   r#   r$   r&   r'   rI   rJ   ro   rM   rK   rL   )rx   ry   r\  r   r  rq  r.   r/   r0   r1   rY   rz   r   r{   ru  rg  ri  rj  s                     r2   0test_merge_base_with_origin_main_in_main_defaultzUTestMainBranchDetectionMasterDefault.test_merge_base_with_origin_main_in_main_default  s   55hGxmmo%%e,rV|rVrrVNNE4U\WRD>SYZ*.TsD|| q |q    |q      q   q   |   q       xx+x~~+~+8++++8++++++q+++q+++x+++~+++++++++8+++8++++++++r4   c                   t         j                  d      }t        j                  dd|      }d}||v}|st	        j
                  d|fd||f      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      ndd	z  }t	        j                  d
      dz   d|iz  }t        t	        j                  |            dx}}y)uC   finish-task.sh 코드(주석 제외)에 origin/main 리터럴 0건.r   r   z#.*r   ro  r0  r2  coder   u:   코드 경로에 origin/main 하드코딩이 남아 있음r   r   N)r   r   rA  subr   r    r$   r!   r"   r#   r%   r&   r'   rx   r)   rz  r   r.   r0   r1   s          r2   'test_source_has_no_origin_main_hardcodezLTestMainBranchDetectionMasterDefault.test_source_has_no_origin_main_hardcode  s    0vvfb#&f}D(fff}Dfff}ffffffDfffDffff*fffffffr4   c                R   t         j                  d      }g }d}||v }|}|sd}||v }|}|snt        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }d	d
|iz  }	|j                  |	       |st        j                  dfd|f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }
dd|
iz  }|j                  |       t        j                  |d      i z  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}x}x}x}x}}y)uA   finish-task.sh 가 origin/${MAIN_BRANCH} 변수 형태를 사용.r   r   zorigin/${MAIN_BRANCH}zorigin/$MAIN_BRANCHr   )z%(py3)s in %(py5)sr)   )r   r   z%(py7)sru   )z%(py10)s in %(py12)s)rd  py12z%(py14)spy14r   u-   origin/${MAIN_BRANCH} 사용 패턴이 없음z
>assert %(py17)spy17N)r   r   r   r    r$   r!   r"   r#   r   r   r%   r&   r'   )rx   r)   r/   r.   rz   r   @py_assert9@py_assert11r1   r{   @py_format13@py_format15@py_format16@py_format18s                 r2   'test_source_uses_origin_main_branch_varzLTestMainBranchDetectionMasterDefault.test_source_uses_origin_main_branch_var  sy   0	
& 	
&#- 	
1F 	
1F#1M 	
 	
 	
&# 	
 	
 		 ' 	
 	
	6	
 	
  +. 	
 	
 		 +. 	
 	
 	
	6	
		
 	
1F# 	
 	
 		 2G 	
 	
	6	
 	
  KN 	
 	
 		 KN 	
 	
 	
	6	
		
 	
 	
  <	
 	
 	
 	
 	
 	
r4   N)r  r   r5  ro   )ry   r   r]  ro   )r   r   r   r   rR  rT  r^  rk  rm  rv  rx  r}  r  r9   r4   r2   rO  rO  V  s6    k/P%N;
9
\	,g
r4   rO  c                  @    e Zd ZdZed	d       Zd Zd Zd Zd Z	d Z
y)
"TestStrictScopeBaseEmptyFailClosedu  회귀7: STRICT scope-gate 에서 SCOPE_BASE 미감지 시 fail-OPEN 금지, fail-closed.

    배경: merge-base(origin/${MAIN_BRANCH}, HEAD) + worktree-base.json fallback 모두
    실패해 SCOPE_BASE 가 비었을 때, 과거엔 `: > "$SCOPE_DIFF_FILE"`(빈 diff)로 scope
    검증을 스킵 = fail-OPEN 이었음. round-3 bounded fix 로 명시적 fail-closed(exit 1)로
    교체됨. 정적 소스 패턴 검증으로 회귀 방지.
    c                R    | j                  d      }| j                  d|      }| || S )uY   STRICT scope-gate 블록(SCOPE_BASE merge-base ~ non-strict else 직전)을 슬라이스.z0SCOPE_BASE=$(git -C "$SCOPE_PROJ_DIR" merge-basez@git -C "$SCOPE_PROJ_DIR" diff --name-only "${MAIN_BRANCH}..HEAD"r   r)   r*   r   s      r2   _strict_blockz0TestStrictScopeBaseEmptyFailClosed._strict_block  s5     		LMiiNPU
 5~r4   c                   t         j                  d      }| j                  |      }d}||v}|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y)uS   STRICT 블록 내에 빈-diff fail-OPEN(`: > "$SCOPE_DIFF_FILE"`)이 없어야 함.r   r   z: > "$SCOPE_DIFF_FILE"r0  r2  strict_blockr   u   STRICT scope-gate SCOPE_BASE empty 분기에 빈-diff fail-OPEN (빈 diff redirect)이 잔존함 — fail-closed 로 교체되어야 함r   r   Nr   r   r  r   r    r$   r!   r"   r#   r%   r&   r'   rx   r)   r  r   r.   r0   r1   s          r2   3test_strict_empty_scope_base_no_empty_diff_failopenzVTestStrictScopeBaseEmptyFailClosed.test_strict_empty_scope_base_no_empty_diff_failopen  s    0))#.' 	
'|; 	
 	
'| 	
 	
 
	 ( 	
 	
 
6	
 	
  0< 	
 	
 
	 0< 	
 	
 W	
 	
 	
 	
 	
r4   c                   t         j                  d      }| j                  |      }d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}d|v xs d|v }|s{t        j                  d      dz   ddt        j                         v st        j                  |      rt        j
                  |      ndiz  }t        t        j                  |            y)uL   STRICT 블록 내에 exit 1 + fail-closed 신호가 모두 존재해야 함.r   r   r   r   r   r  r   u:   STRICT scope-gate 블록에 exit 1(fail-closed) 이 없음r   r   Nfail-closedr   uy   STRICT scope-gate 블록에 fail-closed 신호('fail-closed' 문자열 또는 _emit_worktree_unresolved 호출)가 없음
>assert %(py0)sr   has_failclosed_signalr  )	rx   r)   r  r   r.   r0   r1   r  @py_format1s	            r2   -test_strict_empty_scope_base_exits_failclosedzPTestStrictScopeBaseEmptyFailClosed.test_strict_empty_scope_base_exits_failclosed  sJ   0))#. 	
x<' 	
 	
x< 	
 	
 		  	
 	
	6	
 	
  ( 	
 	
 		 ( 	
 	
  I	
 	
 	
 	
 	
 \) ;*l: 	 % 	
 :	
 	
 
6	
 	
  % 	
 	
 
	 % 	
 	
 	
 	
 	
$r4   c                   t         j                  d      }| j                  |      }d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y)u^   STRICT 블록에 valid SCOPE_BASE 경로(diff --name-only "${SCOPE_BASE}..HEAD")가 보존됨.r   r   z&diff --name-only "${SCOPE_BASE}..HEAD"r   r   r  r   uI   STRICT scope-gate 의 valid SCOPE_BASE diff 경로가 보존되어야 함r   r   Nr  r  s          r2   +test_strict_valid_scope_base_generates_diffzNTestStrictScopeBaseEmptyFailClosed.test_strict_valid_scope_base_generates_diff  s    0))#.7 	
7<G 	
 	
7< 	
 	
 		 8 	
 	
	6	
 	
  <H 	
 	
 		 <H 	
 	
  X	
 	
 	
 	
 	
r4   c                   t         j                  d      }d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y)u[   non-strict 레거시 경로(${MAIN_BRANCH}..HEAD + HEAD~1 fallback)가 보존됨 (회귀3).r   r   z'diff --name-only "${MAIN_BRANCH}..HEAD"r   r   r)   r   u[   non-strict 레거시 ${MAIN_BRANCH}..HEAD 경로가 사라짐 — default-off 호환 깨짐r   r   Nzdiff --name-only HEAD~1uV   non-strict 레거시 HEAD~1 fallback 경로가 사라짐 — default-off 호환 깨짐r   r   r   r    r$   r!   r"   r#   r%   r&   r'   r=  s         r2   $test_nonstrict_legacy_path_preservedzGTestStrictScopeBaseEmptyFailClosed.test_nonstrict_legacy_path_preserved  sU   08 	
8C? 	
 	
8C 	
 	
 		 9 	
 	
	6	
 	
  =@ 	
 	
 		 =@ 	
 	
  j	
 	
 	
 	
 	
 ) 	
(C/ 	
 	
(C 	
 	
 		 ) 	
 	
	6	
 	
  -0 	
 	
 		 -0 	
 	
  e	
 	
 	
 	
 	
r4   c                   t         j                  d      }d}||v}|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      nddt	        j
                         v st        j                  |      rt        j                  |      nddz  }t        j                  d	      d
z   d|iz  }t        t        j                  |            d}y)u/   ANU key 리터럴 노출 0건 (회귀9 보강).r   r   c119085addb0f8b7r0  )z%(py0)s not in %(py2)s_anu_keyr)   r"  u(   ANU key 리터럴이 소스에 노출됨r$  r   N)r   r   r   r    r!   r"   r#   r$   r%   r&   r'   )rx   r)   r  r/   r   r   s         r2   test_no_anu_key_literalz:TestStrictScopeBaseEmptyFailClosed.test_no_anu_key_literal   s    0*s"NNNxsNNNNNNxNNNxNNNNNNsNNNsNNNN$NNNNNNNr4   Nr)   ro   r5  ro   )r   r   r   r   staticmethodr  r  r  r  r  r  r9   r4   r2   r  r    s5      

 

Or4   r  c                  .    e Zd ZdZedd       Zd Zd Zy)TestStrictNonGitFailCloseduA  회귀8: STRICT 에서 SCOPE_PROJ_DIR 가 git repo 아니면 fail-OPEN(스킵) 금지, fail-closed(exit 1).

    근거: PR #171 fresh HIGH-1 (line 540 non-git → 검증 스킵 = fail-open 잔여 분기).
    round-3 가 닫은 SCOPE_BASE empty 와 같은 fail-open family. 정적 소스 패턴으로 회귀 방지.
    c                R    | j                  d      }| j                  d|      }| || S )uX   non-git 분기(rev-parse --git-dir 실패 ~ SCOPE_DIFF_FILE 정의 직전) 슬라이스.z1if ! git -C "$SCOPE_PROJ_DIR" rev-parse --git-dirzSCOPE_DIFF_FILE="$EVENTS_DIRr  r  s      r2   _nongit_blockz(TestStrictNonGitFailClosed._nongit_block  s0     		MNii6>5~r4   c                L   t         j                  d      }| j                  |      }d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}d|v xs d|v }|s{t        j                  d      dz   ddt        j                         v st        j                  |      rt        j
                  |      ndiz  }t        t        j                  |            y)uE   non-git 분기에 STRICT 가드 + exit 1 + fail-closed 신호 존재.r   r   "FINISH_TASK_WORKTREE_STRICT" = "1"r   r   blockr   u)   non-git 분기에 STRICT 가드가 없음r   r   Nr   u7   STRICT non-git 분기에 exit 1(fail-closed) 이 없음r   r  ue   STRICT non-git 분기에 fail-closed 신호(_emit_worktree_unresolved 또는 'fail-closed')가 없음r  r   
has_signalr   r   r  r   r    r$   r!   r"   r#   r%   r&   r'   	rx   r)   r  r   r.   r0   r1   r  r  s	            r2   $test_strict_nongit_exits_fail_closedz?TestStrictNonGitFailClosed.test_strict_nongit_exits_fail_closed  s   0""3'3 	
3u< 	
 	
3u 	
 	
 		 4 	
 	
	6	
 	
  8= 	
 	
 		 8= 	
 	
  8	
 	
 	
 	
 	
 [x5 [[[x5[[[x[[[[[[5[[[5[[[["[[[[[[[0E9S]e=S
 	
  t	
 	
	6	
 	
   	
 	
 		  	
 	
 	
 	
 	
zr4   c                   t         j                  d      }| j                  |      }d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y)uK   non-strict(레거시)에선 'not a git repo — 검증 스킵' echo 보존.r   r   u    not a git repo — 검증 스킵r   r   r  r   uR   non-strict 레거시 non-git SKIP echo 가 사라짐 — default-off 호환 깨짐r   r   Nr  rx   r)   r  r   r.   r0   r1   s          r2   $test_nonstrict_nongit_preserves_skipz?TestStrictNonGitFailClosed.test_nonstrict_nongit_preserves_skip'  s    0""3'1 	
1U: 	
 	
1U 	
 	
 		 2 	
 	
	6	
 	
  6; 	
 	
 		 6; 	
 	
  a	
 	
 	
 	
 	
r4   Nr  )r   r   r   r   r  r  r  r  r9   r4   r2   r  r    s%      

r4   r  c                  .    e Zd ZdZedd       Zd Zd Zy)TestStrictDiffEmptyFailClosedu  회귀9: STRICT 에서 scope diff 비어있음 → fail-OPEN(스킵) 금지, fail-closed(exit 1).

    근거: ANU 전수 audit (line 569 'diff 비어있음 — 검증 스킵' fail-open 후보).
    STRICT 스킵 분기 전수 fail-closed 일관화. non-strict 는 SKIP 보존.
    c                R    | j                  d      }| j                  d|      }| || S )uY   diff-empty 분기(! -s SCOPE_DIFF_FILE ~ task-scope-guard.sh 호출 직전) 슬라이스.z$if [ ! -s "$SCOPE_DIFF_FILE" ]; thenztask-scope-guard.shr  r  s      r2   _diffempty_blockz.TestStrictDiffEmptyFailClosed._diffempty_block;  s0     		@Aii-u55~r4   c                L   t         j                  d      }| j                  |      }d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}d|v xs d|v }|s{t        j                  d      dz   ddt        j                         v st        j                  |      rt        j
                  |      ndiz  }t        t        j                  |            y)uH   diff-empty 분기에 STRICT 가드 + exit 1 + fail-closed 신호 존재.r   r   r  r   r   r  r   u,   diff-empty 분기에 STRICT 가드가 없음r   r   Nr   u:   STRICT diff-empty 분기에 exit 1(fail-closed) 이 없음r   r  u8   STRICT diff-empty 분기에 fail-closed 신호가 없음r  r   r  r   r   r  r   r    r$   r!   r"   r#   r%   r&   r'   r  s	            r2   (test_strict_diff_empty_exits_fail_closedzFTestStrictDiffEmptyFailClosed.test_strict_diff_empty_exits_fail_closedB  sy   0%%c*3 	
3u< 	
 	
3u 	
 	
 		 4 	
 	
	6	
 	
  8= 	
 	
 		 8= 	
 	
  ;	
 	
 	
 	
 	
 ^x5 ^^^x5^^^x^^^^^^5^^^5^^^^"^^^^^^^0E9S]e=S
UUUUUUUUUzUUUzUUUUUzr4   c                   t         j                  d      }| j                  |      }d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y)uN   non-strict(레거시)에선 'diff 비어있음 — 검증 스킵' echo 보존.r   r   u#   diff 비어있음 — 검증 스킵r   r   r  r   uU   non-strict 레거시 diff-empty SKIP echo 가 사라짐 — default-off 호환 깨짐r   r   Nr  r  s          r2   (test_nonstrict_diff_empty_preserves_skipzFTestStrictDiffEmptyFailClosed.test_nonstrict_diff_empty_preserves_skipM  s    0%%c*4 	
4= 	
 	
4 	
 	
 		 5 	
 	
	6	
 	
  9> 	
 	
 		 9> 	
 	
  d	
 	
 	
 	
 	
r4   Nr  )r   r   r   r   r  r  r  r  r9   r4   r2   r  r  4  s&      	V
r4   r  c                  "    e Zd ZdZd Zd Zd Zy)TestNoHomeJayHardcodeu   회귀10: finish-task.sh 코드경로에 /home/jay 리터럴 0 + env/expanduser 주입.

    근거: PR #171 fresh HIGH-2 (line 8 WORKSPACE + line 56 cokacdir glob /home/jay 하드코딩).
    WORKSPACE_ROOT_HARDCODE 계열 재발 방지.
    c                   t         j                  d      }dj                  d |j                         D              }d}||v}|st	        j
                  d|fd||f      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      ndd	z  }t	        j                  d
      dz   d|iz  }t        t	        j                  |            dx}}y)uT   주석 제외 코드에 /home/jay 리터럴 0건 (goal_assertion 과 동일 기준).r   r   r=   c              3  `   K   | ]&  }|j                         j                  d       r#| ( yw)#N)rL   
startswith)r:   ls     r2   r<   zITestNoHomeJayHardcode.test_no_home_jay_literal_in_code.<locals>.<genexpr>d  s$     VqAGGI<P<PQT<UVs   $..z	/home/jayr0  r2  rz  r   u8   코드 경로에 /home/jay 하드코딩이 남아 있음r   r   N)r   r   rE   r3  r   r    r$   r!   r"   r#   r%   r&   r'   r|  s          r2    test_no_home_jay_literal_in_codez6TestNoHomeJayHardcode.test_no_home_jay_literal_in_codea  s    0yyVCNN$4VVb{$&bbb{$bbb{bbbbbb$bbb$bbbb(bbbbbbbr4   c                   t         j                  d      }d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y)uF   WORKSPACE 가 ${WORKSPACE:-$HOME/workspace} env/default 주입 형태.r   r   z)WORKSPACE="${WORKSPACE:-$HOME/workspace}"r   r   r)   r   u-   WORKSPACE env/default 주입 라인이 없음r   r   Nr  r=  s         r2   $test_workspace_uses_home_env_defaultz:TestNoHomeJayHardcode.test_workspace_uses_home_env_defaultg  s    0: 	
:cA 	
 	
:c 	
 	
 		 ; 	
 	
	6	
 	
  ?B 	
 	
 		 ?B 	
 	
  <	
 	
 	
 	
 	
r4   c                   t         j                  d      }d|v xs d|v }|s{t        j                  d      dz   ddt	        j
                         v st        j                  |      rt        j                  |      ndiz  }t        t        j                  |            d	}||v}|st        j                  d
|fd||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}}y)ua   _resolve_task_worktree 의 .cokacdir glob 가 expanduser('~') 기반, /home/jay/.cokacdir 부재.r   r   zos.path.expanduser('~')zos.path.expanduser("~")u'   expanduser('~') 사용 패턴이 없음r  r   has_expanduserz/home/jay/.cokacdirr0  r2  r)   r   u/   cokacdir glob 에 /home/jay 하드코딩 잔존r   r   N)r   r   r   r%   r!   r"   r#   r$   r&   r'   r    )rx   r)   r  r  r   r.   r0   r1   s           r2   *test_resolver_uses_expanduser_for_cokacdirz@TestNoHomeJayHardcode.test_resolver_uses_expanduser_for_cokacdirn  s    0%,P0IS0P 	 HHHHHHHHH~HHH~HHHHH$b$C/bbb$Cbbb$bbbbbbCbbbCbbbb1bbbbbbbr4   N)r   r   r   r   r  r  r  r9   r4   r2   r  r  Z  s    c
cr4   r  )r(   ro   r5  ro   )
rP   ro   rQ   z	list[str]rR   ro   rS   ro   r5  ztuple[str, int])*r   
__future__r   builtinsr!   _pytest.assertion.rewrite	assertionrewriter   r   rN   rA  rI   sysrF   pathlibr   __file__resolverd   REPOr   pathinsertro   utils.dirty_registryr   r   r	   r3   rZ   r\   r   r   r   r   r7  rO  r  r  r  r  r9   r4   r2   <module>r     s9   #    	 	  
   H~''*			,	, 3t9  &
  	
 <?` ?`LD DVE
 E
X5
 5
x`c `cN0
 0
pe
 e
XCO COT!
 !
P
 
Lc cr4   