
    jfR              	         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ZddlmZmZmZ ddlmZ ddlmZ  ee      j3                         j4                  j4                  j4                  Z ee      ej:                  vr"ej:                  j=                  d ee             ddZ edd	        ed
d        edd      Z  edd      Z!e jD                  Z#dZ$ eddddddejJ                        Z&d Z'd Z(d Z)d Z*d Z+d d!dZ, G d dejZ                        Z.e/dk(  r ej`                          yy)"u
  task-2720 P0-a callback pickup runner — regression (9).

pickup_once 의 모든 분기를 mock/fixture 로 검증.
네트워크 0, 전부 mock/fixture, tmpdir 사용.
ANU key literal 절대 노출 금지 — 모듈 상수 / sealed_key_loader fake 주입으로만.
    )annotationsN)datetime	timedeltatimezone)Path)Optionalc                r   | t         j                  v rt         j                  |    S t        j                  j	                  | t
        |z        }g }d }||u}|}|r|j                  }d }||u}	|	}|slt        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  }|j                  |       |rt        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  }|j                  |       t        j                  |d      i z  }dd|iz  }t        t        j                   |            d x}x}x}x}x}x}	}t        j                  j#                  |      }|t         j                  | <   |j                  j%                  |       |S )N)is not)z%(py2)s is not %(py5)sspec)py2py5z%(py7)spy7)z5%(py11)s
{%(py11)s = %(py9)s.loader
} is not %(py14)s)py9py11py14z%(py16)spy16r   zassert %(py19)spy19)sysmodules	importlibutilspec_from_file_location_ROOTloader
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprappend_format_boolopAssertionError_format_explanationmodule_from_specexec_module)modnamerelpathr   @py_assert1@py_assert4@py_assert3@py_assert0@py_assert10@py_assert13@py_assert12@py_format6@py_format8@py_format15@py_format17@py_format18@py_format20mods                    d/home/jay/workspace/.worktrees/task-2723-dev2/tests/regression/test_anu_result_pickup_runner_2720.py_loadr8      sI   #++{{7##>>11'57?KD7t74t77474 777774t77777747774777t77777774777777777777777477777777777777
..
)
)$
/CCKKKKC J    z dispatch.callback_owner_enforcerz#dispatch/callback_owner_enforcer.pyz(dispatch.normal_fallback_callback_helperz+dispatch/normal_fallback_callback_helper.pyz'dispatch.anu_owned_callback_enforcementz*dispatch/anu_owned_callback_enforcement.pyz!dispatch.anu_result_pickup_runnerz$dispatch/anu_result_pickup_runner.py7943afbe12c12f7di           )tzinfoc                     t         S N)_NOW r9   r7   _clockrC   8   s    Kr9   c                 F    t         t        d      z
  j                  d      S )Nr;   )minutesz%Y-%m-%dT%H:%M:%SZ)rA   r   strftimerB   r9   r7   	_fresh_tsrG   <   s    9Q''112FGGr9   c                     t         S )uP   테스트용 ANU key fake 로더 — literal 노출 없이 모듈 상수 반환.)_ANU_KEYrB   r9   r7   _sealed_key_loaderrJ   @   s    Or9   c                      y)u@   키 미설정 모사 — SEALED_KEY_MISSING 경로 테스트용.NrB   rB   r9   r7   _no_key_loaderrL   E   s    r9   c                *    t        |       dfd}|S )Nc                2    | v rd| ddddgdS dd|  dS )	Nok   z2026-05-31 03:00:00)statusts)rQ   idcounthistoryerrorz%schedule not found or access denied: )rQ   messagerB   )schedule_idowneds    r7   _probez_make_probe.<locals>._probeN   sC    %!'+3HIJ	  >{mL
 	
r9   )rX   strreturndict)set)owned_schedulesrZ   rY   s     @r7   _make_prober`   K   s     E
 Mr9   c                    |ddd}|r|j                  |       t        j                  j                  | | d      }t	        |dd      5 }t        j                  ||d	       d
d
d
       |S # 1 sw Y   |S xY w)u4   헬퍼: 정상 result.json 작성 후 경로 반환.donedeadbeef)task_idsummarysha256z.result.jsonwutf-8encodingF)ensure_asciiN)updateospathjoinopenjsondump)
result_dirrd   extrapayloadrn   fhs         r7   _write_result_jsonrw   ^   sp    !f
KGu77<<
wi|$<=D	dC'	* 3b		'2E23K3Ks   A..A8c                  Z    e Zd Zd Zd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zy)TestPickupRunner2720c                    t        j                  d      | _        | j                  t        j
                  | j                  d       y )Nz	task2720-)prefixT)ignore_errors)tempfilemkdtemp_tmp
addCleanupshutilrmtree)selfs    r7   setUpzTestPickupRunner2720.setUpk   s.    $$K8	tyyEr9   c                   t        j                  d| j                        }t        j                  j                  | j                  d      }t        |d      }t        j                  |t        t        t        |      }| j                  |j                  t        j                         | j                  |j                          | j                  |j"                         | j%                  |j&                         | j)                  t+        |j&                        d       | j                  |j,                  d       | j/                  d|j&                         |j&                  j1                  d      }| j                  |j&                  |dz      t2               | j%                  |j4                         | j                  t        j                  j7                  |j4                               y	)
uX   정상 result.json (collector_envelope 없음) → WAKE_BUILT, argv 비어있지 않음.zt2720-1-r{   dirzledger1.jsonl	task-2720executor_keyclocksealed_key_loaderledger_pathr   --keyrP   N)r}   r~   r   rm   rn   ro   rw   Mpickup_once_DEV_KEYrC   rJ   assertEqualverdictPICKUP_WAKE_BUILT
assertTruerO   
wake_builtassertIsNotNoneargvassertGreaterlenrd   assertInindexrI   marker_pathisfile)r   rdirledgerrn   residxs         r7   test_fx_result_json_validz.TestPickupRunner2720.test_fx_result_json_validp   sH   ztyyAdii9!$4mm!0  
 	a&9&9:'SXX&3sxx=!,k2gsxx(hhnnW%#'*H5S__-s78r9   c                   t        j                  d| j                        }t        j                  j                  | j                  d      }d}d}d|ddt               d	}t        |dd
|i      }t        j                  |t        |h      t        t        t        |      }| j                  |j                  t        j                          | j#                  |j$                         | j'                  |j(                         y)uO   collector_envelope(self_key 소유 schedule_id) + access-denied → QUARANTINE.zt2720-2-r   zledger2.jsonlA372DD6B	ANUOWNED1r   ANUF)rd   rX   collector_roleself_key_usedrecorded_atcollector_envelopert   gh_prober   r   r   r   N)r}   r~   r   rm   rn   ro   rG   rw   r   r   r`   r   rC   rJ   r   r   PICKUP_QUARANTINEassertFalser   assertIsNoner   )r   r   r   SELF_SIDANU_SIDenvelopern   r   s           r7   test_fx_self_collector_keyz/TestPickupRunner2720.test_fx_self_collector_key   s    ztyyAdii9"##"$;
 "$)=x(HJmm '+!0  
 	a&9&9:(#((#r9   c                   t        j                  d| j                        }t        j                  j                  | j                  d      }d}d|t               d}t        |dd|i      }d	 }t        j                  ||t        t        t        |
      }| j                  |j                  t        j                         | j!                  |j"                         | j%                  |j&                         y)uN   gh_probe 가 unknown status 반환 → PENDING_OWNER_PROOF, retryable, wake 0.zt2720-3-r   zledger3.jsonlWEIRDSCHEDULEr   )rd   rX   r   r   r   c                
    ddiS )NrQ   weirdrB   )_sids    r7   weird_probezETestPickupRunner2720.test_fx_owner_proof_pending.<locals>.weird_probe   s    g&&r9   r   N)r}   r~   r   rm   rn   ro   rG   rw   r   r   r   rC   rJ   r   r   PICKUP_PENDINGr   r   r   r   )r   r   r   SIDr   rn   r   r   s           r7   test_fx_owner_proof_pendingz0TestPickupRunner2720.test_fx_owner_proof_pending   s    ztyyAdii9"$;

 "$)=x(HJ	' mm !0  
 	a&6&67(#((#r9   c                   t        j                  d| j                        }t        j                  j                  | j                  d      }t        |d      }t        j                  |t        t        t        |      }| j                  |j                  t        j                         | j                  |j                          t        j                  |t        t        t        |      }| j#                  |j                  t        j$                  t        j&                  f       | j)                  |j                          | j+                  |j,                         y)uS   같은 result.json 2회 pickup → 1회차 WAKE_BUILT, 2회차 SKIP (wake 1회만).zt2720-4-r   zledger4.jsonlztask-2720dupr   Nr}   r~   r   rm   rn   ro   rw   r   r   r   rC   rJ   r   r   r   r   r   r   PICKUP_SKIP_DEDUPEPICKUP_SKIP_TERMINALr   r   r   r   r   r   rn   res1res2s         r7   test_fx_duplicate_result_jsonz2TestPickupRunner2720.test_fx_duplicate_result_json   s    ztyyAdii9!$7}}!0  
 	q':':;(}}!0  
 	dll++Q-C-CD	F)$))$r9   c                ,   t        j                  d| j                        }t        j                  j                  | j                  d      }t        |d      }t        j                  j                  |d      }t        |d      5 }|j                  d       ddd       t        j                  |t        t        t        |	      }| j                  |j                  t        j                          | j#                  |j$                         y# 1 sw Y   uxY w)
u;   <task>.pickup.done 미리 생성 → SKIP_TERMINAL, wake 0.zt2720-5-r   zledger5.jsonlztask-2720mrkztask-2720mrk.pickup.donerg   z{}Nr   )r}   r~   r   rm   rn   ro   rw   rp   writer   r   r   rC   rJ   r   r   r   r   r   )r   r   r   rn   rb   rv   r   s          r7   test_fx_terminal_marker_presentz4TestPickupRunner2720.test_fx_terminal_marker_present   s    ztyyAdii9!$7ww||D"<=$_ 	HHTN	mm!0  
 	a&<&<=(	 	s   D

Dc                   t        j                  d| j                        }t        j                  j                  | j                  d      }t        j                  j                  |d      }t        |dd      5 }t        j                  dd	d
|       ddd       t        j                  |t        t        t        |      }| j                  |j                  t        j                          | j#                  |j$                         t        j                  j                  |d      }t        |dd      5 }t        j                  ddi|       ddd       t        j                  |t        t        t        |      }| j                  |j                  t        j                          y# 1 sw Y   xY w# 1 sw Y   gxY w)u-   result.json task_id 빈값/공백 → REJECT.zt2720-6-r   zledger6.jsonlzempty.result.jsonrg   rh   ri   z   x)rd   re   Nr   znotaskid.result.jsonre   y)r}   r~   r   rm   rn   ro   rp   rq   rr   r   r   r   rC   rJ   r   r   PICKUP_REJECTr   r   )r   r   r   rn   rv   r   path2r   s           r7   test_fx_invalid_task_idz,TestPickupRunner2720.test_fx_invalid_task_id   sR   ztyyAdii9ww||D"56$g. 	>"II%C8"=	>mm!0  
 	aoo6( T#9:%w/ 	,2IIy#&+	,}}!0  
 	q7/	> 	>	, 	,s   :F'5F4'F14F=c                b   t         dz  dz  }| j                  |j                         d       |j                  d      }|j	                  d      }| j                  |dd| d       |j	                  d	      }| j                  |dd
| d       d|v xs
 d|v xs d|v }| j                  |d       y)u   finish-task.sh 치환 후:
        - T2626_ANU_KEY literal 0건
        - callback-launch.json 문자열 0건
        - result.json 작성 경로 존재 확인
        scriptszfinish-task.shu,   scripts/finish-task.sh 가 존재해야 함.rh   T2626_ANU_KEYr   u%   finish-task.sh 에 T2626_ANU_KEY 가 u>   건 남아 있음 — task-2720 치환 후 0건 이어야 함.zcallback-launch.jsonu,   finish-task.sh 에 callback-launch.json 이 zresult.jsonanu_owned_callback_enforcementzexecutor-write-resultu   finish-task.sh 에 result.json 작성 경로 (anu_owned_callback_enforcement 또는 executor-write-result 또는 .result.json) 가 없음.N)r   r   is_file	read_textrT   r   )r   	finish_shcontentanu_literal_count	cbl_counthas_result_paths         r7   *test_fx_finish_task_emits_result_json_onlyz?TestPickupRunner2720.test_fx_finish_task_emits_result_json_only  s     I%(88		))+F	H%%g. $MM/:q34E3F G; ;	
 MM"89	q:9+ F; ;	
 W$ 2/7:2&'1 	
 	L	
r9   c                "   t        j                  d| j                        }t        j                  j                  | j                  d      }t        |d      }t        j                  |t        t        t        |      }| j                  |j                  t        j                         | j                  |j                          dj                  |j                         }| j#                  t        |d       | j%                  d|j                          |j                   j'                  d      }| j                  |j                   |d	z      t(               t        j*                  j-                  t        j.                  d
      }	 t        j                  d| j                        }t        j                  j                  | j                  d      }	t        |d      }
t        j                  |
t        t        t0        |	      }| j                  |j                  t        j2                         | j5                  |j6                         |"|t        j*                  t        j.                  <   y
y
# |"|t        j*                  t        j.                  <   w w xY w)u   wake argv 에 executor self-key 미포함 + sealed_key_loader 경유만.
        sealed_key_loader=None + env 미설정 → SEALED_KEY_MISSING.zt2720-8-r   zledger8.jsonlztask-2720sealr    u4   argv 에 executor self-key 가 포함되면 안 됨.r   rP   Nz	t2720-8b-zledger8b.jsonlztask-2720seal2)r}   r~   r   rm   rn   ro   rw   r   r   r   rC   rJ   r   r   r   r   r   assertNotInr   r   rI   environpopENV_ANU_KEYrL   PICKUP_SEALED_KEY_MISSINGr   r   )r   r   r   rn   r   argv_strr   origrdir2ledger2r   r   s               r7   test_fx_anu_key_sealed_onlyz0TestPickupRunner2720.test_fx_anu_key_sealed_only=  s    ztyyAdii9!$8mm!0  
 	a&9&9:SXX&88CHH%8O	Q 	gsxx(hhnnW%#'*H5 zz~~ammT2	1$$KTYYGEggll499.>?G&u.>?E==%"0# ! D T\\1+F+FGT__-,0

1==)  t,0

1==)  s   CI( (&Jc                   ddl }t        j                  d| j                        }t        j
                  j                  | j                  d      }t        |d      }t        j                  |t        t        t        |      }| j                  |j                  t        j                         | j!                  |j"                         |j                  t        j
                  j                  |d            }| j                  |g d	|        t        j                  d
| j                        }t        j
                  j                  | j                  d      }t        |d      }	t        j
                  j                  |d      }
t%        |
d      5 }|j'                  d       ddd       t        j                  |	t        t        t        |      }| j                  |j                  t        j                  d       | j!                  |j"                         | j)                  |j*                         | j-                  t/        t        d      d       y# 1 sw Y   xY w)u  <task>.pickup.lock 파일이 미리 존재해도 pickup 을 차단하지 않음.
        (SKIP_LOCK 상수 제거 — 파일락 완전 제거) → 정상 WAKE_BUILT 반환.
        pickup 완료 후 *.pickup.lock 파일이 생성되지 않았음을 fs 검증.r   Nzt2720-9-r   zledger9.jsonlztask-2720lckr   z*.pickup.lockuD   pickup 이 *.pickup.lock 파일을 생성함 (파일락 미제거): z	t2720-9b-zledger9-2.jsonlztask-2720staleztask-2720stale.pickup.lockrg   z
stale-lockuS   lock 파일이 있어도 pickup 이 차단되면 안 됨 (파일락 제거 회귀).PICKUP_SKIP_LOCKO   PICKUP_SKIP_LOCK 상수가 모듈에 존재 — 파일락 완전 제거 실패.)globr}   r~   r   rm   rn   ro   rw   r   r   r   rC   rJ   r   r   r   r   r   rp   r   r   r   r   hasattr)r   _globr   r   rn   r   	new_locksr   r   r   
stale_lockrv   r   s                r7   test_fx_no_lock_file_createdz1TestPickupRunner2720.test_fx_no_lock_file_createdi  s    	 ztyyAdii9!$7mm!0  
 	a&9&9:'JJrww||D/BC	rRS\R]^	
   C'',,tyy*;<"5*:;WW\\%)EF
*c" 	#bHH\"	#}}!0  
 	q':':n	p(TYY' 	A)*]	
	# 	#s   IIc           	        ddl }| j                  t        t        d      d       | j                  t        t        d      d       |j	                  t              }|j                         D cg c]#  }|j                         j                  d      s|% }}g d}|D ]/  }|D cg c]	  }||v s| }}| j                  |g d	| d
|        1 yc c}w c c}w )u   파일락 완전 제거(task-2720 3차 fix) 입증:
        모듈 코드(비-주석) 라인에 lock 관련 심볼이 0건임을 assert.r   Nr   r   _STALE_LOCK_SECONDSuK   _STALE_LOCK_SECONDS 가 모듈에 존재 — stale 회수 로직 미제거.#)	zpickup.lock_lock_acquired_STALE_LOCKO_EXCLO_CREAT	lock_path	SKIP_LOCKz
lock-stealstealu   lock 심볼 'u+   ' 이 코드(비-주석) 라인에 존재: )	inspectr   r   r   	getsource
splitlinesstrip
startswithr   )	r   r   srcline
code_lineslock_symbolssymlnmatchings	            r7   test_fx_no_lock_symbols_at_allz3TestPickupRunner2720.test_fx_no_lock_symbols_at_all  s     	 	A)*]	
 	A,-Y	

 " !^^-
::<**3/ 

 


   	C%/=r3"9=H="u$OPXzZ	#
$ >s   ,(C#	C-Cc                   t        j                  d| j                        }t        j                  j                  | j                  d      }t        |d      }t        j                  |t        t        t        |      }| j                  |j                  t        j                         | j                  |j                          t        j                  |t        t        t        |      }| j#                  |j                  t        j$                  t        j&                  fd       | j)                  |j                          | j+                  |j,                         y)u   동시 pickup 2회 호출(serial 모사) → 1회차만 WAKE_BUILT, 2회차는
        dedupe/done-marker 로 no-op. lock 단순화 후에도 wake 중복 0 보장.z	t2720-9c-r   zledger9c.jsonlztask-2720conr   uP   2회차 pickup 이 WAKE_BUILT — 중복 wake 발생 (dedupe/done-marker 결함)Nr   r   s         r7   *test_fx_concurrent_pickup_dedupe_wake_oncez?TestPickupRunner2720.test_fx_concurrent_pickup_dedupe_wake_once  s    {		Bdii)9:!$7 }}!0  
 	q':':;( }}!0  
 	dll++Q-C-CDh	j 	)$))$r9   c                x   t        j                  d| j                        }t        j                  j                  | j                  d      }t        |d      }t        j                  j                  |d      }t        |dd      5 }d	d
l}|j                  ddd|       d
d
d
       t        j                  |t        t        t        |      }| j                  |j                   t        j"                  d       | j%                  |j&                         | j)                  |j*                         y
# 1 sw Y   xY w)u   terminal done-marker(<task>.pickup.done) 존재 시 → SKIP_TERMINAL no-op.
        lock 단순화 후에도 terminal marker 우선 처리 회귀 없음.z	t2720-9d-r   zledger9d.jsonlztask-2720dmrkztask-2720dmrk.pickup.donerg   rh   ri   r   Nr   )eventrd   r   u:   done-marker 존재 시 SKIP_TERMINAL 이어야 함 (no-op))r}   r~   r   rm   rn   ro   rw   rp   rq   rr   r   r   r   rC   rJ   r   r   r   r   r   r   r   )r   r   r   rn   rb   rv   _jsonr   s           r7   test_fx_done_marker_noopz-TestPickupRunner2720.test_fx_done_marker_noop  s     {		Bdii)9:!$8ww||D"=>$g. 	W" JJ!4QSUV	W mm!0  
 	a&<&<U	W(#((#	W 	Ws   D00D9N)__name__
__module____qualname__r   r   r   r   r   r   r   r   r   r   r  r	  r  rB   r9   r7   ry   ry   i   sJ    F
96$8$:%:)(8@%
P)1X1
h'T%B$r9   ry   __main__)r'   r[   r(   r[   r@   )rs   r[   rd   r[   rt   zOptional[dict]r\   r[   )1__doc__
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   importlib.utilr   rq   rm   r   r   r}   unittestr   r   r   pathlibr   typingr   __file__resolveparentr   r[   rn   insertr8   M_enfr   ANU_KEYrI   r   utcrA   rC   rG   rJ   rL   r`   rw   TestCasery   r  mainrB   r9   r7   <module>r%     s<   #      	  
   2 2  X ''..55u:SXXHHOOAs5z" (+- 0357:	<	
-
02 == aQ1X\\:H
&T$8,, T$n zHMMO r9   