
    4j6Y                    r   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mZ ddlZddlZ ee      j!                         j"                  j"                  j"                  Z ee      e
j(                  vr"e
j(                  j+                  d ee             ddlmZ ddlmZmZmZmZmZmZmZm Z m!Z!m"Z" edz  dz  Z#edz  d	z  Z$e#d
z  Z%d'dZ&d'dZ'd(dZ(d(dZ)d(dZ*d(dZ+d(dZ,d(dZ-d(dZ.d(dZ/d(dZ0d(dZ1d(dZ2d(dZ3d(dZ4d(dZ5d(dZ6d(dZ7d(dZ8d(dZ9d(dZ:d(d Z;d(d!Z<d(d"Z=d(d#Z>d$ Z?d(d%Z@d(d&ZAy))u{  tests/regression/test_dispatch_callback_contract.py

task-2614 §7b — 회장 2026-05-20 야간 필수 보강. dispatch callback/
progress-trigger 인프라(`anu_v3.dispatch_callback_contract`)의 런타임
계약 regression. 실 모듈 + 실 entrypoint 검증(mock-only FAIL).

PASS 필수 케이스 (회장 verbatim §7b regression):
  (a) normal present → CONTRACT_OK · fallback cancel-on-success
  (b) normal missing · fallback present → fallback recovery 경로(정상 안전망)
  (c) result + normal missing + fallback missing → DISPATCH_CONTRACT_VIOLATION
      + recovery watcher required (회장 필수 fixture case-callback-gap)
  (d) recovery watcher idempotent — 동일 task 2회 호출 시 spawn 정확히 1회
  (e) recovery watcher 가 fixed-time/dead-man 아님 (조건 미충족 시 no-op)
  (f) executor self-key collector/adjudication/dispatch → fail-closed
    )annotationsN)Path)
CONTRACT_OKDISPATCH_CONTRACT_VIOLATIONEXECUTOR_SELF_KEY_FORBIDDENFALLBACK_RECOVERYINDEPENDENT_ANU_KEYExecutorSelfKeyForbiddenRecoveryWatcherclassify_dispatch_contractevaluaterun_self_checkmemoryfixturesschemasz&dispatch_callback_contract.schema.jsonz task-2614.case-callback-gap.jsonc                 T    t        j                  t        j                  d            S )Nutf-8encoding)jsonloadsSCHEMA_PATH	read_text     G/home/jay/workspace/tests/regression/test_dispatch_callback_contract.py_schemar   0   s    ::k++W+=>>r   c                 Z    t        j                  t        j                  d            d   S )Nr   r   observation)r   r   CALLBACK_GAPr   r   r   r   _gap_observationr!   4   s$    ::l,,g,>?NNr   c                    t        dddd      } | j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }d	d
|iz  }t        t        j                  |            d x}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}| j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }d	d
|iz  }t        t        j                  |            d x}}t        j                   t#                     j%                  | j'                                y )N	task-2614Ttask_idnormal_callback_presentfallback_presentresult_present==z6%(py2)s
{%(py2)s = %(py0)s.classification
} == %(py4)srecr   py0py2py4assert %(py6)spy6iszB%(py2)s
{%(py2)s = %(py0)s.fallback_cancel_on_success
} is %(py5)sr.   r/   py5assert %(py7)spy7Fz9%(py2)s
{%(py2)s = %(py0)s.recovery_required
} is %(py5)s)z5%(py2)s
{%(py2)s = %(py0)s.collector_key
} == %(py4)sr	   )r   classificationr   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationfallback_cancel_on_successrecovery_requiredcollector_keyr	   
jsonschemaDraft7Validatorr   validateto_dictr,   @py_assert1@py_assert3@py_format5@py_format7@py_assert4@py_format6@py_format8s           r   <test_a_normal_present_contract_ok_fallback_cancel_on_successrS   9   s%   
$ $	C ,,,,,,,,,,,3,,,3,,,,,,,,,,,,,,,,,,,))1T1)T1111)T11111131113111)111T1111111  )E) E)))) E))))))3)))3))) )))E)))))))3 33333 333333333333333333333 3333 33333333wy)223;;=Ar   c                    t        dddd      } | j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndd	z  }d
d|iz  }t        t        j                  |            d x}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}t        j                  t                     j!                  | j#                                y )Nr#   FTr$   r)   r+   r,   r   r-   r1   r2   r3   r:   r6   r8   r9   zJ%(py2)s
{%(py2)s = %(py0)s.recovery_is_fixed_time_or_dead_man
} is %(py5)s)r   r;   r   r<   r=   r>   r?   r@   rA   rB   rC   rE   "recovery_is_fixed_time_or_dead_manrG   rH   r   rI   rJ   rK   s           r   4test_b_normal_missing_fallback_present_is_safety_netrW   H   s   
$ %	C 2!22222!222222232223222222222!2222!22222222  )E) E)))) E))))))3)))3))) )))E)))))))11:U:1U::::1U::::::3:::3:::1:::U:::::::wy)223;;=Ar   c                    t               } t        |       }|j                  }|t        k(  }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              nddz  }dd|iz  }t        t	        j                  |            d x}}|j                  }d}||u }|st	        j
                  d	|fd
||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d x}x}}|j                  }d}||u }|st	        j
                  d	|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d x}x}}|j                  }d}||u }|st	        j
                  d	|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d x}x}}|j                  }d}||u }|st	        j
                  d	|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d x}x}}|j                   }d}||u }|st	        j
                  d	|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d x}x}}t#        j$                  t'                     j)                  |j+                                t-        j.                  t0        j3                  d            }	|	d   }
|j                  }|
d   }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d x}x}}|j                  }|
d   }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d x}x}}y )Nr)   r+   r,   r   r-   r1   r2   Tr3   r:   r6   r8   r9   z6%(py2)s
{%(py2)s = %(py0)s.result_present
} is %(py5)sFz?%(py2)s
{%(py2)s = %(py0)s.normal_callback_present
} is %(py5)sz8%(py2)s
{%(py2)s = %(py0)s.fallback_present
} is %(py5)srU   r   r   expectedr;   )z6%(py2)s
{%(py2)s = %(py0)s.classification
} == %(py5)srE   )z9%(py2)s
{%(py2)s = %(py0)s.recovery_required
} == %(py5)s)r!   r   r;   r   r<   r=   r>   r?   r@   rA   rB   rC   rE   r(   r&   r'   rV   rG   rH   r   rI   rJ   r   r   r    r   )obsr,   rL   rM   rN   rO   rP   rQ   rR   fxexps              r   6test_c_callback_gap_is_violation_and_requires_recoveryr`   V   s   

C
3-C<!<<<<<!<<<<<<<3<<<3<<<<<<<<<!<<<<!<<<<<<<<  (D( D(((( D((((((3(((3((( (((D(((((((%%%%%%%%%%%%3%%%3%%%%%%%%%%%%%&&/%/&%////&%//////3///3///&///%///////(5(5((((5((((((3(((3((((((5(((((((11:U:1U::::1U::::::3:::3:::1:::U:::::::wy)223;;=A	L**G*<	=B
Z.C6%5!66!66666!666666636663666666!66666666  <C(;$<< $<<<<< $<<<<<<<3<<<3<<< <<<$<<<<<<<<r   c                 T   g t        fd      } t               }| j                  |      }| j                  |      }| j                  |      }|d   }d}||u }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}}g }
|d   }d	}||u }|}|r|d
   }d}||u }|}|st        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }	dd|	iz  }|
j                  |       |r_t        j                  dfdf      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}x}}g }
|d   }d	}||u }|}|r|d
   }d}||u }|}|st        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }	dd|	iz  }|
j                  |       |r_t        j                  d|fd||f      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}x}}t              }d}||k(  }|st        j                  d|fd||f      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
                  |      t        j
                  |      dz  }	dd|	iz  }t        t        j                  |            d x}x}}d   d   }|t        k(  }|st        j                  d|fd|t        f      t        j
                  |      dt        j                         v st        j                  t              rt        j
                  t              nddz  }d d!|iz  }t        t        j                  |            d x}}| j                  }t        |      }d}||k(  }|s
t        j                  d|fd"||f      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
                  |      t        j
                  |      t        j
                  |      d$z  }d%d&|iz  }t        t        j                  |            d x}x}x}}y )'Nc                *    j                  | |f      S Nappendtidkeycallss     r   <lambda>zFtest_d_recovery_watcher_idempotent_exactly_one_spawn.<locals>.<lambda>j   s    sCj)A r   spawnedTr3   z%(py1)s is %(py4)spy1r0   r1   r2   Fduplicate_suppressed)z%(py3)s is %(py6)s)py3r2   z%(py8)spy8)z%(py11)s is %(py14)s)py11py14%(py16)spy16r   assert %(py19)spy19   r)   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenri   r.   rn   rp   r2   assert %(py8)sz%(py1)s == %(py3)sr	   rn   rp   assert %(py5)sr7   zR%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.spawned_keys
})
} == %(py8)swr.   rn   rp   r7   rq   assert %(py10)spy10)r   r!   maybe_spawnr<   r=   rA   rB   rC   re   _format_booloprz   r>   r?   r@   r	   spawned_keys)r   r]   r1r2r3@py_assert0rM   @py_assert2rN   rO   rL   @py_assert5rP   @py_assert10@py_assert13@py_assert12@py_format9@py_format15@py_format17@py_format18@py_format20@py_format4rQ   @py_assert7@py_assert6@py_format11ri   s                             @r   4test_d_recovery_watcher_idempotent_exactly_one_spawnr   h   s   EABA

C	
s	B	
s	B	
s	Bi= D =D    =D   =   D       H2i=HEH=E!Hb)?&@HDH&@D&HHHH=EHHH=HHHEHHHHHHH&@DHHH&@HHHDHHHHHHHHHHHHHHH2i=HEH=E!Hb)?&@HDH&@D&HHHH=EHHH=HHHEHHHHHHH&@DHHH&@HHHDHHHHHHHHHHHHHHu::?:33uu:8A;-;-----;----;------------------~~#3~#!#!####!######3###3######q###q###~######!#######r   c                    t               } t               }t        d |       }t        d |       }|j                  |      d   }d}||u }|slt	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }d	d
|iz  }t        t	        j                  |            dx}x}}|j                  |      d   }d}||u }|slt	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }d	d
|iz  }t        t	        j                  |            dx}x}}y)uP   영속 idempotency ledger 주입 시 새 watcher 인스턴스에서도 중복 0.c                     yNsr   tks     r   rj   z;test_d_idempotency_survives_shared_ledger.<locals>.<lambda>{       r   )seenc                     yr   r   r   s     r   rj   z;test_d_idempotency_survives_shared_ledger.<locals>.<lambda>|   r   r   rk   Tr3   rl   rm   r1   r2   NF)	setr!   r   r   r<   r=   rA   rB   rC   )	r   r]   w1w2r   rM   r   rN   rO   s	            r   )test_d_idempotency_survives_shared_ledgerr   w   s    D

C	)	5B	)	5B>>#y)1T1)T1111)T111)111T1111111>>#y)2U2)U2222)U222)222U2222222r   c                 t   g t        fd      } | j                  ddddd      }| j                  ddddd      }| j                  ddddd      }|d   }d}||u }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|d   }d}||u }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|d   }d}||u }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|d   }|t        k(  }|st        j                  d|fd|t        f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }	dd|	iz  }
t        t        j                  |
            dx}}g }|k(  }|st        j                  d|fd|f      dt        j                         v st        j                        rt        j                        ndt        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}}|||fD ]  }|d   }d}||u }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}} y)uU   조건 미충족 시 no-op — 시간 경과만으로 발화하는 진행트리거 0.c                &    j                  |       S rc   rd   rf   s     r   rj   zGtest_e_recovery_watcher_is_not_fixed_time_or_dead_man.<locals>.<lambda>   s    c): r   r   TFr$   t2t3rk   r3   rl   rm   r1   r2   Nr;   r)   r}   r   r~   r   r7   )z%(py0)s == %(py3)sri   r.   rp   fixed_time_or_dead_man)r   r   r<   r=   rA   rB   rC   r   r>   r?   r@   )r   r_okr_fbr_noresr   rM   r   rN   rO   r   rQ   rL   rri   s                @r   5test_e_recovery_watcher_is_not_fixed_time_or_dead_manr      s   E:;A ==D"d	<D
 ==U!T	;D
 mmU"e	=G 	?#e#?e####?e###?###e#######	?#e#?e####?e###?###e#######9&&&&&&&&&&&&&&&&&&&#$C$(CCCCC$(CCCC$CCCCCC(CCCC(CCCCCCCC5B;5B55BD'" 4)*3e3*e3333*e333*333e33333334r   c                     t        j                  t              5  t        ddddt               d d d        y # 1 sw Y   y xY w)Nr#   Tr%   r&   r'   r(   rF   )pytestraisesr
   r   r   r   r   r   .test_f_executor_self_key_collector_fail_closedr      s;    	/	0 
"$(!5	

 
 
s	   8Ac                     t        j                  t              5  t        d t               d d d        y # 1 sw Y   y xY w)Nc                     y rc   r   r   s     r   rj   zGtest_f_executor_self_key_recovery_watcher_fail_closed.<locals>.<lambda>   r   r   )rF   )r   r   r
   r   r   r   r   r   5test_f_executor_self_key_recovery_watcher_fail_closedr      s7    	/	0 C)&A	CC C Cs   6?c                     t        j                  t              5  t        ddddd       d d d        y # 1 sw Y   y xY w)Nr#   TFdeadbeefdeadbeefr   )r   r   r
   r   r   r   r   -test_f_arbitrary_non_anu_key_also_fail_closedr      s;    	/	0 
"$(",	

 
 
s   4=c                    t        j                  t                     } t        dddd      j	                         }| j                  |       t        |      }d|d<   t        j                  t         j                        5  | j                  |       d d d        t        |      }d|d<   t        j                  t         j                        5  | j                  |       d d d        y # 1 sw Y   WxY w# 1 sw Y   y xY w)Nr   FTr$   rV   executor_self_key_forbidden)
rG   rH   r   r   rJ   rI   dictr   r   ValidationError)vgoodweakweak2s       r   /test_schema_forward_rejects_weakened_invariantsr      s    ""79-A%Ut gi 	 JJt:D15D	-.	z11	2 	

4 JE+0E
'(	z11	2 	

5  
 s   ?C'C3'C03C<c                 Z   t        t        t                    } | d   }d}||u }|st        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }t        j                  |       dz   d|iz  }t        t        j                  |            d x}x}}| d   }d}||u }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }d	d|iz  }t        t        j                  |            d x}x}}t        j                  }t        |      }|sd
dt        j                         v st        j                  t              rt        j
                  t              nddt        j                         v st        j                  t              rt        j
                  t              ndt        j
                  |      t        j
                  |      dz  }t        t        j                  |            d x}}y )N
all_passedTr3   rl   rm   z
>assert %(py6)sr2   mock_only_would_failr1   z\assert %(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.classify_dispatch_contract
})
}callableDCC)r.   rn   rp   r7   )r   strr    r<   r=   rA   _format_assertmsgrB   rC   r   r   r   r>   r?   r@   )resr   rM   r   rN   rO   rP   rQ   s           r   &test_self_check_real_entrypoint_passesr      s@   
\*
+C|))$))))))))))))c)))))))%&.$.&$....&$...&...$.......223823333333383338333333C333C33323333333333r   c                    t        dddd      j                  } t        t                     j                  }| t        k(  }|st        j                  d|fd| t        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z  }d	d
|iz  }t        t        j                  |            d}|t        k(  }|st        j                  d|fd|t        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z  }d	d
|iz  }t        t        j                  |            d}| |k7  }|st        j                  d|fd| |f      dt        j                         v st        j                  |       rt        j                  |       nddt        j                         v st        j                  |      rt        j                  |      nddz  }d	d
|iz  }t        t        j                  |            d}y)ui   상수 분류기(항상 CONTRACT_OK)는 (c) callback-gap 에서 반드시 FAIL —
    실 로직 입증.r   Tr$   r)   )z%(py0)s == %(py2)sar   )r.   r/   zassert %(py4)sr0   Ncr   )!=)z%(py0)s != %(py2)s)r   r;   r   r!   r   r<   r=   r>   r?   r@   rA   rB   rC   r   )r   r   rL   @py_format3rN   s        r   -test_mock_only_constant_classifier_would_failr      sW    	#Td	 n  	!#$33A111+++++1+++++++1+++1++++++++++++++++++6MMM1MMMMMM1MMM1MMMMMMMMMMMMMMMMr   c                    t        dddg d      } | j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      d	t        j                         v st        j                  t              rt        j                  t              nd	d
z  }dd|iz  }t        t        j                  |            dx}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)u   H1: mixed-signal truthy 비-bool 입력은 명시적 bool 로 정규화돼야 한다.

    분류 분기는 truthy 동등하지만 reocrd 의 signal 필드는 진짜 bool 만 노출
    (downstream 약화/JSON-schema validation 회피 차단).
    ztask-h1-truthyrx   yes)rx         r$   r)   r+   r,   r   r-   r1   r2   NTr3   rZ   r6   r8   r9   r[   rY   )r   r;   r   r<   r=   r>   r?   r@   rA   rB   rC   r&   r'   r(   rK   s           r   :test_h1_classify_truthy_non_bool_inputs_normalized_to_boolr      s    %  ! 	C ,,,,,,,,,,,3,,,3,,,,,,,,,,,,,,,,,,,&&.$.&$....&$......3...3...&...$.......'4'4''''4''''''3'''3''''''4'''''''%%%%%%%%%%%%3%%%3%%%%%%%%%%%%%r   c                    t        dddd      } | j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      d	t        j                         v st        j                  t              rt        j                  t              nd	d
z  }dd|iz  }t        t        j                  |            dx}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)uC   H1: falsy 비-bool (0/""/None/[]) → False 정규화 → 약화 0.ztask-h1-falsyr    Nr$   r)   r+   r,   r   r-   r1   r2   Fr3   rZ   r6   r8   r9   r[   rY   )r   r;   r   r<   r=   r>   r?   r@   rA   rB   rC   r&   r'   r(   rK   s           r   9test_h1_classify_falsy_non_bool_inputs_normalized_to_boolr      s   
$ !	C <!<<<<<!<<<<<<<3<<<3<<<<<<<<<!<<<<!<<<<<<<<&&/%/&%////&%//////3///3///&///%///////(5(5((((5((((((3(((3((((((5(((((((&&&&&&&&&&&&3&&&3&&&&&&&&&&&&&r   c                    t        dddd      } | j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      d	t        j                         v st        j                  t              rt        j                  t              nd	d
z  }dd|iz  }t        t        j                  |            dx}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)u   H1: normal=truthy + fallback=falsy + result=falsy 경계.

    혼합 신호: normal truthy → CONTRACT_OK (fallback/result 와 무관).
    ztask-h1-mixedpresentr   Fr$   r)   r+   r,   r   r-   r1   r2   NTr3   rZ   r6   r8   r9   r[   r5   )r   r;   r   r<   r=   r>   r?   r@   rA   rB   rC   r&   r'   rD   rK   s           r   ,test_h1_classify_mixed_truthy_falsy_boundaryr     s   
 % )	C ,,,,,,,,,,,3,,,3,,,,,,,,,,,,,,,,,,,&&.$.&$....&$......3...3...&...$.......(5(5((((5((((((3(((3((((((5((((((())2U2)U2222)U22222232223222)222U2222222r   c                 z    ddl m}  t        j                  |       5  t	        d       ddd       y# 1 sw Y   yxY w)u8   H2: None observation → InvalidObservation fail-closed.r   InvalidObservationN!anu_v3.dispatch_callback_contractr   r   r   r   r   s    r   -test_h2_evaluate_none_observation_fail_closedr     s.    D	)	*      1:c                 z    ddl m}  t        j                  |       5  t	        i        ddd       y# 1 sw Y   yxY w)u0   H2: 빈 dict observation → InvalidObservation.r   r   Nr   r   s    r   'test_h2_evaluate_empty_dict_fail_closedr   %  s.    D	)	*   r   c                     ddl m}  dgddfD ]+  }t        j                  |       5  t	        |       ddd       - y# 1 sw Y   8xY w)uA   H2: dict 가 아닌 입력 (list/str/int) → InvalidObservation.r   r   r#   *   Nr   )r   bads     r   'test_h2_evaluate_wrong_type_fail_closedr   ,  sK    D{B/ ]]-. 	SM	 		 	s	   <A	c                     ddl m}  t        j                  |       5  t	        dddd       ddd       t        j                  |       5  t	        dddd       ddd       y# 1 sw Y   7xY w# 1 sw Y   yxY w)uL   H2: required key (task_id + 3 boolean signal) 누락 → InvalidObservation.r   r   Tr&   r'   r(   Nr#   )r%   r&   r(   r   r   s    r   1test_h2_evaluate_missing_required_key_fail_closedr   4  s|    D	)	* '+ $"
 	 
)	* "'+"	
 	   s   A"	A."A+.A7c                 h   ddl m}  ddddd}dD ];  }t        |      }d||<   t        j                  |       5  t        |       ddd       = dD ]H  }dd	id	d
gfD ];  }t        |      }|||<   t        j                  |       5  t        |       ddd       = J y# 1 sw Y   xY w# 1 sw Y   VxY w)uP   H2: boolean signal 자리에 None / dict / list 등 silent-truthy 잡음 차단.r   r   r#   Tr$   r   Nxrx   r   )r   r   r   r   r   r   )r   baser   r   r   s        r   ?test_h2_evaluate_none_or_wrong_typed_boolean_signal_fail_closedr   H  s    D#' 	D O 4jA]]-. 	SM	 	 O (QF# 	At*CCF12  		 	 s   BB(B%	(B1c                 0   t               } t        |       }|j                  }|t        k(  }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              nddz  }dd|iz  }t        t	        j                  |            dx}}y)	u?   H2: 기존 PASS-path (정합 fixture / dict 입력) 는 byte-0.r)   r+   r,   r   r-   r1   r2   N)r!   r   r;   r   r<   r=   r>   r?   r@   rA   rB   rC   )r]   r,   rL   rM   rN   rO   s         r   !test_h2_evaluate_pass_path_byte_0r   `  s    

C
3-C<!<<<<<!<<<<<<<3<<<3<<<<<<<<<!<<<<!<<<<<<<<r   c                   
 g t               i 
d
fd} t        |       j                        }|d   }d}||u }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}t              }d
}||k(  }|st        j                  d|fd||f      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
                  |      t        j
                  |      dz  }t        j                  d      dz   d|iz  }	t        t        j                  |	            d	x}x}}
d   d   }d}||u }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}
d   d   }d}||u }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}y	)u   H3: mark-then-act atomic — 재진입 시도(spawn_fn 안에서 maybe_spawn
    재호출)에서도 spawn 정확히 1회 강화. write-then-mark 약점 봉합.c                T    j                  | |f       j                        d<   y)Nreentryrk   )re   r   )rg   _keycapturedr]   spawn_callsr   s     r   reentrant_spawnz_test_h3_idempotency_atomic_record_order_blocks_concurrent_double_spawn.<locals>.reentrant_spawnr  s+    C;'mmC0r   rk   Tr3   rl   rm   r1   r2   Nrx   r)   ry   rz   r   r{   uW   재진입 호출이 H3 atomic mark-then-act 위반으로 두 번째 spawn 호출 발생z
>assert %(py8)srq   r   Fro   rg   r   r   r   returnr   )r!   r   r   r<   r=   rA   rB   rC   rz   r>   r?   r@   r   )r   r   r   rM   r   rN   rO   r   rP   r   r   r]   r   r   s             @@@@r   Ftest_h3_idempotency_atomic_record_order_blocks_concurrent_double_spawnr  g  s/    K

C
 H  	(A	cAY<4<4<4<4{ q q    q                             !    	b     Iy)2U2)U2222)U222)222U2222222I56>$>6$>>>>6$>>>6>>>$>>>>>>>r   c                 "   g t               } dfd}t        |      }t        j                  t              5  |j                  |        ddd       |j                  }g }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d      dz   d	|iz  }t        t        j                  |            dx}x}}|j                  |       }|d
   }	d}|	|u }
|
slt        j                  d|
fd|	|f      t        j                  |	      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}	x}
}t!              }
d}|
|k(  }|st        j                  d|fd|
|f      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                  |
      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}
x}}|j                  }
t!        |
      }d}||k(  }|s
t        j                  d|fd||f      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                  |
      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}
x}x}}y# 1 sw Y   xY w)uK   H3: spawn_fn 예외 → idempotency 마킹 rollback (재시도 deadlock 0).c                Z    j                  |        t              dk(  rt        d      y)Nrx   u   transient — retry next timezspawned-on-retry)re   rz   RuntimeError)rg   r   attemptss     r   flaky_spawnzBtest_h3_idempotency_rollback_on_spawn_failure.<locals>.flaky_spawn  s*    x=A>??!r   Nr)   )z4%(py2)s
{%(py2)s = %(py0)s.spawned_keys
} == %(py5)sr   r6   u5   idempotency rollback 미실행 — 재시도 deadlockz
>assert %(py7)sr9   rk   Tr3   rl   rm   r1   r2   r   ry   rz   r  r{   r|   rq   rx   r   r   r   r   r   )r!   r   r   r   r  r   r   r<   r=   r>   r?   r@   rA   r   rB   rC   rz   )r]   r  r   rL   rP   rM   rQ   rR   r   r   r   rN   rO   r   r   r   r   r   r  s                     @r   -test_h3_idempotency_rollback_on_spawn_failurer    sS   H

C" 	$A	|	$ 	c>>XRX>RXXX>RXXXXXX1XXX1XXX>XXXRXXX!XXXXXXXX	
s	Bi= D =D    =D   =   D       x=A=A=A33xx=A~~#3~#!#!####!######3###3######q###q###~######!####### s   PPc                    ddl } ddl}t        dz  dz  }|j                         sy|j                  j                  d      }|t        |dd      t        |      k(  r|S |Mt        |j                        D ]5  }|dk(  s|j                  d      s|j                  j                  |d       7 | j                  j                  dt        |      t        t        dz        g      }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}}| j                  j1                  |      }||j                  d<   |j                  j3                  |       |S )u  pytest test-collection 이 tests/ 를 sys.path 에 먼저 추가하여 비어 있는
    tests/dispatch/__init__.py 가 진짜 /home/jay/workspace/dispatch 패키지를
    가리는 환경을 우회한다. 본 헬퍼는 WORKSPACE 의 dispatch 패키지를 직접
    file-location 으로 로드하여 sys.modules 에 명시적으로 등록한다(테스트
    범위 한정, 다른 테스트에 영향 0 — 이미 동일 패키지로 표준화).r   Ndispatchz__init__.py__file__r   z	dispatch.)submodule_search_locationsis not)z%(py2)s is not %(py5)sspec)r/   r7   z%(py7)sr9   )z5%(py11)s
{%(py11)s = %(py9)s.loader
} is not %(py14)s)py9rr   rs   rt   ru   rv   rw   )importlib.utilsys	WORKSPACEexistsmodulesgetgetattrr   list
startswithpoputilspec_from_file_locationloaderr<   r=   r>   r?   r@   rA   re   r   rB   rC   module_from_specexec_module)	importlib_syspkg_initexistingr   r  rL   rP   rM   r   r   r   r   rQ   rR   r   r   r   r   pkgs                       r   !_force_workspace_dispatch_packager$    s    :%5H??||
+H*b AS] Rdll# 	*AJ!,,{";  D)	* >>11H$'	J(>$?#@ 2 D
 8t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"DLLKKC Jr   c            
        ddl } ddl} t                t        t        dz        }| j
                  j                  d|      }| j                  j                  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  }d	d
|iz  }t        t        j                   |            dx}}| j                  j#                  |      }|j%                  |       d}	d}
t'        ||	|
      }t)        |      }|sGddt        j                         v st        j                  t(              rt        j                  t(              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                  |	      t        j                  |
      t        j                  |      t        j                  |      dz  }t        t        j                   |            dx}	x}
x}}d}	d}
t'        ||	|
      }t)        |      }|sGddt        j                         v st        j                  t(              rt        j                  t(              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                  |	      t        j                  |
      t        j                  |      t        j                  |      dz  }t        t        j                   |            dx}	x}
x}}d}d}t'        |||      }|t*        k(  }|sWt        j                  d|fd|t*        f      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                  |      t        j                  |      t        j                  |      dt        j                         v st        j                  t*              rt        j                  t*              nddz  }dd|iz  }t        t        j                   |            dx}x}x}}d}d}t'        |||      }|t,        k(  }|sWt        j                  d|fd|t,        f      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                  |      t        j                  |      t        j                  |      dt        j                         v st        j                  t,              rt        j                  t,              nddz  }dd|iz  }t        t        j                   |            dx}x}x}}|j/                  dddd      }|j0                  }|t2        k(  }	|	st        j                  d|	fd|t2        f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t2              rt        j                  t2              nddz  }d d!|iz  }t        t        j                   |            dx}}	t5        j6                  |j8                        5  |j;                  t,               ddd       y# 1 sw Y   yxY w)"u   Site #1 결선 핵심: dispatch.py 가 dispatch_callback_contract 의 정본
    심볼을 재내보내야 한다(`import dispatch as pkg` 가 아니라 shim 파일 직접
    로드 — 'import dispatch' 는 패키지를 해석한다).r   Nzdispatch.pydispatch_shim_file_tr  )z%(py0)s is not %(py3)sr  r   r   r7   r   z^assert %(py10)s
{%(py10)s = %(py0)s(%(py8)s
{%(py8)s = %(py1)s(%(py2)s, %(py4)s, %(py6)s)
})
}r   r  mod)r.   rn   r/   r0   r2   rq   r   'assert_collector_key_is_independent_anur	   r)   )zB%(py7)s
{%(py7)s = %(py0)s(%(py1)s, %(py3)s, %(py5)s)
} == %(py9)s)r.   rn   rp   r7   r9   r  zassert %(py11)srr   r   task-2620-wiringTr$   r+   r,   r   r-   r1   r2   )importlib.machineryr  r$  r   r  	machinerySourceFileLoaderr  spec_from_loaderr<   r=   r>   r?   r@   rA   rB   rC   r  r  r  r   r	   r   r   r;   r   r   r   r
   r(  )r  	shim_pathr  r  r   rL   r   rQ   r'  rM   r   r   @py_assert9r   rP   r   @py_assert8@py_format10@py_format12r,   rN   rO   s                         r   7test_wiring_dispatch_py_shim_reexports_contract_symbolsr3    s     &'I-.I  112H)TF>>**+A6JD4t4t44t
..
)
)$
/C
s!=EtEGC!=tDE8DEEEEEEEE8EEE8EEEEEEGEEEGEEEEEECEEECEEE!=EEEtEEEDEEEEEEEEEE!JRDRGC!JDQR8QRRRRRRRR8RRR8RRRRRRGRRRGRRRRRRCRRRCRRR!JRRRDRRRQRRRRRRRRRR-KtK73-t4K48KKKKK48KKKKKKK7KKK7KKKKKK3KKK3KKK-KKKtKKK4KKKKKK8KKKK8KKKKKKKK5[t[735t<[<@[[[[[<@[[[[[[[7[[[7[[[[[[3[[[3[[[5[[[t[[[<[[[[[[@[[[[@[[[[[[[[

(
("Dd ) C ,,,,,,,,,,,3,,,3,,,,,,,,,,,,,,,,,,,	s33	4 Q334OPQ Q Qs   7aac                 ~   t                ddlm}   | ddt        t        dddddd	d
dd      }|j
                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|j                  }d}||u}|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|j                  }t        |v }|st        j                  d|fdt        |f      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  }dd|iz  }t        t        j                  |            dx}} | ddt        t        ddd      }	|	j
                  }d }||k(  }|st        j                  d|fd||f      d!t        j                         v st        j                  |	      rt        j                  |	      nd!t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|	j                  }d}||u }|st        j                  d"|fd#||f      d!t        j                         v st        j                  |	      rt        j                  |	      nd!t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}d$ |	j                  D        }t!        |      }|sd%d&t        j                         v st        j                  t               rt        j                  t               nd&t        j                  |      t        j                  |      dz  }t        t        j                  |            dx}} | d'dt        d(dd)d      }
|
j
                  }d }||k(  }|st        j                  d|fd||f      d*t        j                         v st        j                  |
      rt        j                  |
      nd*t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|
j                  }d}||u }|st        j                  d"|fd#||f      d*t        j                         v st        j                  |
      rt        j                  |
      nd*t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)+uE  Site #2 결선 핵심: dispatch.normal_fallback_callback_helper.build_anu
    _owned_callback_request 가 dispatch_callback_contract.assert_collector
    _key_is_independent_anu 를 통해 executor self-key 를 추가로 차단해야
    한다. enforce_callback_owner 와 동일 케이스에서 FAIL — strictly 더 강함.r   ) build_anu_owned_callback_requestnormalr)  
6937032012z[task-2620 wiring test] normalz2026-05-20 23:59:00znormal-trace-cronzfallback-trace-cronzdispatch-trace-cronTcokacdir_cron_direct)kindr%   executor_key	owner_keychat_idpromptatcron_idnormal_collector_cron_idfallback_callback_cron_iddispatch_cron_idprompt_claims_anu_collector
entry_pathPASSr)   )z/%(py2)s
{%(py2)s = %(py0)s.verdict
} == %(py5)sreq_passr6   r8   r9   Nr  )z0%(py2)s
{%(py2)s = %(py0)s.argv
} is not %(py5)s)in)z,%(py0)s in %(py4)s
{%(py4)s = %(py2)s.argv
}r	   r-   r1   r2   z1[task-2620 wiring test] should never produce argv)r9  r%   r:  r;  r<  r=  r>  FAILreq_selfr3   )z,%(py2)s
{%(py2)s = %(py0)s.argv
} is %(py5)sc              3  $   K   | ]  }d |v  
 yw)zBdispatch_callback_contract.assert_collector_key_is_independent_anuNr   ).0r   s     r   	<genexpr>zNtest_wiring_normal_fallback_helper_defends_against_self_key.<locals>.<genexpr>  s       	MPQQs   z,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyfallbackr   z)[task-2620 wiring test] arbitrary non-ANUreq_arb)r$  (dispatch.normal_fallback_callback_helperr5  r   r	   verdictr<   r=   r>   r?   r@   rA   rB   rC   argvreasonsrM  )r5  rF  rL   rP   rM   rQ   rR   rN   rO   rI  rO  s              r   ;test_wiring_normal_fallback_helper_defends_against_self_keyrT    sB   
 &'
 0"0%/ #!4"7.$()H %v%v%%%%v%%%%%%8%%%8%%%%%%v%%%%%%%==$$=$$$$=$$$$$$8$$$8$$$=$$$$$$$$$$"*--/-////-///////////////(///(///-/////// 0"0-B H %v%v%%%%v%%%%%%8%%%8%%%%%%v%%%%%%%== D =D    =D      8   8   =   D       !! 3                         /"0$: G ??$f$?f$$$$?f$$$$$$7$$$7$$$?$$$f$$$$$$$<<4<4<477<4r   )r   r   )r   None)B__doc__
__future__r   builtinsr>   _pytest.assertion.rewrite	assertionrewriter<   r   r  pathlibr   rG   r   r
  resolveparentr  r   pathinsertr   dispatch_callback_contractr   r   r   r   r   r	   r
   r   r   r   r   FIXTURESr   r    r   r!   rS   rW   r`   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r$  r3  rT  r   r   r   <module>rc     s=   #    
   N""$++2299	y>!HHOOAs9~& /   x*,)#&NN<<?O
B
B=$$34<
C
(4
$&&'3$(0=?6$8BQB; r   