
    j                        d Z ddlmZ ddlmZmZmZmZ ddlm	Z	m
Z
mZ dZdZdZdZd	Zd
ZdZddZddZ	 d	 	 	 	 	 ddZy)u  utils.anu_collector_action_trigger — collector action vs sendfile-only split.

task-2636 — callback collector canonical-root resolver (Core hardening).

Spec: memory/specs/system_callback_collector_canonical_root_spec_260523.md
sha256: 6f0b04810cc458ea4cb12f3c1c9c511d14b1439917b7ef4f1ef91982e32d92c1

회장 verbatim (task md §2 항목 9, 10):
    9. callback envelope 는 단순 로그가 아니라 ANU collector action trigger
       임을 명확히 검증
    10. sendfile-only 와 normal callback envelope 구분 유지
        (collector trigger 시점에 sendfile envelope 무시)

ANCHOR-5 (spec §14): sendfile-only ≠ normal callback trigger 분리
(is_callback_action_trigger 단언).

fail-closed: NOT_REGISTERED / REGISTER_FAILED 는 trigger=False (5축 정합).
    )annotations)AnyDictListOptional)DeliveryMethodRegistrationResultStatusnormalize_statusz%utils.anu_collector_action_trigger.v1normal_callback_registeredsendfile_only_delivery)registration_result_status_not_registered*registration_result_status_register_failed"registration_result_status_skippedenvelope_invalid_or_missingc                   t        | t              syt        | j                  d| j                  d                  }|t        j
                  j                  k7  ry| j                  d      }|t        j                  j                  k7  ryy)u  Decide whether ``envelope`` should fire a collector action (spec §5.2).

    True iff ALL of:
      * envelope is a dict
      * registration_result_status (or legacy alias) == REGISTERED
      * delivery_method == anu_cron_callback

    False (fail-closed) otherwise — including sendfile_only, NOT_REGISTERED,
    REGISTER_FAILED, SKIPPED_WITH_EXPLICIT_REASON, and any envelope that is
    not a dict.
    Fregistration_result_statusregistration_statusdelivery_methodT)	
isinstancedictr
   getr	   
REGISTEREDvaluer   ANU_CRON_CALLBACKenvelopestatusr   s      9/home/jay/workspace/utils/anu_collector_action_trigger.pyis_callback_action_triggerr   *   sz     h%(LL./	
F )44:::ll#45O.::@@@    c                   t        | t              st        S t        | j	                  d| j	                  d                  }| j	                  d      }|t
        j                  j                  k(  s|t        j                  j                  k(  rt        S |t        j                  j                  k(  r#|t
        j                  j                  k(  rt        S |t        j                  j                  k(  rt        S |t        j                  j                  k(  rt         S |t        j"                  j                  k(  rt$        S t        S )zGSingle-string explanation of the trigger decision (for action records).r   r   r   )r   r   REASON_INVALID_ENVELOPEr
   r   r   SENDFILE_ONLYr   r	   REASON_SENDFILE_ONLYr   r   REASON_NORMAL_CALLBACKNOT_REGISTEREDREASON_NOT_REGISTEREDREGISTER_FAILEDREASON_REGISTER_FAILEDSKIPPED_WITH_EXPLICIT_REASONREASON_SKIPPEDr   s      r   _classify_reasonr,   F   s   h%&&(LL./	
F ll#45O.66<<< ..44A $#)44:::((..@ &%)88>>>$$)99???%%)FFLLL""r    Nc                   t        |       }t        |       }t        ||t        | t              r| j                  d      ndt        | t              r| j                  d      ndt        | t              r*t        | j                  d| j                  d                  ndt        | t              r| j                  d      nddd}|r||j                  |       d	|d
<   |S )u%  Append a collector action record IFF the envelope is a real trigger.

    Returns the action record (always — even when skipped — so callers can
    audit the decision). When trigger=False, the record is NOT pushed onto
    ``queue`` (sendfile-only must never produce collector work).
    task_idNr   r   r   callback_delivery_statusF)schema
is_triggerreasonr.   r   r   r/   enqueuedTr3   )r   r,   TRIGGER_SCHEMAr   r   r   r
   append)r   queuetriggerr2   records        r   enqueue_collector_actionr9   b   s     )2Gh'F .84.H8<<	*d/9(D/IHLL*+t (D) 0LL!67  (D) LL34/F2 5$V!zMr    )r   r   returnbool)r   r   r:   str)N)r   r   r6   zOptional[List[Dict[str, Any]]]r:   zDict[str, Any])__doc__
__future__r   typingr   r   r   r   utils.callback_envelope_schemar   r	   r
   r4   r%   r$   r'   r)   r+   r"   r   r,   r9    r    r   <module>rB      sy   $ # , ,  9 6 / C E 57 8#< -1(()( (r    