
    i:)                        d 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mZ  ed      Z ee      e
j                   vr"e
j                   j#                  d ee             dedefdZ eded	z  d
z  dz  dz        Z eded	z  d
z  dz  dz        Z ededz  dz        ZdededefdZd Zd Zd Zd Zd Zd ZdededefdZdededefdZd  Z d! Z!d" Z"y)#u  
test_verifier_fix_pack.py — task-2381 verifier 3건 통합 fix 회귀 테스트

대상 fix:
- Fix 1: teams.shared.verifiers.git_evidence — _resolve_project_dir nested lookup
- Fix 2: teams.shared.verifiers.critical_gap — 정규식 + 마커 패턴
- Fix 3: scripts.auto_merge — _sync_task_timers helper

작성: 모리건 (dev3 테스터)
원칙: TDD RED-first. 루의 구현이 끝난 뒤 GREEN 검증.
    N)Pathz-/home/jay/workspace/.worktrees/task-2381-dev3name	file_pathc                 0   t         j                  j                  | t        |            }||j                  t        d|  d|       t         j                  j                  |      }|t        j                  | <   |j                  j                  |       |S )NzCannot load z from )
	importlibutilspec_from_file_locationstrloaderImportErrormodule_from_specsysmodulesexec_module)r   r   specmodules       8/home/jay/workspace/tests/dev3/test_verifier_fix_pack.py_load_moduler      s{    >>11$IGD|t{{*LfYK@AA^^,,T2FCKKKKF#M    git_evidence_t2381teamsshared	verifierszgit_evidence.pycritical_gap_t2381zcritical_gap.pyauto_merge_t2381scriptszauto_merge.py	workspacepayloadreturnc                     | dz  }|j                  dd       |dz  }|j                  t        j                  |dd      d	       |S )
NmemoryT)parentsexist_oktask-timers.jsonF   )ensure_asciiindentutf-8encoding)mkdir
write_textjsondumps)r   r   
memory_dirtimerss       r   _write_timersr1   8   sP    X%JTD1,,F
djjuQGRYZMr   c                 8    dD ]  }| j                  |d        y )N)PROJECT_PATHWORKTREE_PATHF)raising)delenv)monkeypatchenv_vars     r   
_clear_envr9   @   s$    4 37E23r   c           	         t        |       | dz  }|j                          |dz  j                          t        | dddt        |      iii       t        j                  dt        |             }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)uK   timers.json의 tasks.<task_id>.worktree_path를 정상 발견해야 한다.worktree_target.gittasks	task-2400worktree_pathworkspace_root==)z0%(py0)s == %(py5)s
{%(py5)s = %(py2)s(%(py3)s)
}resultr
   tmp_dirpy0py2py3py5u   nested lookup 실패: expected=, got=
>assert %(py7)spy7N)r9   r+   r1   r
   git_evidence_resolve_project_dir
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanation)tmp_pathr7   rE   rD   @py_assert4@py_assert1@py_format6@py_format8s           r   test_git_evidence_nested_lookupr^   I   s   { **GMMOv	;#g, ?@A
 ..CM / F \ 6\!   6\                          !    !    "    *'&A    r   c                    t        |       | dz  }|j                          |dz  j                          t        | ddt        |      ii       t        j                  dt        |             }t        |      }||k7  }|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z   d|iz  }t        t        j                  |            dx}}g }t        |t              }|}	|r|}	|	sd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d	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      dz  }
|j!                  |
       |rXd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z   d|iz  }t        t        j                  |            dx}	x}}y)u_   legacy top-level 구조({task_id: {...}})는 매칭되지 않고 fallback (D)로 가야 한다.legacy_targetr<   r>   r?   r@   )!=)z0%(py0)s != %(py5)s
{%(py5)s = %(py2)s(%(py3)s)
}rD   r
   rE   rF   u-   legacy top-level이 잘못 매칭됨: result=rL   rM   Nz.%(py6)s
{%(py6)s = %(py2)s(%(py3)s, %(py4)s)
}
isinstance)rH   rI   py4py6z%(py8)spy8r   u   fallback 결과가 비어있음
>assert %(py11)spy11)r9   r+   r1   r
   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   rb   append_format_boolop)rY   r7   rE   rD   rZ   r[   r\   r]   @py_assert5@py_assert0@py_format7@py_format9@py_format10@py_format12s                 r   +test_git_evidence_legacy_top_level_no_matchrp   `   sb   {(GMMOv 	G56
 ..CM / F
 \ 6\!   6\                          !    !    "    8x@    
 Q:fc"P"P"vPPPPPP:PPP:PPPPPPfPPPfPPPPPPcPPPcPPP"PPPP"PPPPPvPPPvPPPPPPPPP/PPPPPPPPr   c                    d}| dz  }|j                  |d       t        j                  dt        |            }|d   }d}||k(  }|st	        j
                  d	|fd
||f      t	        j                  |      t	        j                  |      dz  }t	        j                  d|d    d|j                  d             dz   d|iz  }t        t	        j                  |            dx}x}}y)uW   이슈 마커 형식이 아닌 본문 평문에서 'critical' 단어가 나와도 PASS.um   이 영역은 critical 한 영역이라 신중하게 처리합니다.
작업이 정상 완료되었습니다.	task-X.mdr(   r)   task-Xreport_pathstatusPASSrB   z%(py1)s == %(py4)spy1rc   u   평문 false positive: status=
, details=details
>assert %(py6)srd   Nr,   critical_gapverifyr
   rP   rQ   rU   rV   getrW   rX   	rY   bodyreportrD   rk   @py_assert3@py_assert2@py_format5rl   s	            r   !test_critical_gap_plain_text_passr      s    	2 	 #F
dW-  s6{ CF( v v%  v         &    ))9(:*VZZPYEZD[\     r   c                    d}| dz  }|j                  |d       t        j                  dt        |            }|d   }d}||k(  }|st	        j
                  d	|fd
||f      t	        j                  |      t	        j                  |      dz  }t	        j                  d|d    d|j                  d             dz   d|iz  }t        t	        j                  |            dx}x}}y)u4   이슈 마커(- CRITICAL: ...) + 미해결 → FAIL.uC   ## 발견 이슈
- CRITICAL: token storage 누락
해결 미완료.rr   r(   r)   rs   rt   rv   FAILrB   rx   ry   u   마커 미감지: status=r{   r|   r}   rd   Nr~   r   s	            r   !test_critical_gap_marker_detectedr      s    	 	
 #F
dW-  s6{ CF( v v%  v         &    $F8$4#5Z

9@U?VW     r   c                    d}| dz  }|j                  |d       t        j                  dt        |            }|d   }d}||k(  }|st	        j
                  d	|fd
||f      t	        j                  |      t	        j                  |      dz  }t	        j                  d|d    d|j                  d             dz   d|iz  }t        t	        j                  |            dx}x}}y)u3   마커 발견 + 후행 RESOLVED 키워드 → PASS.uu   ## 발견 이슈
- CRITICAL: token storage 누락

## 해결
**[Codex 위험 5건 모두 해결됨]**
수정 완료.
rr   r(   r)   rs   rt   rv   rw   rB   rx   ry   u   resolved 인식 실패: status=r{   r|   r}   rd   Nr~   r   s	            r   !test_critical_gap_marker_resolvedr      s    	 	 #F
dW-  s6{ CF( v v%  v         &    *&*:);:fjjQZF[E\]     r   task_id
base_entryc                 &    d||ii}t        | |      S )u8   workspace/memory/task-timers.json 에 task entry 작성.r=   )r1   )r   r   r   r   s       r   _setup_taskr      s    *-.GG,,r   c                     | dz  dz  }t        j                  |j                  d            }|j                  di       j                  |i       S )Nr!   r$   r(   r)   r=   )r-   loads	read_textr   )r   r   r0   datas       r   
_read_taskr      sL    !$66F::f&&&89D88GR $$Wb11r   c                 
   d}t        | |ddd       t        j                  | |dd      }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}}t        | |      }|j                  }d} ||      }	d}
|	|
k(  }|st        j                  d|fd|	|
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |	      t        j                  |
      dz  }t        j                  d|j                  d             dz   d|iz  }t        t        j                  |            dx}x}x}	x}}
|j                  }d} ||      }	|	st        j                  d|       dz   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |	      dz  }t        t        j                  |            dx}x}}	|j                  }d} ||      }	d}
|	|
k(  }|st        j                  d|fd|	|
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |	      t        j                  |
      dz  }t        j                  d|j                  d             dz   d|iz  }t        t        j                  |            dx}x}x}	x}}
|j                  dd       }|j                  }d!} ||      }	|	st        j                  d"|       d#z   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |	      dz  }t        t        j                  |            dx}x}}	y)$uM   _sync_task_timers 호출 후 status=completed, end_time/sha/closed_by 기록.r>   running2026-05-02T00:00:00+00:00rv   
start_timeabc1234auto_mergedTisz%(py0)s is %(py3)sretrG   rI   u   반환값 불일치: 
>assert %(py5)srJ   Nrv   	completedrB   zI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} == %(py9)sentryrG   rH   rc   rd   py9zstatus: rf   rg   end_timeu   end_time 누락: zG
>assert %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
})rG   rH   rc   rd   merge_commit_shazmerge_commit_sha: 	closed_by zauto_merge:u   closed_by prefix 불일치: zN
>assert %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.startswith
}(%(py4)s)
})r   
auto_merge_sync_task_timersrP   rQ   rR   rS   rT   rU   rV   rW   rX   r   r   
startswith)rY   r   r   r   r[   @py_format4r\   r   r   rj   @py_assert8@py_assert7rn   ro   rl   r   s                   r   test_auto_merge_sync_statusr      s   G,GH 
&
&'9mC 53$;5553$55555535553555$555/u5555555x)E99OXO9XO+O+-OOO+OOOOOO5OOO5OOO9OOOXOOOOOO+OOO%))H:M9N/OOOOOOOO99=Z=9Z = ==$5eW"=======5===5===9===Z=== ======99 ' 9'( I (I5  (I                  (    )    -6    UYY'9:;<      		+r*I  . .   'yk2                  !.    /      r   c                 d    d}t         |ddd       t        j                   |dd      }t        j                   |dd      }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}}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}}dt         ddd       g t        j                          fd}t        d      D 	cg c]  }	t        j                  |       }
}	|
D ]  }|j!                           |
D ]  }|j#                           t%        d 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}}t'               }|j(                  }d} ||      }d }||k(  }|st        j                  d|fd!||f      d"t        j                         v st        j                  |      rt        j                  |      nd"t        j                  |      t        j                  |      t        j                  |      t        j                  |      d#z  }d$d%|iz  }t        t        j                  |            dx}x}x}x}}yc c}	w )&uU   동일 task에 대한 중복 호출은 두 번째가 False (이미 completed) 반환.r>   r   r   r   r   r   Tr   r   ret1r   u   첫 호출 반환값: r   rJ   NFret2u   두 번째 호출 반환값: u&    (이미 completed면 False여야 함)z	task-2401c                      t         j                  dd      } 5  j                  |        d d d        y # 1 sw Y   y xY w)Ndeadbeefr   )r   r   rh   )rlockresultstask_id2rY   s    r   workerz+test_auto_merge_sync_atomic.<locals>.worker   sB    ((h
M
  	NN1	 	 	s	   7A r%   )targetc              3   *   K   | ]  }|d u sd  yw)T   N ).0r   s     r   	<genexpr>z.test_auto_merge_sync_atomic.<locals>.<genexpr>
  s     5119Q5s   	r   rB   )z%(py0)s == %(py3)s
true_countu   race condition: True 반환 u   회 (1회여야 함), results=rv   r   r   entry2r   zassert %(py11)srg   )r   r   r   rP   rQ   rR   rS   rT   rU   rV   rW   rX   	threadingLockrangeThreadstartjoinsumr   r   )rY   r   r   r   r   r[   r   r\   r   _threadstr   r   r   rj   r   r   rn   ro   r   r   r   s   `                   @@@r   test_auto_merge_sync_atomicr      s   G,GH '''9mD '''9mD 844<888448888884888488848881$8888888f45=fff45ffffff4fff4fff5fff9$?efffffff H,GH G>>D 9>aA1yv.AGA 		 	 555J :?  :                  'zl2PQXPYZ     (+F::.h.:h.;.;....;......6...6...:...h......;........ Bs   P-c           	         d}d}t        | |dd|dd       t        j                  | |dd      }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}}t        | |      }|j                  }d}	 ||	      }
|
|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|j                  d             dz   d|iz  }t        t        j                  |            dx}x}	x}
}y)uF   이미 completed인 task의 end_time을 덮어쓰지 않아야 한다.r>   z2026-01-01T00:00:00+00:00r   z2025-12-31T00:00:00+00:00preexisting)rv   r   r   r   newsha99r   Fr   r   r   r   u&   이미 completed일 때 False 기대: r   rJ   Nr   rB   )zI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} == %(py8)sr   original_end_time)rG   rH   rc   rd   re   u#   end_time이 덮어써짐: expected=rK   z
>assert %(py10)spy10)r   r   r   rP   rQ   rR   rS   rT   rU   rV   rW   rX   r   r   )rY   r   r   r   r   r[   r   r\   r   r   rj   r   rm   @py_format11s                 r   test_auto_merge_sync_no_clobberr     s   G3!5) -		
	 
&
&':}C G3%<GGG3%GGGGGG3GGG3GGG%GGGA#GGGGGGGx)E99 Z 9Z   $55    $5                       !      %6    %6    ..?-@uyyQ[G\F]^     r   )#__doc__builtinsrR   _pytest.assertion.rewrite	assertionrewriterP   importlib.utilr   r-   r   r   pathlibr   	WORKSPACEr
   pathinsertr   rN   r   r   dictr1   r9   r^   rp   r   r   r   r   r   r   r   r   r   r   r   <module>r      sK  
     
  @A	y>!HHOOAs9~&s t  ("[03DD ("[03DD 	O+
T D T 3.Q> "0-4 -# -4 -2$ 2 2 260/fr   