
    PJjVJ                    h   d Z ddlmZ ddlZddlZddlZddlZddlmZm	Z	 ddl
mZ ddlmZmZmZ ddlmZmZmZmZmZmZ ddlmZmZ d	Zd
Ze G d d             Ze G d d             ZddZ	 	 	 	 	 	 	 	 	 	 ddZddZ 	 	 	 	 	 	 	 	 	 	 	 	 ddZ!eddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ"g dZ#y)uB  utils/operational_collector_wiring.py

task-2553+25 — OPERATIONAL COLLECTOR WIRING.

목적 (회장 verbatim, task-2553+25 §2):
  normal completion callback collector **durable-success 직후**
  ``run_operational_cancel_seam(operational=True)`` 를 **1회 호출**하도록
  운영 collector 경로에 결선한다. md 박제가 아닌 실행 결선.

결선 위치·방식 (§4 / 9-R.2 — additive seam-call only, frozen byte-0):
  * 본 모듈은 **신규 strict-additive wrapper** 이다.
    ``utils/anu_delegation_completion_callback.py`` (frozen anchor,
    sha256 83b3e307…) 를 **read-only import** 만 하며 1 byte 도 수정하지
    않는다. utils/completion_callback_operational_cancel_seam (+23 산출),
    utils/live_cron_state_verifier (+23 산출), +9a 분리모듈도 무수정.
  * 결선 call-site = ``run_operational_completion_callback_collector``.
    이 wrapper 는 frozen collector ``run_completion_callback_collector``
    를 호출하여 그것이 반환한 **공개 ``CollectorResult``** 를 관찰한다.
    collector 가 ``closeout_candidate = (classification == PASS)`` 로
    durable-success 를 *판정한 그 결과* 를 frozen anchor **밖에서**
    읽으므로, frozen/forbidden collector 본체 편집·import 결합 0 으로
    durable-success 인접 결선이 성립한다 (9-R.2 hard-gate 통과 — frozen
    edit 유일경로 아님, HOLD 불요).
  * durable-success(PASS) 일 때만 +23 ``run_operational_cancel_seam``
    을 ``operational=True`` 로 **정확히 1회** invoke 한다. 그 외 분류
    (DUPLICATE_CALLBACK_IGNORED 포함) → seam 미진입 (무회귀).

exact-once (9-R.3 — seam-entry-time canonical token + atomic claim):
  * event identity 는 collector 가 durable-success 를 판정하는 그 시점에
    이미 손에 든 입력에서만 도출한다 — ``result.json`` 재독 의존 0.
    ``event_id = sha256(task_id + fallback_cron_id + dispatch-fired marker
    경로 + durable-success 판정 입력 해시)`` 로, seam 호출 시도 이전
    (pre-seam) 에 항상 존재·안정하다.
  * seam invoke **직전** ``event_id`` 기반 claim marker 를
    ``O_CREAT|O_EXCL|O_WRONLY`` 로 원자 선점한다. 선점 성공 시에만 seam
    1회 진입, 이미 존재(retries / duplicate callback / 복수 success
    branch / 동시 2호출)면 **즉시 no-op** (seam 미진입). claim marker 는
    ``task-2553+25.*`` 네임스페이스 (git-untracked batch-internal).

디커플 (§3 / §7 — collector success 와 seam 결과 완전 분리):
  * seam (혹은 wrapper 자체) 의 어떤 예외·skip·remove 실패도 frozen
    collector 가 반환한 ``CollectorResult`` 를 변경하지 않는다. wrapper
    는 collector 결과를 **그대로** 돌려준다. cron-remove 실패가 normal
    collector 성공을 실패로 바꾸지 않는다.

본 task 범위 (§6 / 9-R.4 — 실 운영 cron 비접촉):
  * 본 모듈의 구현·테스트·evidence 는 mock/fixture/격리 only. 실 운영
    cron 실제 삭제 0. 실 firing 은 결선완료·verifier PASS 후 운영단계
    동작이며 본 task 행위가 아니다.
    )annotationsN)	dataclassfield)Path)CallableOptionalUnion)CallbackInputClassificationCollectorResultPostResultReview no_real_codex_post_result_review!run_completion_callback_collector)OperationalCancelOutcomerun_operational_cancel_seamztask-2553+25.cancel-audit_v1ztask-2553+25c                      e Zd ZU dZded<   ded<   ded<   ded<   ded<   d	Zd
ed<   d	Zded<   d	Zded<   d	Zd
ed<   d	Z	d
ed<   d	Z
ded<   y	)OperationalSeamParamsu  +23 ``run_operational_cancel_seam`` 호출에 필요한 운영 입력.

    운영 caller 가 결선 시점에 바인딩한다. 모든 경로는 격리/fixture 로
    주입 가능하며, ``cron_lister``/``remover`` 미주입 시 +23 seam 의
    운영 기본 DI (실 cokacdir) 가 쓰이나 — 본 task 구현/테스트는 항상
    fake/격리 주입으로만 검증한다 (§6 9-R.4).
    strtarget_cron_idr   dispatch_fired_marker_pathresult_json_pathreport_pathcollector_result_marker_pathNzOptional[Path]
audit_pathzOptional[Callable[[], dict]]cron_listerzOptional[Callable[..., object]]removerfallback_cancelled_marker_pathcancel_lock_pathzOptional[dict]callback_contract)__name__
__module____qualname____doc____annotations__r   r   r   r   r   r        9/home/jay/workspace/utils/operational_collector_wiring.pyr   r   S   sh      $$"&&!%J%04K-4/3G,359"N9'+n+(,~,r&   r   c                      e Zd ZU dZded<   ded<   ded<   ded<   ded	<   d
Zded<   d
Zded<   d
Zded<    ee	      Z
ded<    ee      Zded<   y
)OperationalWiringResultu   wrapper 1회 실행 결과.

    ``collector_result`` 는 frozen collector 가 반환한 값 **그대로**
    (디커플 — seam 결과로 변경 0). ``seam_invoked`` 가 True 일 때만
    ``seam_outcome`` 존재.
    r   collector_resultbooldurable_successseam_invokedr   seam_skipped_reasonevent_idNzOptional[str]claim_marker_path"Optional[OperationalCancelOutcome]seam_outcomecancel_audit_path)default_factorydictcancel_auditlistnotes)r    r!   r"   r#   r$   r0   r2   r3   r   r5   r6   r7   r8   r%   r&   r'   r)   r)   j   se     &%M'+}+7;L4;'+}+t4L$4-E4-r&   r)   c           
        | j                   }| j                  j                  |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      d}t	        j
                  |d	d
      }t        j                  |j                  d            j                         S )u  durable-success 판정 입력 해시 (9-R.3).

    collector 가 PASS 를 산출하는 데 쓰인 *결정 입력* 만 canonical JSON
    으로 직렬화해 sha256. ``result.json`` 재독 0 — frozen collector 가
    in-memory ``CallbackInput`` 에서 만들어 반환한 ``delegation_result``
    의 결정 필드만 사용한다 (변동 ts_utc 등 비결정 필드 제외).
    callback_typecallback_cron_iddispatch_cron_idrequired_closeout_markersforbidden_action_postcheckpreservation_anchors
dev_sunset)classificationr:   r;   r<   r=   r>   r?   r@   TF)	sort_keysensure_asciiutf-8)
delegation_resultrA   valuegetjsondumpshashlibsha256encode	hexdigest)resultdrdecisivecanons       r'   _durable_success_input_hashrR      s     
	!	!B
 !//550FF#56FF#56%'VV,G%H&(ff-I&J "'= >ff\*	H JJx4eDE>>%,,w/0::<<r&   c                    dj                  | |t        |      t        |      f      }t        j                  |j                  d            j                         S )u   seam-entry-time canonical token (9-R.3).

    pre-seam 항상 존재·안정. 입력은 전부 durable-success 판정 시점에
    손에 든 값 (result.json 재독 0).
    rD   )joinr   rR   rJ   rK   rL   rM   )task_idfallback_cron_idr   rN   tups        r'   compute_event_idrY      sQ     ++*+'/		
C >>#**W-.88::r&   c                N   | j                   j                  dd       	 t        j                  t	        |       t        j
                  t        j                  z  t        j                  z  d      }t        j                  |dd      5 }t        j                  ||dd	
       |j                          t        j                   |j#                                ddd       y# t        $ r Y yt        $ r(}|j                  t        j                  k(  rY d}~y d}~ww xY w# 1 sw Y   yxY w)u   ``O_CREAT|O_EXCL|O_WRONLY`` 원자 선점.

    True  = 선점 성공 (본 호출만 seam 1회 진입 허용).
    False = 이미 존재 (retries/duplicate/concurrent) → 즉시 no-op.
    Tparentsexist_oki  FNwrD   encoding   rC   indent)parentmkdirosopenr   O_CREATO_EXCLO_WRONLYFileExistsErrorOSErrorerrnoEEXISTfdopenrH   dumpflushfsyncfileno)
claim_pathpayloadfdexcfs        r'   _atomic_claimry      s     D48	WW
ORZZ"))3bkkA5
 
2sW	- 		'15;		
    99$ s1   AC AD	D(D0DDDD$c                &   |t         | |dddddddddd|dddS |j                  xs i }|j                  d      xs i }|j                  d	      |j                  d
      |j                  d      |j                  d      |j                  d      d}|j                  }|dv }	|j                  r|j
                  rdnd}
nd}
i dt         d| d|j                  d|d|d|j                  d|j                  d|j                        d|dt        |j                        d|
dt        |j
                        dt        |j                        d|j                  d|	d t        |j                        d!|j                  d"|j                  S )#u   task-2553+25.cancel-audit_v1 레코드 (9-R.4 필수 필드 전수).

    필수: lookup_status / five_condition_results / remove_attempted /
    remove_result / skip_reason / already_removed_or_missing /
    normal_success_unchanged / event_id.
    NFNOT_INVOKED)c1_task_id_matchc2_chat_id_ownedc3_role_fallbackc4_marker_id_crosscheck c5_pending_not_fired_not_removedNOT_ATTEMPTEDT)schemar/   r   r-   lookup_statusfive_condition_resultsremove_attemptedremove_resultskip_reasonalready_removed_or_missingnormal_success_unchangedchecksr|   r}   r~   r   r   )SKIP_LIVE_SKIP_ALREADY_REMOVEDSKIP_LIVE_SKIP_ALREADY_FIREDSKIP_LIVE_SKIP_NOT_FOUND	CANCELLEDREMOVE_NONFATALr   r/   r   r-   seam_classificationstager   rA   r   r   r   fallback_cancelledremove_allowed_by_live_verifierr   r   r   plus9a_decisionts_utc)SCHEMA_CANCEL_AUDITlive_verificationrG   r   cron_remove_invokedr   r   r   r+   r   r   normal_success_preservedr   r   )r/   r   r-   r.   outcomelvr   fivescalreadyr   s              r'   build_cancel_auditr      s#    ) ,!*$($($(+/48' !&,.*/(,#
 	
& 
	"	"	(bBVVH#F"JJ'9:"JJ'9:"JJ'9:#)::.G#H,2JJ.-
D 
	$	$B  G
 """55K;L 	 (%H 	'00 		
 	r 	 	 0'--@ 	!$ 	D!<!<= 	 	d7#=#=> 	*433,
 	w**  	%g!$ 	#D)I)I$J%& 	722'( 	'..) r&   )post_result_review_fnduplicate_callback_seenevidence_pathspost_result_review_marker_pathr3   c                  t        | |||||      }	|	j                  t        j                  k(  xr |	j                  du xr |	j
                  du }
t        | j                  |j                  |j                  |	      }|
s*t        |	ddd|	j                  j                   d|dg      S t        |      t         d	| d
z  }t        |d|| j                  |j                  dd      }|st        |	ddd|t        |      dg      S d}d}d}	 t!        | j                  |j                  |j                  |j"                  |j$                  |j&                  |j(                  |j*                  |j,                  |j.                  |j0                  |j2                  d      }d}t7        ||j                  |||      }d}|t        |      nt        |      t         dz  }	 |j8                  j;                  dd       |j=                  t?        j@                  |dd      d       t        |      }t        |	d|||t        |      |||ddg
      S # t4        $ r}d| }Y d}~d}~ww xY w# tB        $ r d}Y Hw xY w)u  운영 collector 결선 진입점 — durable-success 직후 seam 1회 결선.

    절차:
      1. frozen ``run_completion_callback_collector`` 호출 (read-only;
         frozen byte-0). 반환 ``CollectorResult`` 만 관찰.
      2. ``classification == PASS`` → durable-success. 그 외 → seam 미진입
         (DUPLICATE_CALLBACK_IGNORED 등 무회귀).
      3. 9-R.3: pre-seam event_id 도출 (result.json 재독 0) → O_EXCL
         atomic claim. 선점 성공 시에만 4 진입, 실패 시 즉시 no-op.
      4. ``run_operational_cancel_seam(operational=True)`` **1회** invoke.
      5. cancel-audit JSON 기록. seam 예외/skip/remove 실패는 collector
         결과로 전파 0 — collector_result 는 1 의 반환을 **그대로** 유지.
    )r   r   r   r   T)rV   rW   r   rN   Fu'   durable-success 아님 (classification=u0   ) → seam 미진입, fallback 보존, 무회귀uk   비-PASS (DUPLICATE_CALLBACK_IGNORED 포함) → operational cancel seam 진입 0 (기존 경로 무회귀))r*   r,   r-   r.   r/   r8   z.seam-claim.z.jsonztask-2553+25.seam-claim_v1zO_CREAT|O_EXCL)r   r/   rV   r   atomic_create_methoduc   event_id claim 이미 선점됨 (retries/duplicate/concurrent) → exact-once no-op, seam 미진입u6   exact-once: atomic claim loser → seam 중복호출 0)r*   r,   r-   r.   r/   r0   r8   N )rV   r   r   r   r   r   r   r   r   r   r   r   operationaluT   seam invoke 예외 → fallback 보존, normal collector 성공 불변 (디커플): )r/   r   r-   r.   r   z.cancel-audit.jsonr[   ra   rb   rD   r_   u   결선 위치: frozen collector 공개 CollectorResult 관찰 후 durable-success(PASS) 직후 +23 run_operational_cancel_seam(operational=True) 1회 invoke (frozen byte-0, additive)u]   디커플: seam 결과와 무관하게 collector_result 불변, normal_success_unchanged=True)
r*   r,   r-   r.   r/   r0   r2   r3   r6   r8   )"r   rA   r   PASScloseout_candidateack_acquiredrY   rV   r   r   r)   rF   r   TASK_MARKER_PREFIXry   r   r   r   r   r   r   r   r   r   r   r   	Exceptionr   rd   re   
write_textrH   rI   rl   )inpack_pathseam_params	claim_dirr   r   r   r   r3   r*   r,   r/   rt   claimedr2   r-   r.   rw   auditaudit_writtenaudit_targets                        r'   -run_operational_completion_callback_collectorr     s
   8 93 7%'E 	''>+>+>> 	2//47	2))T1   $33#.#I#I	H &-!9#22889 :-- A
 	
$ 	Y XJe
<	=  2 {{)88$4	
	G &- 7 !*oKL
 	
 8<LL
2KK&55'2'M'M(99#//88"--#//''::(99);;#
&  "11!/E $(M ( 	)_"4!55GHH 
!!$!>JJu5;g 	  	
 L) #)!/j/!'G,	
 ;  
5" 	
4  s,   BI AI( 	I%I  I%(I65I6)r   r   r   r)   rY   r   r   )rN   r   returnr   )
rV   r   rW   r   r   Union[str, Path]rN   r   r   r   )rt   r   ru   r5   r   r+   )r/   r   r   r   r-   r+   r.   r   r   r1   r   r5   )r   r
   r   r   r   r   r   r   r   z2Callable[[dict, Classification], PostResultReview]r   Optional[list]r   r   r   Optional[Union[str, Path]]r3   r   r   r)   )$r#   
__future__r   rm   rJ   rH   rf   dataclassesr   r   pathlibr   typingr   r   r	   (utils.anu_delegation_completion_callbackr
   r   r   r   r   r   1utils.completion_callback_operational_cancel_seamr   r   r   r   r   r)   rR   rY   ry   r   r   __all__r%   r&   r'   <module>r      s  1d #    	 (  , , 
 5  $  - - -, . . .(=4;; ; !1	;
 ; 	;.0NN N 	N
 N 0N 
Nr 	).2%)AE48i	ii '	i
  ii ,i #i %?i 2i iXr&   