
    4jA                       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 ddlmZ  ee      j)                         j*                  d   Z ee      ej0                  vr"ej0                  j3                  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| jG                  d      s|  c} D ]  Z$ej<                  e$=   ejJ                  de eedz        g      Z&g Z'dZ(e&e(uZ)e)Z*e)re&jV                  Z,dZ-e,e-uZ.e.Z*e*sB ej^                  de)fde&e(f      d ej`                         v s ejb                  e&      r ejd                  e&      nd ejd                  e(      dz  Z3dde3iz  Z4e'jk                  e4       e)r ej^                  de.fde,e-f      d ej`                         v s ejb                  e&      r ejd                  e&      nd ejd                  e,       ejd                  e-      dz  Z6dde6iz  Z7e'jk                  e7        ejp                  e'd      i z  Z9dde9iz  Z: e; ejx                  e:            dxZ*xZ'xZ)xZ(xZ,xZ.Z- ejz                  e&      Z>e>ej<                  d<   e&jV                  j                  e>       ddl@mAZB ddlCmDZDmEZEmFZFmGZGmHZH  G d d      ZI G d d      ZJd ZKd  ZLd! ZM G d" d#      ZNd)d*d$ZOd+d%ZP G d& d'ej                        ZReSd(k(  r ej                          yyc c} w ),u  tests/regression/test_p0b_callback_launch_signature_2763.py

task-2763 — callback_launch_fn call-time 시그니처 회귀 테스트.

수정 대상: dispatch/anu_pickup_driver.py scan_live_inbox_once (line ~1826) 가
callback_launch_fn 을 단일 dict positional 로 호출하던 결함을,
_fn(result_json_path, *, task_id, sha256, executor_key="", ...) 시그니처에 맞게
명시 kwarg 전달로 수정했다:
    callback_launch_fn(p, task_id=task_id, sha256=sha, executor_key=executor_key)

회귀 핵심:
  - 기존 mock/spy(아무거나 받는 lambda) 는 결함을 가린다.
  - 본 테스트는 **실제 build_callback_launch_fn factory** 를 사용해 결함 노출/방지한다.
  - 수정 전 코드(dict positional)면 TypeError → FIRE_FAILED 로 이 테스트 FAIL.
  - 수정 후에는 TypeError 없이 PASS.

★ 모든 테스트: runner_fire_fn=fake(실 cron/systemd/subprocess 발사 0).
   canonical root 미접촉 · tmp_path hermetic.
    )annotationsN)Path)List   dispatchz__init__.py__file__ z	dispatch.)submodule_search_locations)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py16zassert %(py19)spy19)anu_pickup_driver)build_callback_launch_fnLAUNCH_NOOP_DISABLEDLAUNCH_ENFORCEDLAUNCH_NO_RESULT_JSONLAUNCH_FAILc                      e Zd ZdZd Zy)_FakeFireResultu9   anu_runner_pickup_and_fire 가 반환하는 ok+argv mock.c                0    d| _         dg| _        g | _        y )NTz	fake-argv)okargvreasonsselfs    O/home/jay/workspace/tests/regression/test_p0b_callback_launch_signature_2763.py__init__z_FakeFireResult.__init__B   s     M	    N)__name__
__module____qualname____doc__r$    r%   r#   r   r   @   s
    C r%   r   c                      e Zd ZdZd Zd Zy)_FakeFireFnuI   실 cron/subprocess 발사 0 — 기록만 남기는 fake runner_fire_fn.c                    g | _         y N)callsr!   s    r#   r$   z_FakeFireFn.__init__K   s	    !#
r%   c               T    | j                   j                  |||d       t               S )N)result_json_pathexecutor_keyanu_key)r/   appendr   )r"   r1   r2   r3   anu_keyskwargss         r#   __call__z_FakeFireFn.__call__N   s-    

 0(
 	
   r%   Nr&   r'   r(   r)   r$   r7   r*   r%   r#   r,   r,   H   s    S$!r%   r,   c                 "    t         j                  S )uB   activation flag_reader: ACTIVE 활성 모사(실파일 미생성).)drvACTIVATION_ENABLEDr*   r%   r#   _enabledr<   X   s    !!!r%   c                     ddl m}  | S )u3   callback launch ACTIVE flag reader: enabled 반환.r   CALLBACK_LAUNCH_ENABLED)"dispatch.anu_callback_launch_auditr?   r>   s    r#   _cb_flag_enabledrA   ]   s    J""r%   c                      y)u4   callback launch ACTIVE flag reader: disabled 반환.r	   r*   r*   r%   r#   _cb_flag_disabledrC   c   s    r%   c                  $    e Zd ZdZddZdddZy)_GateuC   owner_gate_fn 결과 모사. ready=True → ANU owner proof 통과.c                P    || _         |rt        j                  | _        y d| _        y )NOWNER_PICKUP_BLOCKED)readyr:   GATE_READY_STATUSstatus)r"   rH   s     r#   r$   z_Gate.__init__j   s    
/4c++:Pr%   r	   )r2   c                   | S r.   r*   )r"   pathr2   s      r#   r7   z_Gate.__call__n   s    r%   N)rH   boolr8   r*   r%   r#   rE   rE   h   s    MQ .0 r%   rE   c                   t        j                  j                  | gt        j                  j                  d       }t        j                  |d       t         j                  j                  || d      }t        |dd      5 }|j                  t        j                  ||dd	
             ddd       |S # 1 sw Y   |S xY w)uK   tmp root 의 LIVE_INBOX 에 task-XXXX.result.json 작성 → 경로 반환./T)exist_okz.result.jsonwzutf-8)encoding)task_idbodyF)ensure_asciiN)osrL   joinr:   LIVE_INBOX_DIR_RELsplitmakedirsopenwritejsondumps)rootrS   rT   dpfhs         r#   _write_live_resultrc   r   s    
T>C2288=>AKKD!
Q7)<01A	aw	' U2
>USTUHUHs   *B::Cc                    t        j                         }t        | d      5 t        fdd      D ]  }|j	                  |        	 d d d        |j                         S # 1 sw Y   |j                         S xY w)Nrbc                 &     j                  d      S )Ni   )read)rb   s   r#   <lambda>z_sha256_of.<locals>.<lambda>   s    "''%. r%   r%   )hashlibsha256r[   iterupdate	hexdigest)rL   hchunkrb   s      @r#   
_sha256_ofrp   |   si    A	dD	 R0#6 	EHHUO	 ;;= ;;=s   &A!!A9c                  (    e Zd ZdZd Zd Zd Zd Zy)TestCallbackLaunchSignature2763uW   callback_launch_fn 시그니처 회귀 — 실 factory build_callback_launch_fn 사용.c                H   t               }t        dt        |      }t        j                         5 }t
        j                  j                  |d      }t        |d      5 }|j                  d       ddd       	  ||dd	      }ddd       | j                  j                  t        d|j                          | j                  t        |j                         dd       y# 1 sw Y   rxY w# t        $ r}| j                  d
| d       Y d}~d}~ww xY w# 1 sw Y   xY w)u<  실제 build_callback_launch_fn 이 반환하는 _fn 을
        _fn(result_json_path, task_id=..., sha256=...) 형태로 호출 가능한지 검증.

        ACTIVE flag OFF 환경 → NOOP_DISABLED 반환(no-op) — 시그니처 호환만 확인.
        실 cron 발사 0(flag OFF + runner_fire_fn=fake).
        z/nonexistent-fake-root)r_   flag_readerrunner_fire_fnztask-2763-x.result.jsonrQ   z{"task_id":"task-2763-x"}Nztask-2763-xaabbccrS   rj   uL   build_callback_launch_fn 반환 _fn(path, task_id=, sha256=) 가 TypeError: u   
→ 시그니처 회귀.u'   flag OFF → NOOP_DISABLED 기대, got=r   u   flag OFF → 실 fire 호출 0)r,   r   rC   tempfileTemporaryDirectoryrV   rL   rW   r[   r\   	TypeErrorfailassertEqualverdictr   lenr/   )r"   	fake_fire_fntmpra   rb   resultes           r#   Itest_real_factory_fn_signature_accepts_positional_path_and_keyword_id_shaziTestCallbackLaunchSignature2763.test_real_factory_fn_signature_accepts_positional_path_and_keyword_id_sha   s     M	&))$
 ((* 	cS";<Aa 6456QhG	 	NN05fnn5EF	
 	Y__-q2RS!6 6
  		""#$>@ 	 	sG   -DC!0D9C-!C*	&D-	D6DDDDD!c           
     "   t               }t        j                         5 }t        |t        |t
        j                  j                  |d            }t        |d      }t
        j                  j                  |d      }t
        j                  j                  |d      }t        d      }	 t        j                  |t        |||g||      }D 
cg c]  }
|
j                   }}
|D ]G  }|j                  t        j                   k(  s!t#        |dd      xs d}| j%                  d|d|        I | j'                  t)        |      dd       ddd       y# t        $ r}	| j                  d	|	 d
       Y d}	~	d}	~	ww xY wc c}
w # 1 sw Y   yxY w)u  scan_live_inbox_once 에 실제 build_callback_launch_fn factory 결과를 주입하고,
        activation ON + owner_gate ready(fake) + 유효한 result.json 1건 배치.

        scan 실행 시 TypeError 없이 callback_launch_fn 까지 도달해야 한다.

        ★ 회귀 핵심: 수정 전 코드(dict positional 호출)면
          TypeError → FIRE_FAILED 로 이 테스트 FAIL.
          수정 후엔 PASS (결과 verdict != FIRE_FAILED).
        fake_audit.jsonlr_   rt   ru   
audit_pathztask-2763-yledger.jsonl	processedTrH   )rt   owner_gate_fncallback_launch_fnpathsledger_pathprocessed_diruD   scan_live_inbox_once 내 callback_launch_fn 호출에서 TypeError: uC   
→ callback_launch_fn(p, task_id=...) 호출 시그니처 회귀.Nerrorr	   rz   uL   FIRE_FAILED verdict 의 error 에 TypeError 포함 — 시그니처 회귀: r   u'   scan 이 record 를 반환하지 않음)r,   rx   ry   r   rA   rV   rL   rW   rc   rE   r:   scan_live_inbox_oncer<   rz   r{   r}   VERDICT_FIRE_FAILEDgetattrassertNotInassertGreaterr~   )r"   r   r_   r   ra   ledgerpdirgaterecordsr   rverdictsrecerrs                 r#   ;test_scan_live_inbox_reaches_real_factory_without_typeerrorz[TestCallbackLaunchSignature2763.test_scan_live_inbox_reaches_real_factory_without_typeerror   s     M	((* /	[d*,(77<<.@A	C #47AWW\\$7F77<<k2Dt$D22 ("&'*# &"& ,33a		3H3
  ;;#"9"99!#w39rC$$#Sfgjfkl s7|Q0YZ_/	[ /	[6  		Z[\Z] ^Y Y  4C/	[ /	[sI   B
F*!EFF "$FAF	E=E83F8E==FFc                   t               }g t        j                         5 }t        |t        |t
        j                  j                  |d            dddddfd
}t        |d      }t        j                  |      }t        j                  |      }t
        j                  j                  |d      }t
        j                  j                  |d	      }t        d
      }		 t        j                  |t        |	|d|g||       | j#                  t%              dd       d   }| j#                  |d   |d| d|d           | j#                  |d   |d| d|d           | j#                  |d   |d| d|d           | j#                  |d   dd|d           ddd       y# t        $ r}
| j!                  d|
        Y d}
~
d}
~
ww xY w# 1 sw Y   yxY w)u  scan_live_inbox_once 가 callback_launch_fn 에 전달하는 인자를 캡처하여 검증.

        result_json_path == 실제 result 파일 경로(p)
        task_id == _legacy_skip_task_id(p) 값
        sha256 == _sha256_file(p) 값
        executor_key == scan 에 전달된 executor_key

        실 _fn 을 감싸 인자를 기록 후 위임하는 wrapper 사용(단순 spy 아님 — 실 factory 경유).
        r   r   r	   F)r2   schedule_idterminal_intentrelay_requiredc          	     N    j                  | |||d        | ||||||      S )u,   실 _fn 을 감싸 인자 캡처 후 위임.)r1   rS   rj   r2   )rS   rj   r2   r   r   r   )r4   )	r1   rS   rj   r2   r   r   r   _real_fncaptured_callss	          r#   _capturing_wrapperziTestCallbackLaunchSignature2763.test_callback_launch_called_with_correct_args.<locals>._capturing_wrapper  sH     %%(8&$$0	'   $#!!- +$3#1 r%   ztask-2763-zr   r   Tr   zfake-executor-key)rt   r   r   r2   r   r   r   u   wrapper 호출 중 TypeError: N   u9   callback_launch_fn 이 정확히 1회 호출돼야 한다r   r1   u%   result_json_path 불일치: expected=z, got=rS   u   task_id 불일치: expected=rj   u   sha256 불일치: expected=r2   u   executor_key 불일치, got=)r,   rx   ry   r   rC   rV   rL   rW   rc   r:   _legacy_skip_task_id_sha256_filerE   r   r<   rz   r{   r|   r~   )r"   r   r_   r   ra   expected_task_idexpected_shar   r   r   r   callr   r   s               @@r#   -test_callback_launch_called_with_correct_argszMTestCallbackLaunchSignature2763.test_callback_launch_called_with_correct_args   s     M	%'((* O	d 0-(77<<.@A	H WY/12V[& #47A"77:++A.LWW\\$7F77<<k2Dt$D@(( ("&'9!4# &"&	 S0!XZ "!$D '(!7s&FXAY@Z[ Y!1./?.@tIFWX X-l^6$x.AQR ^$&9.tN/C.DEYO	 O	`  @		:1#>??@aO	 O	s7   C G$"F)BG)	G2GGGGGc           
        ddl m} |j                  }t               }| j	                  ||d       | j                  t        |      j                  t        |      j                  d       t        j                         5 }t        |t        |t        j                  j                  |d            }t        j                  j                  |d      }t        |d      5 }|j!                  d	       ddd        ||d
d      }|j"                  t$        k(  rY| j'                  t)        |j*                        dd       |j*                  d   }	| j-                  d|	       | j-                  d|	       | j/                  |j0                  t        d       | j3                  t)        |j*                        ddt)        |j*                                ddd       y# 1 sw Y   xY w# 1 sw Y   yxY w)u  모든 테스트에서 runner_fire_fn 이 fake 임을 보장하는 가드 테스트.

        fake_fire.calls 로 호출 기록만 남기고, 실 cron/systemd/subprocess 는 0.
        _FakeFireFn 이 실 anu_runner_pickup_and_fire 와 다름을 증명한다.
        r   NuN   fake_fire 는 실 anu_runner_pickup_and_fire 와 다른 객체이어야 한다uH   fake_fire 는 _FakeFireFn 이고 실 fire 와 타입이 달라야 한다r   r   ztask-2763-guard.result.jsonrQ   z{"task_id":"task-2763-guard"}ztask-2763-guard
deadbeef00rw   r   u5   LAUNCH_ENFORCED → fake_fire 1회 호출(실 cron 0)r1   r3   uQ   runner_fire_fn 은 _FakeFireFn 이어야 한다(실 cron 발사 구조적 차단)u;   fake_fire 가 2회 이상 호출됨(중복 발사 위험): )'dispatch.anu_owned_callback_enforcementanu_owned_callback_enforcementanu_runner_pickup_and_firer,   assertIsNotassertNotEqualtyper&   rx   ry   r   rA   rV   rL   rW   r[   r\   r}   r   r|   r~   r/   assertInassertIs	__class__assertLessEqual)
r"   _real_module	real_firer   r_   r   ra   rb   r   r   s
             r#   !test_fire_fn_is_fake_no_real_cronzATestCallbackLaunchSignature2763.test_fire_fn_is_fake_no_real_cronJ  s    	G ;;	M	 	y\	
 	O$$d9o&>&>V	

 ((* #	d*,(77<<.@A	C T#@AAa :89: $5lKF ~~0  Y__!5q!XZ !q)0$7i. MM##[c   IOO$aMcR[RaRaNbMcdA#	 #	: :#	 #	s&   =AGG-CGG	GG'N)r&   r'   r(   r)   r   r   r   r   r*   r%   r#   rr   rr      s    a!TH;[|\~8r%   rr   __main__)r   )r_   strrS   r   rT   r   returnr   )rL   r   r   r   )Ur)   
__future__r   builtins@py_builtins_pytest.assertion.rewrite	assertionrewrite
@pytest_arri   r]   rV   sysrx   unittestpathlibr   typingr   r   resolveparents_ROOTr   rL   insertimportlib.utilutil_ilu
_real_initmodulesget_cachedr   list
startswith_kspec_from_file_locationr   @py_assert1@py_assert4@py_assert3@py_assert0loader@py_assert10@py_assert13@py_assert12_call_reprcomparelocals_should_repr_global_name	_saferepr@py_format6@py_format8r4   @py_format15@py_format17_format_boolop@py_format18@py_format20AssertionError_format_explanationmodule_from_spec_pkgexec_moduler   r   r:   r@   r   r   r   r   r   r   r,   r<   rA   rC   rE   rc   rp   TestCaserr   r&   main)ks   0r#   <module>r      s  & #     	 
     	X ((+u:SXXHHOOAs5z" Z-/

++//*
%
?ww
B7=2#j/Qs{{+\QqJ!,,{B[q\ KKO(D((JC
@R<S;TE :9599T9T!9999599999599959999999999T9999999999999T9999999999999 4  'D"CKK
	LLT" -    ! ! "
#
 }h&7&7 }@ zHMMO u
 ]s   *MM