
    nj                    ^   d Z ddl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m	Z	 ddl
Z
 e	e      j                         j                  d   Z ee      ej                   vr"ej                   j#                  d ee             ddlmZ edz  dz  Zej,                  j/                  d      Ze eedd	      xs d	 ee      k7  r eej,                        D  cg c]  } | dk(  s| j7                  d
      s|  c} D ]  Zej,                  e=   ej:                  de eedz        g      Zeej>                  J  ej@                  e      Z!e!ej,                  d<   ej>                  jE                  e!       ddl#m$Z% ddddddddZ&d<dZ'd=dZ(d>d?dZ)d@dZ*ddl+Z,dAdBdZ-d Z.dCdDdZ/dEdDdZ0d Z1d Z2d Z3d Z4d  Z5d! Z6d" Z7d# Z8d$ Z9d% Z:d& Z;d' Z<d( Z=e
j|                  j                  d)g d*      d+        Z@d, ZAd- ZBd. ZCd/ ZDd0 ZEd1 ZFd2 ZGd3 ZHd4 ZId5 ZJd6 ZKd7 ZLd8 ZMd9 ZNd: ZOd; ZPyc c} w )Fu[  task-2721 P0-b ANU pickup driver — regression (11).

대상 모듈: dispatch.anu_pickup_driver (불칸 동시 구현).

절대 제약:
- ANU key literal 'c119085...' 를 테스트 코드에 절대 쓰지 않는다 (0건).
- pickup_once 실호출 절대 금지 — 전부 mock/stub. pickup_fn / verify_fn 은
  호출 인자로 mock 주입한다. 실제 wake/cron 발사 0건.
- tmp_path fixture 만 사용. 실제 memory 디렉토리에 쓰지 않는다.
  activation flag 도 tmp dir 에만 둔다.

이 파일은 driver 의 공개 API 계약(task-2721 spec)에 맞춰 작성된 회귀 테스트다.
    )annotationsN)Path   dispatchz__init__.py__file__ z	dispatch.)submodule_search_locations)anu_pickup_drivertask-999EXECUTOR_RESULT_WRITTENsch-1task_idschedule_idzr.mdabc)r   completion_signalcollector_envelopereport_pathsha256c                j    | dz  dz  j                  dd       | dz  dz  j                  dd       | S )uV   tmp_path 안에 memory/events, memory/state 디렉토리를 만들고 root 를 반환.memoryeventsTparentsexist_okstate)mkdir)tmp_paths    /tests/regression/test_anu_pickup_driver_2721.py
_make_dirsr    C   sA    8#**4$*G7"))$)FO    c                    | dz  dz  S )Nr   r    )roots    r   _events_dirr%   J   s    (?X%%r!   c                ~    t        |       |z  }|t        }|j                  t        j                  |      d       |S )u@   memory/events 아래에 result.json 을 쓰고 경로를 반환.utf-8encoding)r%   VALID_PAYLOAD
write_textjsondumps)r$   namepayloadps       r   _write_resultr1   N   s9    DD ALLG$wL7Hr!   c                    | dz  dz  dz  }|j                   j                  dd       |j                  t        j                  dz   d       y	)
u7   tmp dir 의 activation flag 파일에 'enabled' 작성.r   r   p0b_driver_enabledTr   
r'   r(   N)parentr   r+   drvACTIVATION_ENABLED)r$   flags     r   _enable_activationr9   W   sH    (?W$';;DKKdT2OOC**T1GODr!   c                t    t        j                         |z
  }t        j                  t	        |       ||f       y)u   result 파일 mtime/atime 을 과거로 설정해 readiness 'aged' 게이트를 통과시킨다.
    (write race 방어 readiness window 회피용 — 테스트에서 writer flush 완료 상태 모사.)N)_timetimeosutimestr)pathsecondspasts      r   _agerC   a   s*     ::<'!DHHSYt%r!   c                      y Nr#   )aks     r   <lambda>rH   i       r!   c                (     g  fd}|_         |S )u   pickup_fn mock. 호출 인자를 calls 리스트에 기록한다.

    mock.calls -> list[(args, kwargs)]
    호출 시 SimpleNamespace(verdict, ok, argv, task_id, reasons) 반환.
    실제 wake/cron 발사는 전혀 하지 않는다 (순수 stub).
    c                 f    j                  | |f       t        j                  dk(  dgdg       S )N
WAKE_BUILTxr   )verdictokargvr   reasonsappendtypesSimpleNamespaceargskwargscallsrN   s     r   _pickupz!make_pickup_mock.<locals>._pickupv   s<    dF^$$$<'
 	
r!   rY   )rN   rZ   rY   s   ` @r   make_pickup_mockr\   m   s     E
 GMNr!   c                (     g  fd}|_         |S )uA   verify_fn mock. 호출 인자를 calls 리스트에 기록한다.c                 b    j                  | |f       t        j                  dk(  dg       S )NAUTHORITATIVEr   )rN   rO   classificationrQ   rR   rV   s     r   _verifyz!make_verify_mock.<locals>._verify   s7    dF^$$$?*	
 	
r!   r[   )rN   ra   rY   s   ` @r   make_verify_mockrb      s    E
 GMNr!   c                <   t        |       }t               }t        j                  ||d d      }t	        |      dk(  sJ |d   }|j
                  t        j                  k(  sJ |j                  t        j                  k(  sJ t	        |j                        dk(  sJ y )Nc                      y rE   r#   r#   r!   r   rH   z,test_default_disabled_noop.<locals>.<lambda>   rI   r!   F)	pickup_fnflag_readerwrite_evidence   r   )
r    r\   r6   	scan_oncelenrN   VERDICT_NOOP_DISABLED
activationACTIVATION_DISABLEDrY   )r   r$   pickuprecordsrecs        r   test_default_disabled_nooprq      s    hDFmm 	G w<1
!*C;;#33333>>S44444v||!!!r!   c                   t        |       }t        |      }t               }|dz  }|dz  }|dz  }|||fD ]  }|j                  dd        |dz  }|j                  t	        j
                  t              d       t        j                  t        |            du sJ t        j                  t        |            d	u sJ t        j                  t        |            d	u sJ t        j                  t        |            d	u sJ |||fD ]B  }t        j                  t        |      ||
      }	|	j                  t        j                  k(  rBJ  t        |j                        dk(  sJ y )Nzfoo.mdz	bar.jsonlztask-1.result.json.tmp-9rM   r'   r(   ztask-7.result.jsonTF)r$   re   r   )r    r%   r\   r+   r,   r-   r*   r6   	is_targetr?   process_onerN   VERDICT_NOOP_NOT_TARGETrj   rY   )
r   r$   evrn   p_mdp_jsonlp_tmpr0   finalrp   s
             r   test_scan_limited_not_targetr{      sV   hD	T	BF=D;G++EGU# ,	S7+, %%E	TZZ.A==U$,,,==T#u,,,==W&%///==U$--- GU# :ooc!f46B{{c99999: v||!!!r!   c                z   t        |       }t        |       t               }t        |      dz  }|j	                  dd       t        |       |j                         j                  dk(  sJ t        j                  t        |      ||t              }|j                  t        j                  k(  sJ |j                  dk(  sJ |j                  du sJ t!        |j"                        dk(  sJ |j%                         rJ |d	z  d
z  dz  }|dz  j%                         sJ |d	z  dz  dz  dz  j%                         rJ y )Ntask-999.result.jsonr   r'   r(   r   r$   re   sleep_fnsize0Tr   	p0b_state
quarantiner   )r    r9   r\   r%   r+   rC   statst_sizer6   rt   r?   	_NO_SLEEPrN   VERDICT_QUARANTINEquarantine_reasonquarantinedrj   rY   exists)r   r$   rn   r0   rp   qdirs         r   test_quarantine_size0r      s.   hDtFD22ALLgL&G668q   
//#a&tv	
RC;;#00000  G+++??d"""v||!!! xxz>(?[(<7D))11333x(*\9<RRZZ\\\\r!   c                |   t        |       }t        |       t               }t        |      dz  }|j	                  dd       t        |       t        j                  t        |      ||t              }|j                  t        j                  k(  sJ |j                  dk(  sJ t        |j                        dk(  sJ y )Nr}   z"{invalid jsonr'   r(   r~   
parse_failr   )r    r9   r\   r%   r+   rC   r6   rt   r?   r   rN   r   r   rj   rY   r   r$   rn   r0   rp   s        r   test_quarantine_parse_failr      s    hDtFD22ALL!GL4G
//#a&tv	
RC;;#00000  L000v||!!!r!   c                   t        |       }t        |       t               }t        |      dz  }|j	                  t        j                  ddi      d       t        |       t        j                  t        |      ||t              }|j                  t        j                  k(  sJ |j                  dk(  sJ t        |j                         dk(  sJ y )	Nr}   foorh   r'   r(   r~   schema_failr   )r    r9   r\   r%   r+   r,   r-   rC   r6   rt   r?   r   rN   r   r   rj   rY   r   s        r   test_quarantine_schema_failr      s    hDtFD22ALLUAJ''L:G
//#a&tv	
RC;;#00000  M111v||!!!r!   c                   t        |       }t        |       t               }t        d      }t	        |      }t        |       t        j                  t        |      |||t              }|j                  t        j                  k(  sJ |j                  dk(  sJ t        |j                        dk(  sJ |j                  t        j                   k7  sJ |j                  t        j"                  t        j$                  fv sJ y )NQUARANTINEDrN   r$   re   	verify_fnr   owner_proof_failr   )r    r9   r\   rb   r1   rC   r6   rt   r?   r   rN   r   r   rj   rY   owner_key_classOKC_ANUOKC_FOREIGNOKC_SELFr   r$   rn   verifyr0   rp   s         r    test_quarantine_owner_proof_failr     s    hDtFm4FdAG
//#a&tv#,.C;;#00000  $6666v||!!!#++---3??CLL"AAAAr!   c                   t        |       }t        |       t               }t               }t	        t
              }|j                  d       t        ||      }t        |       t        j                  t        |      |||t              }|j                  t        j                  k(  sJ |j                  dk(  sJ t!        |j"                        dk(  sJ y )Nr   r/   r   owner_unprovabler   )r    r9   r\   rb   dictr*   popr1   rC   r6   rt   r?   r   rN   r   r   rj   rY   )r   r$   rn   r   r/   r0   rp   s          r    test_quarantine_owner_unprovabler      s    hDtFF=!GKK$%dG,AG
//#a&tv#,.C;;#00000  $6666v||!!!r!   c                   t        |       }t        |       t               }t        d      }t	        |      }t        |       t        |      dz  }|j                  dd       t        j                  t        |      |||t              }|j                  t        j                  k(  sJ |j                  du sJ t        |j                         d	k(  sJ y )
Nr_   r   task-999.pickup.donedoner'   r(   r   Fr   )r    r9   r\   rb   r1   rC   r%   r+   r6   rt   r?   r   rN   VERDICT_PICKUP_SKIPr   rj   rY   )r   r$   rn   r   r0   markerrp   s          r   test_dedupe_done_marker_noopr   5  s    hDtFo6FdAG!77F
fw/
//#a&tv#,.C;;#11111??e###v||!!!r!   c                   t        |       }t        |       t        d      }t        d      }t	        |      }t        |       t        j                  t        |      |||t              }|j                  t        j                  k(  sJ |j                  t        j                  k(  sJ t        |j                        dk(  sJ |j                  d   \  }}|d   t        |      k(  sJ y )NrL   r   r_   r   rh   r   r    r9   r\   rb   r1   rC   r6   rt   r?   r   rN   VERDICT_WAKE_BUILTr   r   rj   rY   )r   r$   rn   r   r0   rp   rW   rX   s           r   #test_six_conditions_pass_wake_builtr   K  s    hDtl3Fo6FdAG
//#a&tv#,.C;;#00000#++--- v||!!!<<?LD&7c!fr!   c                   t        |       }t        |       t        d      }t        d      }t	        |      }t        |       t        j                  |||dt              }t        |      dk\  sJ |dz  dz  d	z  }|j                         sJ |dz  d
z  dz  j                         rJ |j                  d      }|j                         D cg c]  }|j                         s| }	}t        |	      dk\  sJ |	D ];  }t        j                  |      }
|
j!                  d      t        j"                  k(  r;J  d|v sJ t        j"                  |v sJ d}||vsJ y c c}w )NrL   r   r_   Tre   r   rg   r   rh   r   r   zdriver_runs.jsonlr   zp0b_driver_runs.jsonlr'   r(   driverz"driver"c119085addb0f8b7)r    r9   r\   rb   r1   rC   r6   ri   r   rj   r   	read_text
splitlinesstripr,   loadsgetDRIVER_NAME)r   r$   rn   r   r0   ro   evidencecontentlnlinesobj	forbiddens               r   test_scan_once_evidence_jsonlr   b  si   hDtl3Fo6FdAGmmG w<1h,/BBH??x(*-DDLLNNN  ' 2G!,,.=B"((*R=E=u:?? 4jjnwwx COO3334
    ??g%%% (IG### >s   E%Ec                0   t        |       }t        |       t        d      }t        d      }t	        |      }t        |       t        j                  t        |      |||t              }t        j                  |j                               }d}||vsJ y )NrL   r   r_   r   r   )r    r9   r\   rb   r1   rC   r6   rt   r?   r   r,   r-   to_json)r   r$   rn   r   r0   rp   dumpedr   s           r   test_no_key_literal_in_recordsr     s    hDtl3Fo6FdAG
//#a&tv#,.C ZZ&F'IF"""r!   c                     t        t              j                         j                  d   } | dz  dz  j	                  d      }d|v sJ d|j                  dd	      vsJ d
|v sJ y)uL   HIGH-1: entrypoint lock 경로에 UID 포함 + /tmp 고정 경로 미사용.r   scriptsanu_pickup_entrypoint.shr'   r(   UIDz/tmp/anu-pickup.driver.lockXDG_RUNTIME_DIRr   flockN)r   r   resolver   r   replace)r$   shs     r   &test_entrypoint_lock_path_uid_isolatedr     so    >!!#++A.D

7
7	B	BG	B	TBB;;(

;Lb0QQQQb==r!   c                 6   t         j                  j                  d      sJ t         j                  j                  d      sJ t         j                  j                  d      rJ t         j                  j                  d      rJ t         j                  dk(  sJ y)uU   HIGH-2: quarantine/evidence 출력 경로가 watched 디렉터리(memory/events) 밖.zmemory/p0b_statezmemory/eventsN)r6   QUARANTINE_DIR_REL
startswithEVIDENCE_JSONL_RELEVENTS_DIR_RELr#   r!   r   'test_driver_outputs_outside_watched_dirr     s    !!,,-?@@@!!,,-?@@@%%00AAA%%00AAA000r!   evil_task_id)z../../../etc/task-pwnz../task-escapezsub/dir/task-xz..\task-winz/abs/task-absc                ^   t        |       }t        |       t        d      }t        d      }t	        t
              }||d<   |dd|d<   t        ||      }t        |       t        j                  t        |      |||t        	      }|j                  t        j                  k(  sJ |j                  d
k(  sJ t        |j                         dk(  sJ t        |j                         dk(  sJ t#        |      }t%        |j&                  j&                  j)                  d            }	|	g k(  sJ y )NrL   r   r_   r   r   r   r   r   r   r   r   z*.pickup.done)r    r9   r\   rb   r   r*   r1   rC   r6   rt   r?   r   rN   r   r   rj   rY   r%   listr5   rglob)
r   r   r$   rn   r   r/   r0   rp   
result_dirleakeds
             r   &test_path_traversal_task_id_quarantiner     s    hDtl3Fo6F=!G%GI0<W$UG !dG,AG
//#a&tv#,.C ;;#00000  M111v||!!!v||!!! T"J*##**00ABFR<<r!   c                   t        |       }t        |       t        d      }t        d      }t	        |      }t        |       t        j                  t        |      |||t              }|j                  t        j                  k(  sJ |j                  t        j                  k(  sJ t        |j                        dk(  sJ y )NrL   r   r_   r   rh   r   r   s         r   *test_normal_task_id_passes_traversal_guardr     s    hDtl3Fo6FdAG
//#a&tv#,.C;;#00000#++---v||!!!r!   c                   t        |       }|dz  dz  dz  }|j                  j                  dd       |j                  d       t	        j
                  t        |            dk(  sJ t	        j                  t        |            du sJ t               }t	        j                  t        |      |d	      }t        |      d
k(  sJ |d   j                  t        j                  k(  sJ t        |j                        dk(  sJ y )Nr   r   r3   Tr   s
    enabledr   F)re   rg   rh   r   )r    r5   r   write_bytesr6   read_activationr?   is_activatedr\   ri   rj   rN   rk   rY   )r   r$   r8   rn   ro   s        r   %test_failsafe_activation_invalid_utf8r     s    hD(?W$';;DKKdT2() s4y)R///CI&%///FmmCINGw<11:!:!::::v||!!!r!   c                    t        |       }|dz  dz  dz  }|j                  j                  dd       |j                  d       t	        j
                  dt        |      t        |            du sJ y )	Nr   r   zcallback_4tuple_index.jsonlTr   s    not utf8r   F)r    r5   r   r   r6   _dedupe_hitr?   )r   r$   ledgers      r   (test_failsafe_dedupe_ledger_invalid_utf8r     sk    hDH_x'*GGF
MMt4
+, ??:s6{CI>%GGGr!   c                L   dd l t        |       }t        |       t        |      dz  }|j	                  dd       t        |       fd}|j                  t        j                   d|       t        j                  t        |      t        |      d       }|J d|j                         v sd	|v sJ t               }t        j                  t        |      t        |      |t        
      }|j                  t        j                  k(  sJ t!        |j"                        dk(  sJ y )Nr   r}   r   r'   r(   c                &    j                  d      )Nzsimulated shutil.ErrorErrorsrcdst_shs     r   _boomz4test_failsafe_quarantine_shutil_error.<locals>._boom#  s    ii011r!   moveshutilu   실패r~   )r   r    r9   r%   r+   rC   setattrr6   _quarantine_mover?   lowerr\   rt   r   rN   r   rj   rY   )	r   monkeypatchr$   r0   r   msgrn   rp   r   s	           @r   %test_failsafe_quarantine_shutil_errorr     s    hDtD22ALLgL&G2

FE2 

s1vs4y$
7C??syy{"h#o55 F
//#a&s4yFY
WC;;#00000v||!!!r!   c                $   t        |       }t        |       t               }t               }t	        |      dz  }|j                  dd       t        j                  t        |      t        |      ||t              }|j                  t        j                  k(  sJ |j                  du sJ t        |j                        dk(  sJ t        |j                        dk(  sJ |j                         sJ |dz  d	z  d
z  dz  }|j                         rJ y )Nr}   '{"task_id": "task-999", "completion_sigr'   r(   r   Fr   r   r   r   )r    r9   r\   rb   r%   r+   r6   rt   r?   r   rN   VERDICT_NOOP_NOT_READYr   rj   rY   r   )r   r$   rn   r   r0   rp   qfiles          r   %test_partial_json_recent_mtime_defersr   7  s    hDtFFD22ALL:WLM //#a&s4yFf#,.C;;#44444??e###v||!!!v||!!!88::8Ok)L8;QQE||~~r!   c                   t        |       }t        |       t               }t        |      dz  }|j	                  dd       t        |d       t        j                  t        |      t        |      |t              }|j                  t        j                  k(  sJ |j                  dk(  sJ t        |j                        d	k(  sJ |j                         rJ |d
z  dz  dz  dz  j                         sJ y )Nr}   r   r'   r(   
   rA   r~   r   r   r   r   r   )r    r9   r\   r%   r+   rC   r6   rt   r?   r   rN   r   r   rj   rY   r   r   s        r   -test_old_invalid_json_quarantines_after_gracer  R  s    hDtFD22ALL:WLMB
//#a&s4yFY
WC;;#00000  L000v||!!!xxz>8Ok)L8;QQYY[[[r!   c                   t        |       }t        |       t               }t        |      dz  }|j	                  d       t        j                  t        |      t        |      |t              }|j                  t
        j                  k(  sJ |j                  du sJ |j                         sJ t        |d       t        j                  t        |      t        |      |t              }|j                  t
        j                  k(  sJ |j                  dk(  sJ t!        |j"                        dk(  sJ |j                         rJ |d	z  d
z  dz  dz  j                         sJ y )Nr}   s"   {"task_id": "task-999"   truncatedr~   Fr   r   	null_byter   r   r   r   )r    r9   r\   r%   r   r6   rt   r?   r   rN   r   r   r   rC   r   r   rj   rY   )r   r$   rn   r0   	rec_deferrec_qs         r   $test_null_byte_defer_then_quarantiner  g  s3   hDtF 	D22AMM=>ASY&S\]I : ::::  E)))88:: 	BOOCFTfyYE==C22222""k111v||!!!xxz>8Ok)L8;QQYY[[[r!   c                  
 ddl m 
 t        |       }t        |      dz  }|j                  t	        j
                  t              d       
fd}t        j                  t        |      |t              \  }}|du sJ |d	k(  sJ t        |d
       t        j                  t        |      |t              \  }}|du sJ |dk(  sJ t        j                  t        t        |      dz        |t              \  }}	|du sJ |	dk(  sJ y )Nr   datetimer}   r'   r(   c                 B     j                  t        j                        S rE   )nowr6   KSTr  s   r   rH   z+test_check_readiness_unit.<locals>.<lambda>  s    HLL) r!   )clockr   Frecent_mtimer   r   Treadyznope.result.json	stat_fail)r	  r    r%   r+   r,   r-   r*   r6   _check_readinessr?   r   rC   )r   r$   r0   r  r  reasonready2reason2ready3reason3r	  s             @r   test_check_readiness_unitr    s    !hDD22ALLM*WL=)E ((QuyQME6E>>^### 	B**3q6SOFGT>>g **3{4/@CU/U+V16LOFGU??k!!!r!   c                   t        |       }t        |       t        d      }t        d      }t	        |      }t        |       t        j                  t        |      |||t              }|j                  t        j                  k(  sJ |j                         du sJ |dz  dz  dz  }|d	z  j                         d
u sJ t        j                  t        t        |      dz              }|g k(  sJ y)u   WAKE_BUILT 도달 시 원본 memory/events 에서 삭제 + processed 에 존재.
    glob 재매칭 0 입증 (무한 재트리거 소멸 확인).rL   r   r_   r   Fr   r   	processedr}   Ttask-*.result.jsonN)r    r9   r\   rb   r1   rC   r6   rt   r?   r   rN   r   r   globr%   r   r$   rn   r   r0   rp   r  	remainings           r   +test_wake_built_moves_result_out_of_watchedr    s     hDtl3Fo6FdAG
//#a&tv#,.C;;#00000 88: x+-;I..668D@@@ 		#k$/2FFGHI??r!   c                $   t        |       }t        |       t               }t        d      }t	        |      }t        |       t        |      dz  }|j                  dd       t        j                  t        |      |||t              }|j                  t        j                  k(  sJ |j                         du sJ |d	z  d
z  dz  }|dz  j                         du sJ t        j                  t        t        |      dz              }|g k(  sJ y)uJ   dedupe done marker 존재 시 PICKUP_SKIP → 원본 processed 로 이동.r_   r   r   r   r'   r(   r   Fr   r   r  r}   Tr  N)r    r9   r\   rb   r1   rC   r%   r+   r6   rt   r?   r   rN   r   r   r  )	r   r$   rn   r   r0   r   rp   r  r  s	            r   &test_pickup_skip_done_marker_moves_outr     s   hDtFo6FdAG!77F
fw/
//#a&tv#,.C;;#11111 88: x+-;I..668D@@@ 		#k$/2FFGHI??r!   c                   t        |       }t        |       t        d      }t        d      }t	        |      }t        |       t        j                  t        |      |||t              }|j                  t        j                  k(  sJ |j                         du sJ |dz  dz  dz  }|d	z  j                         d
u sJ t        |j                        dk(  sJ y)uH   pickup_fn 이 SKIP_TERMINAL 반환 시 PICKUP_SKIP → processed 이동.SKIP_TERMINALr   r_   r   Fr   r   r  r}   Trh   N)r    r9   r\   rb   r1   rC   r6   rt   r?   r   rN   r   r   rj   rY   )r   r$   rn   r   r0   rp   r  s          r   2test_pickup_skip_terminal_from_pickup_fn_moves_outr#    s    hDto6Fo6FdAG //#a&tv#,.C;;#11111 88: x+-;I..668D@@@ v||!!!r!   c                   t        |       }t        |       t               }t               }t	        |      dz  }|j                  dd       t        j                  t        |      |||t              }|j                  t        j                  k(  sJ |j                         du sJ |dz  dz  d	z  }|dz  j                         rJ t        j                  t        t	        |      d
z              }t        |      dk(  sJ y)u   최근 mtime(부분 JSON) → NOOP_NOT_READY. 파일 잔류 + glob 길이 1 입증.
    DEFER 는 terminal 아님 — 의도적 잔류.r}   r   r'   r(   r   Tr   r   r  r  rh   N)r    r9   r\   rb   r%   r+   r6   rt   r?   r   rN   r   r   r  rj   r  s           r   test_defer_stays_for_retriggerr%    s     hDtFFD22ALL:WLM //#a&tv#,.C;;#44444 88: x+-;I22::<<< 		#k$/2FFGHIy>Qr!   c                   t        |       }t        |       t        d      }t        d      }t	        |      }t        |       t        j                  |||dt              }t        j                  t        t        |      dz              }|g k(  sJ |D cg c]"  }|j                  t        j                  k(  s!|$ }}t        |      dk(  sJ yc c}w )	us   scan_once WAKE_BUILT 완료 후 watched(memory/events) 에 result.json 0건.
    무한 재트리거 소멸 입증.rL   r   r_   Fr   r  rh   N)r    r9   r\   rb   r1   rC   r6   ri   r   r  r?   r%   rN   r   rj   )	r   r$   rn   r   r0   ro   r  rwake_recordss	            r   )test_scan_once_no_glob_rematch_after_waker)    s     hDtl3Fo6FdAGmmG 		#k$/2FFGHI??  'N!!))s7M7M*MANLN|!!! Os   "C;Cc                  	 ddl 	t        |       }t        |       t        d      }t	        d      }t        |      }t        |       d }	fd}|j                  t        j                  d|       |j                  t        j                   d	|       t        j                  t        |      |||t        
      }|j                  t        j                  k(  sJ |j                  J y)u   os.replace / shutil.move 둘 다 실패해도 process_one 크래시 없이 반환.
    rec.verdict==WAKE_BUILT 유지, rec.error 에 이동 실패 메시지 기록.r   NrL   r   r_   c                    t        d      )Nzsimulated os.replace failure)OSError)r   r   s     r   boom_oserrorz1test_terminal_move_failsafe.<locals>.boom_oserrorD  s    455r!   c                &    j                  d      )Nzsimulated shutil.move failurer   r   s     r   boom_shutilerrorz5test_terminal_move_failsafe.<locals>.boom_shutilerrorG  s    ii788r!   r   r   r   )r   r    r9   r\   rb   r1   rC   r   r6   r=   rt   r?   r   rN   r   error)
r   r   r$   rn   r   r0   r-  r/  rp   r   s
            @r   test_terminal_move_failsafer1  7  s     hDtl3Fo6FdAG69 	<8

F,<= //#a&tv#,.C ;;#00000 99   r!   c                   t        |       }t        |      dz  }|j                  t        j                  t
              d       t        j                  t        |      t        |      d      }|J |dz  dz  dz  }|dz  j                         sJ t        |      dz  }t        t
              }d|d	<   |j                  t        j                  |      d       t        j                  t        |      t        |      d      }|J t        j                  t        |            }|D 	cg c]  }	|	j                  d      s|	 }
}	t        |
      dk\  sJ d
|
dt        |
       d       yc c}	w )u|   동일 basename 두 번 _quarantine_move: 첫 파일 보존 + 두 번째는 suffix 별도 파일.
    덮어쓰기 0 검증.r}   r'   r(   Nr   r   r   r   retryu(   overwrite 방지 실패: quarantine 에 z (u   개만 존재))r    r%   r+   r,   r-   r*   r6   r   r?   r   r   r=   listdirr   rj   )r   r$   p1err1r   p2payload2err2	all_filesfmatchings              r   $test_quarantine_overwrite_protectionr=  [  sW    hD 
T	3	3BMM$**]+gM>BTD9D<<(?[(<7D))11333 
T	3	3BM"HHWMM$**X&M9BTD9D<< 

3t9%I$Ma5K(LMHMx=A 
28,bX~^ Ns   (E+?E+c                     t        t              j                         j                  d   } | dz  dz  j	                  d      }d|vsJ d       d|v sJ d	       d
|v sJ d       d|v sJ d       d|v sJ d       y)u   scripts/anu_pickup_entrypoint.sh 정적 분석:
    /tmp 고정 경로 미사용, XDG_RUNTIME_DIR 우선, mkdir -p 보장,
    symlink 거부 가드(-L), flock single-flight 유지.r   r   r   r'   r(   z/tmpu?   /tmp 고정 경로가 entrypoint 에 있어서는 안 됩니다r   u6   XDG_RUNTIME_DIR 이 entrypoint 에 있어야 합니다zmkdir -pu/   mkdir -p 가 entrypoint 에 있어야 합니다z-LuF   symlink 거부 가드(-L 검사)가 entrypoint 에 있어야 합니다r   u:   flock single-flight 가 entrypoint 에 있어야 합니다N)r   r   r   r   r   )script_rootr   s     r   -test_entrypoint_lock_no_tmp_and_symlink_guardr@  |  s     x.((*2215K
	
!$>
>	I	ISZ	I	[B ^^^ "\$\\" NNN 2:___: b=VVV=r!   )r   r   returnr   )r$   r   rA  r   )r}   N)r$   r   r.   r?   rA  r   )r$   r   rA  None)g      $@)rA   floatrA  rB  )rL   )rN   r?   )r_   )Q__doc__
__future__r   r  r,   r=   sysrT   pathlibr   pytestr   r   r   _ROOTr?   r@   insertimportlib.utilutil_ilu
_real_initmodulesr   _cachedgetattrr   r   _kspec_from_file_location_specloadermodule_from_spec_pkgexec_moduler   r
   r6   r*   r    r%   r1   r9   r<   r;   rC   r   r\   rb   rq   r{   r   r   r   r   r   r   r   r   r   r   r   markparametrizer   r   r   r   r   r   r  r  r  r  r   r#  r%  r)  r1  r=  r@  )rG   s   0r   <module>r[     sx   #   	 
    	X ((+u:SXXHHOOAs5z" Z-/

++//*
%
?ww
B7=2#j/Qs{{+\QqJ!,,{B[q\ KKO(D((JC
@R<S;TE !999 4  'D"CKK
	LLT" - 2&0I&E & !	.("*"<]6"$"&B*"*",.$$T#&	1  * @"&"*H":6\*\6"8<@":>">!HBWe ]s   H*2H*