
    +s#jI/                    @   d Z ddlmZ ddlmZmZ ddlmZmZm	Z	m
Z
mZ ddlmZmZmZ ddlmZmZmZmZ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  dZ!e G d	 d
             Z"ddZ#ddZ$efdddddddded		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ%	 d	 	 	 	 	 	 	 ddZ&y)u"  dispatch.finalize_hooks — executor completion lifecycle 결선.

task-2635 — normal callback registration enforcement (Core hardening).
task-2635+1 — build-then-register-then-update 순서 + 5축 propagation.

Spec: memory/specs/system_normal_callback_registration_implementation_spec_260523.md
sha256: 0fbd1dad1e110c49474dfbdf13a21fb3bdd9c7f094128004dba8472840bb832d

회장 verbatim (task-2635 §3.3):
    dispatch/finalize_hooks.py — executor 완료 lifecycle 결선
      * finalize_with_callback_registration(task_id, result, anu_key)
          -> finalize_result
      * 호출 순서: envelope build → registrar 호출 → registration_status 회수
        → result.json 갱신 → fail-closed 분기
      * sendfile 은 별도 함수 send_envelope_to_chat(envelope, chat_id) —
        callback 대체 아님 (보조)

회장 verbatim (task-2635+1 §4):
    register 성공 후 envelope payload 갱신 — registration_result_status =
    REGISTERED · cron_schedule_id = 실제 id · registered_at_ts = 실제 시각 ·
    attempted_callback_registration = True · delivery_method = anu_cron_callback.

ANCHOR-1 (task-2635+1): envelope payload 최종 5축 상태 정확 반영 —
build-then-register-then-update 순서.
ANCHOR-3: sendfile/report ≠ callback — 함수/스키마 분리.
    )annotations)	dataclassfield)AnyCallableDictListOptional)FallbackDecisiondecide_fallback_cancelexpected_collector_spawn)INDEPENDENT_ANU_KEYRegistrarResultbuild_callback_envelope$merge_registrar_result_into_enveloperegister_normal_callback)
CANONICAL_ROOT_DEFAULTCallbackDeliveryStatusCollectorReceiptStatus NormalCallbackRegistrationStatusRegistrationResultStatusdetect_status_contradictionsis_callback_completeis_fail_closed_statusis_success_statusvalidate_envelopezdispatch.finalize_hooks.v2c                      e Zd ZU dZded<   ded<   ded<   ded<    ee	      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<   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)FinalizeResultu   Lifecycle outcome returned to the executor.

    ``finalize_result`` ∈ {"success", "fail"}. The executor MUST translate
    "fail" to a non-zero exit code (fail-closed contract, spec §2).
    strfinalize_resultregistration_statusr   fallback_decisionDict[str, Any]envelope)default_factory	List[str]registrar_argvFboolr   is_collector_spawn_expectederrorsnotesTregistration_intentregistration_attempted registration_result_statuscallback_delivery_statuscollector_receipt_statusN)__name__
__module____qualname____doc____annotations__r   listr'   r   r)   r*   r+   r,   r-   r/   r0   r1        J/home/jay/workspace/.worktrees/task-2729+8-dev1/dispatch/finalize_hooks.pyr   r   =   s     '' %d ;NI;!&$&(--d3FI3T2E92 $$#(D(&(($&c&$&c&r9   r   c                "    t        |       \  }}|S )u   Return validation errors (empty on PASS). Validator allows the seed
    NOT_REGISTERED status with no cron_schedule_id — that's intentional for
    fail-closed paths (envelope-only / sendfile_only callers).)r   )r$   _errss      r:   _validate_or_collect_errorsr>   V   s      )GAtKr9   c           	     ^   t        | j                  dd            t        | j                  dd            | j                  d| j                  dd            xs d| j                  dt        j                  j                        | j                  d	t
        j                  j                        d
S )z5Read the 5 axes off an envelope, with safe fallbacks.r,   Tr-   Fr/   r!   r.   r0   r1   )r,   r-   r/   r0   r1   )r(   getr   NOT_APPLICABLEvaluer   )r$   s    r:   _five_axis_snapshotrC   ^   s      $HLL1F$MN"&x||4Le'T"U&.ll((,,7Lb*Q'
 ' $,LL&(>(M(M(S(S%
 %-LL&(>(M(M(S(S%
 r9   
   NF)	delay_secondssubprocess_runnerskip_registrationskip_reasondelivery_method_overrideseed_envelope_overridescli_exists_checkat_valuecanonical_rootc       	        T   |r|s| |dddt         j                  j                  t         j                  j                  t        j                  j                  t
        j                  j                  d|xs dd}|r||d<   t        dt         j                  j                  t        dddt         j                  j                  	      |d
gddt         j                  j                  t        j                  j                  t
        j                  j                  
      S t        | ||d|xs dt         j                  j                  |dd	      }|r||d<   |r|j                  |       t        |      }t        |      }|d   }t        |      }t        dt        |      r|sdnd|||t        |      t!        |      |dgd|S t        | |||xs dddd      }|r||d<   |r|j                  |       t#        |||||	|
      }t%        ||      }t        |      }t'        |      }t        |      }|d   }t)        |      rd}n	|s|rd}nd}t        |      }t        d|||||j*                  t        |      t!        |      ||z   d|j,                   d|j.                  xs d gd	|S )u  task-2635+1 §4 — build-then-register-then-update pipeline.

    1. Build seed envelope (5 axes pre-populated for NOT_REGISTERED + PENDING).
    2. If skip_registration → SKIPPED_WITH_EXPLICIT_REASON pathway.
    3. Else → call registrar → merge result back into envelope (axes 3/4/5
       transition together).
    4. Run contradiction scan + envelope validator → fail-closed gating.
    5. Return FinalizeResult with full 5-axis snapshot.
    ANUTFnone)task_idanu_keycollector_roler,   r-   r/   r!   r0   r1   attempted_callback_registrationdelivery_methodrM   failz/skip_registration requested without skip_reason)cancel_fallbackreasondurable_success_marker_presentstatusz7skip_registration=True requires a non-empty skip_reason)
r    r!   r"   r$   r*   r,   r-   r/   r0   r1   )	rQ   resultrR   rT   rU   r!   explicit_skip_reasonr,   r-   r/   successz)skipped registration with explicit reason)r    r!   r"   r$   r   r)   r*   r+   anu_cron_callback)rQ   r[   rR   rU   rT   r,   r-   )r$   rE   rR   rF   rK   rL   zregistrar_byte_count=zregistrar_error=)	r    r!   r"   r$   r'   r   r)   r*   r+   r8   )r   NOT_REGISTEREDrB   r   rA   r   r   r   r   SKIPPED_WITH_EXPLICIT_REASONupdater>   r   rC   r   r   r   r   r   r   r   argv
byte_counterror)rQ   r[   rR   rE   rF   rG   rH   rI   rJ   rK   rL   rM   minimal_enveloper$   r*   decisionrZ   snapseed_enveloperegistrar_resultfinal_envelopecontradictionsoutcomes                          r:   #finalize_with_callback_registrationrm   p   s   0  #""''+*/.F.U.U.[.['?'N'N'T'T,B,Q,Q,W,W,B,Q,Q,W,W38#;#Ev  5C !12! &$<$K$K$Q$Q"2$)L383BBHH	# *QR$(',+C+R+R+X+X)?)N)N)T)T)?)N)N)T)T " +,14> 8 U U [ [!, $#(

 )7H%&"OO34,X6)(367"8, 

):6)B6IW] &&!5h!?(@(J>?

 

 
	
 ,0G4G(, #M *8&'45(@#+)) :-IYZN(8F1.AN%n5H89FV$	>~.D ""',,1.A$<^$L&#$4$?$?#@A/55?@A
  r9   c                F    dd}||n|} || |      }t         dz   ||dddS )a  Sendfile-only auxiliary delivery (ANCHOR-3 separation).

    THIS IS NOT A SUBSTITUTE FOR ``register_normal_callback``. It exists so
    operators have a structured place to call envelope sendfile, but it does
    NOT register a cron, does NOT spawn a collector, and does NOT mark
    ``registration_result_status`` as REGISTERED. The function returns an audit
    record only; the registrar remains the single source of truth for
    callback registration.
    c                2    dt        t        |             |dS )Nnoop)rZ   envelope_byteschat_id)lenr   )envcids     r:   _noop_sendfilez-send_envelope_to_chat.<locals>._noop_sendfile  s     CCMcRRr9   z	.sendfileFznsendfile is auxiliary (ANCHOR-3). register_normal_callback is the only path that produces a REGISTERED status.)schemadelivered_torl   is_callback_substitutenote)rt   r#   ru   r   returnr#   )FINALIZE_HOOK_SCHEMA)r$   rr   sendfile_runnerrv   runnerrl   s         r:   send_envelope_to_chatr     sC    S !0 ;_FXw'G&4"'B	 	r9   )r$   r#   r{   r&   )r$   r#   r{   r#   )rQ   r   r[   r#   rR   r   rE   intrF   z)Optional[Callable[[List[str], int], Any]]rG   r(   rH   Optional[str]rI   r   rJ   zOptional[Dict[str, Any]]rK   zOptional[Callable[[str], bool]]rL   r   rM   r   r{   r   )N)r$   r#   rr   r   r}   z.Optional[Callable[[Dict[str, Any], str], Any]]r{   r#   )'r5   
__future__r   dataclassesr   r   typingr   r   r   r	   r
   utils.anu_callback_fallbackr   r   r   utils.anu_callback_registrarr   r   r   r   r   utils.callback_envelope_schemar   r   r   r   r   r   r   r   r   r   r|   r   r>   rC   rm   r   r8   r9   r:   <module>r      sR  4 # ( 6 6 
    4  ' ' '0* 'P
 CG#!%.28<8<"$:PPP P
 P AP P P ,P 6P 6P P "P Pl GK D 	r9   