
    jU                    F   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
mZ ddlZddlmZmZ ddlmZmZmZmZ  ee      j-                         j.                  d   dz  d	z  Zg d
ZddZej6                  j9                  de      d        Zej6                  j9                  de      d        Zej6                  j9                  de      d        Zej6                  j9                  de      d        Z ej6                  j9                  de      d        Z!d Z"d Z#d Z$d Z%d Z&y)u  tests/regression/test_callback_registration_enforcement.py

task-2635 — 5 fixture finalize_result 단언 + fail-closed 5값 enum 분기.

Spec §5 / §4.1: REGISTERED → success+cancel · NOT_REGISTERED/SENDFILE_ONLY/
REGISTER_FAILED → fail-closed+no-cancel · SKIPPED_WITH_EXPLICIT_REASON →
success+(이중잠금시) cancel.

Subprocess 실호출 0. fixture evidence.json 을 그대로 finalize_hooks 에 흘려
보내고 expected.json 과 cross-check.
    )annotationsN)Path)decide_fallback_cancelexpected_collector_spawn) NormalCallbackRegistrationStatusis_callback_completeis_fail_closed_statusis_success_status   fixturesnormal_callback_registration)registered_normalnot_registered_envelope_onlysendfile_only_no_cronregister_failed_cli_errorskipped_explicit_reason_dryrunscenarioc                    t         | z  }t        j                  |dz  j                  d            }t        j                  |dz  j                  d            }||fS )Nevidence.jsonzutf-8)encodingexpected.json)FIXTURE_ROOTjsonloads	read_text)r   sdirevidenceexpecteds       N/home/jay/workspace/tests/regression/test_callback_registration_enforcement.py
_load_pairr    +   sY    ("Dzz4/1<<g<NOHzz4/1<<g<NOHX    c                   t         | z  }d}||z  }|j                  } |       }|sddt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      t	        j                  |      dz  }t        t	        j                  |            d x}x}x}}d}||z  }|j                  } |       }|sddt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      t	        j                  |      dz  }t        t	        j                  |            d x}x}x}}d}||z  }|j                  } |       }|sddt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      t	        j                  |      dz  }t        t	        j                  |            d x}x}x}}y )Nr   zNassert %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = (%(py0)s / %(py2)s).is_file
}()
}r   )py0py2py5py7r   zPROVENANCE.md)	r   is_file@py_builtinslocals
@pytest_ar_should_repr_global_name	_safereprAssertionError_format_explanation)r   r   @py_assert1@py_assert3@py_assert4@py_assert6@py_format8s          r   /test_fixture_directories_exist_with_three_filesr4   2   sw   ("D"-D?"-"++-+--------D---D---?---+----------"-D?"-"++-+--------D---D---?---+----------"-D?"-"++-+--------D---D---?---+----------r!   c                &   t        |       \  }}|d   }|d   }||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            d x}x}}y )Nregistration_status==z%(py1)s == %(py4)spy1py4assert %(py6)spy6)r    r*   _call_reprcomparer,   r-   r.   )r   r   r   @py_assert0r0   @py_assert2@py_format5@py_format7s           r   ,test_evidence_status_matches_expected_statusrD   :   sm    #H-Hh)*Mh7L.MM*.MMMMM*.MMMM*MMM.MMMMMMMMr!   c                   t        |       \  }}|d   }t        |      }|d   }t        |      }||u }|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                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}}t        |      }
|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}x}}y )Nr6   fail_closedisz0%(py0)s is %(py6)s
{%(py6)s = %(py2)s(%(py4)s)
}boolr#   r$   r<   r>   assert %(py8)spy8)z%(py0)s is not %(py3)ssuccess)r#   py3r=   r>   )r    r	   rJ   r*   r?   r(   r)   r+   r,   r-   r.   r
   )r   r   r   statusrF   r0   @py_assert5r/   rC   @py_format9rN   rA   r1   rB   s                 r   0test_fail_closed_branching_matches_enum_contractrS   @   s3   #H-Hh+,F'/K'67$677;77777;7777777;777;777777$777$777677777777777  'G#M23223723333723333337333733323333333r!   c                   t        |       \  }}t        |      }|j                  }|d   }t        |      }||u }|sCt	        j
                  d|fd||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t	        j                  |      t	        j                  |      dz  }t	        j                  d|  d|j                   d	|j                  d
|d          dz   d|iz  }	t        t	        j                  |	            d x}x}x}}d|v r|d   }
|j                  }|
|v }|st	        j
                  d|fd|
|f      t	        j                  |
      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }t	        j                  d|  d|j                        dz   d|iz  }t        t	        j                  |            d x}
x}}y y )Nfallback_cancel_signalrG   )zU%(py2)s
{%(py2)s = %(py0)s.cancel_fallback
} is %(py8)s
{%(py8)s = %(py4)s(%(py6)s)
}decisionrJ   r#   r$   r<   r>   rM   z	scenario z: decided cancel=z	 (reason=z) vs expected=z
>assert %(py10)spy10!fallback_decision_reason_containsin)z.%(py1)s in %(py5)s
{%(py5)s = %(py3)s.reason
})r;   rO   r%   u   : reason mismatch — got z
>assert %(py7)sr&   )r    r   cancel_fallbackrJ   r*   r?   r(   r)   r+   r,   _format_assertmsgreasonr-   r.   )r   r   r   rV   r/   rQ   @py_assert7r0   rR   @py_format11r@   r1   rA   @py_format6r3   s                  r   'test_fallback_decision_matches_expectedrb   M   sa   #H-Hh%h/H## H5M,N t,N'O #'OO   #'O              $      (,    (,    -O    (P    H:.x/G/G.H I??%^H=U4V3W	Y      +h6;< 	
 	
<O 	
 	
< 	
 	
 		 = 	
 	
	6	
 	
  AI 	
 	
 		 AI 	
 	
 		 AP 	
 	
  z!;HOO;NO	
 	
 	
 	
 	
 	
 7r!   c                   t        |       \  }}t        |      }|d   }t        |      }||u }|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                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}t        |      }	|d	   }t        |      }|	|u }|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                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )Ncollector_spawn_expectedrG   rI   spawnrJ   rK   rL   rM   r   callback_complete)r    r   rJ   r*   r?   r(   r)   r+   r,   r-   r.   r   )
r   r   r   re   r0   rQ   r/   rC   rR   rf   s
             r   .test_collector_spawn_expected_matches_expectedrg   [   sZ   #H-Hh$X.E!"<=>D=>>5>>>>>5>>>>>>>5>>>5>>>>>>D>>>D>>>=>>>>>>>>>>>,X6%-.D%EF%E FF FFFFF FFFFFFFFFFFFFFFFFFFFFF%EFFF FFFFFFFFr!   c                    t               } t        D ]$  }t        |      \  }}| j                  |d          & t        D ch c]  }|j
                   }}| |k(  }|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  }t        j                  d|| z
   d| |z
         d	z   d
|iz  }t        t        j                  |            d}yc c}w )z0Each enum value appears in at least one fixture.r6   r7   )z%(py0)s == %(py2)sused
all_values)r#   r$   z'missing enum values in fixture matrix: z	; extra: z
>assert %(py4)sr<   N)set	SCENARIOSr    addr   valuer*   r?   r(   r)   r+   r,   r]   r-   r.   )	ri   r   ev_srj   r/   @py_format3rB   s	            r   4test_all_5_enum_values_are_covered_by_fixture_matrixrs   d   s*   5D ,8$A)*+, $DDa!''DJD:  4:                        2*t2C1D E#$	&     Es    Ec            	         ddl m}   | ddddddd	d
ddd
i      }|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                  }t        j                  }|j                  }||k(  }|s
t        j                  d|fd||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t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}x}}|j                  }|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                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}}y) zskipped scenario: helper accepts skip_registration=True + reason and
    produces success outcome (matches expected.json contract).r   #finalize_with_callback_registrationztask-2635-skip-testdispatch-executor-dev6z,memory/tasks/task-2635-skip-test.result.jsonz%memory/reports/task-2635-skip-test.md(0000000000000000000000000000000000000000@0fbd1dad1e110c49474dfbdf13a21fb3bdd9c7f094128004dba8472840bb832dexecutor_nameresult_pathreport_path
commit_shaspec_sha256Tzunit-test dry-run pre-approval(explicit_skip_authorizes_fallback_cancel)task_idresultskip_registrationskip_reasonseed_envelope_overridesrN   r7   z7%(py2)s
{%(py2)s = %(py0)s.finalize_result
} == %(py5)sfrr#   r$   r%   assert %(py7)sr&   N)z%(py2)s
{%(py2)s = %(py0)s.registration_status
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.SKIPPED_WITH_EXPLICIT_REASON
}.value
}r   rW   assert %(py10)srX   rG   z^%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.fallback_decision
}.cancel_fallback
} is %(py7)sr#   r$   r<   r&   assert %(py9)spy9)dispatch.finalize_hooksrv   finalize_resultr*   r?   r(   r)   r+   r,   r-   r.   r6   r   SKIPPED_WITH_EXPLICIT_REASONrn   fallback_decisionr\   )rv   r   r/   r1   r0   ra   r3   rQ   r_   rR   r`   r2   @py_format10s                r   Ctest_finalize_with_callback_registration_success_on_skipped_fixturer   q   sR    L	,%5IB"]
 4!KT R
B ************2***2*************
+HHHNNN	O  N     	   	   	     ,   ,   I   O      
 7//747/47777/477777727772777777/77747777777r!   c            	     "   ddl m}  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                  }t        j                  }|j                  }	||	k(  }|s
t        j                  d|fd||	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t        j                  |      t        j                  |	      dz  }
dd|
iz  }t        t        j                  |            dx}x}x}}	|j                  }|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                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}}y) uE   Registrar returns REGISTER_FAILED → finalize_result must be 'fail'.r   ru   c                $     G d d      } |       S )Nc                      e Zd ZdZdZdZy)ftest_finalize_with_callback_registration_fail_on_register_failed_path.<locals>.fake_runner.<locals>._P    z2{"status":"error","message":"network unreachable"}N__name__
__module____qualname__
returncodestdoutstderr r!   r   _Pr      s    JFIFr!   r   r   argvtimeoutr   s      r   fake_runnerzZtest_finalize_with_callback_registration_fail_on_register_failed_path.<locals>.fake_runner   s    	J 	J
 tr!   ztask-2635-fail-testrw   z,memory/tasks/task-2635-fail-test.result.jsonz%memory/reports/task-2635-fail-test.mdrx   ry   rz   c                     yNTr   rp   s    r   <lambda>zWtest_finalize_with_callback_registration_fail_on_register_failed_path.<locals>.<lambda>       r!   r   r   subprocess_runnercli_exists_checkfailr7   r   r   r   r   r&   N)z{%(py2)s
{%(py2)s = %(py0)s.registration_status
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.REGISTER_FAILED
}.value
}r   rW   r   rX   FrG   r   r   r   r   )r   rv   r   r*   r?   r(   r)   r+   r,   r-   r.   r6   r   REGISTER_FAILEDrn   r   r\   )rv   r   r   r/   r1   r0   ra   r3   rQ   r_   rR   r`   r2   r   s                 r   Etest_finalize_with_callback_registration_fail_on_register_failed_pathr      sM   K 
-%5IB"]
 &'
B ''''''''''''2'''2'''''''''''''
+;;;AAA	B  A     	   	   	     ,   ,   <   B       8//858/58888/588888828882888888/88858888888r!   c            	     	   ddl m}  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                  }t        j                  }|j                  }	||	k(  }|s
t        j                  d|fd||	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t        j                  |      t        j                  |	      dz  }
dd|
iz  }t        t        j                  |            dx}x}x}}	|j                  d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|j                   }|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                  |      t        j                  |      d#z  }d$d%|iz  }t        t        j                  |            dx}x}x}}d&}|j                   }|j$                  }||v }|st        j                  d'|fd(||f      t        j                  |      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}x}}y)*u   Registrar returns REGISTERED → finalize_result='success' but fallback
    cancel still requires the durable-success marker (ANCHOR-4 invariant).
    r   ru   c                $     G d d      } |       S )Nc                      e Zd ZdZdZdZy)dtest_finalize_with_callback_registration_success_on_registered_path.<locals>.fake_runner.<locals>._Pr   z {"status":"ok","id":"CRON-OK-1"}r   Nr   r   r!   r   r   r      s    J7FFr!   r   r   r   s      r   r   zXtest_finalize_with_callback_registration_success_on_registered_path.<locals>.fake_runner   s    	 	
 tr!   ztask-2635-ok-testrw   z*memory/tasks/task-2635-ok-test.result.jsonz#memory/reports/task-2635-ok-test.mdrx   ry   rz   c                     yr   r   r   s    r   r   zUtest_finalize_with_callback_registration_success_on_registered_path.<locals>.<lambda>   r   r!   r   rN   r7   r   r   r   r   r&   N)zv%(py2)s
{%(py2)s = %(py0)s.registration_status
} == %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.REGISTERED
}.value
}r   rW   r   rX   cron_schedule_idz	CRON-OK-1r9   r:   r=   r>   FrG   r   r   r   r   zdurable-success markerrZ   )zU%(py1)s in %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py3)s.fallback_decision
}.reason
})r;   rO   r%   r&   )r   rv   r   r*   r?   r(   r)   r+   r,   r-   r.   r6   r   
REGISTEREDrn   enveloper   r\   r^   )rv   r   r   r/   r1   r0   ra   r3   rQ   r_   rR   r`   r@   rA   rB   rC   r2   r   s                     r   Ctest_finalize_with_callback_registration_success_on_registered_pathr      s    L 
-#5G@"]
 &'
B ************2***2*************!!V%E%P%PV%P%V%VV!%VVVVV!%VVVVVVV2VVV2VVV!VVVVVV%EVVV%EVVV%PVVV%VVVVVVVV;;)*9k9*k9999*k999*999k99999998//858/58888/588888828882888888/88858888888#Br';';B';'B'BB#'BBBBB#'BBBB#BBBBBBrBBBrBBB';BBB'BBBBBBBBr!   c                    ddl } d}t        | |      }|sddt        j                         v st	        j
                  t              rt	        j                  t              nddt        j                         v st	        j
                  |       rt	        j                  |       ndt	        j                  |      t	        j                  |      dz  }t        t	        j                  |            dx}}y)uD   spec §3.3 §6.2 — dispatch/__init__.py 1줄 import 결선 확인.r   Nrv   z5assert %(py5)s
{%(py5)s = %(py0)s(%(py1)s, %(py3)s)
}hasattrdispatch)r#   r;   rO   r%   )	r   r   r(   r)   r*   r+   r,   r-   r.   )r   rA   r1   ra   s       r   +test_dispatch_package_exports_finalize_hookr      s    BC78BCCCCCCCC7CCC7CCCCCC8CCC8CCCBCCCCCCCCCCr!   )r   str)'__doc__
__future__r   builtinsr(   _pytest.assertion.rewrite	assertionrewriter*   r   pathlibr   pytestutils.anu_callback_fallbackr   r   utils.callback_envelope_schemar   r   r	   r
   __file__resolveparentsr   rl   r    markparametrizer4   rD   rS   rb   rg   rs   r   r   r   r   r   r!   r   <module>r      sA  
 #      X  	N$$Q'$% 	 Y/. 0. Y/N 0N
 Y/	4 0	4 Y/

 0

 Y/G 0G
869@CDDr!   