
    3j4                       d Z ddlmZ ddlmZ ddlmZmZmZm	Z	 dZ
dZdZdZd	Ze G d
 d             Z	 	 	 	 ddZe G d d             ZddZddZe G d d             Z	 	 	 	 ddZddZe G d d             Z	 	 	 	 	 	 ddZy)uN  anu_v3.batch_join_policy — join-time policy: contamination, authority
packet selection, callback classification, batch next-action.

Authority: task-2553+17.md §4(6,7,8,10) + §12 9-R.6.

All rules are deterministic with explicit tie-breakers (9-R.6):
  * final_authority_packet_selector: per task authority =
        result.json (schema anu_*_result / *final_packet) preferred;
        on multiple packets for the same task -> normal collector > fallback,
        then latest ts.
  * duplicate / pending fallback classifier:
        normal collector completed first, later fallback ->
            DUPLICATE_CALLBACK_IGNORED
        fallback only, no normal -> CALLBACK_PENDING (non-blocking iff that
            track's authority packet already settled via the normal path OR
            the batch final decision does not depend on that track)
        4-tuple cron_id mismatch -> TRACK_MISMATCH
        cross-track artifact citation -> batch-level CONTAMINATION_HOLD
  * cross_track_contamination_checker: a track artifact citing another
        track's artifact -> batch-level CONTAMINATION_HOLD.
    )annotations)	dataclass)DictListSequenceTupleDUPLICATE_CALLBACK_IGNOREDCALLBACK_PENDINGTRACK_MISMATCHCONTAMINATION_HOLDNORMAL_COLLECTOR_ACCEPTEDc                  j    e Zd ZU ded<   ded<   ded<   ded<   ded<   ded<   dZded	<   d
ddZddZy)PacketCandidatestrtask_idtrack_idsourceschematspath status   r   )normalfallbackc                f    | j                   j                  | j                  d      | j                  fS )N)_SOURCE_RANKgetr   r   )selfs    :/home/jay/workspace/scripts/../anu_v3/batch_join_policy.pyrank_keyzPacketCandidate.rank_key/   s(    !!%%dkk26@@    N)returnzTuple[int, str])__name__
__module____qualname____annotations__r   r   r"    r#   r!   r   r   #   s:    LMKKG
IFCQ/LAr#   r   c                    i }| D ]-  }|j                  |j                  g       j                  |       / i }|j                         D ]  \  }}t	        |d d      d   ||<    |S )zPer task_id pick the single authoritative packet (9-R.6).

    Tie-breakers, in order: source (normal > fallback), then latest ts.
    c                "    | j                         S N)r"   )cs    r!   <lambda>z1final_authority_packet_selector.<locals>.<lambda>A   s     r#   T)keyreverser   )
setdefaultr   appenditemssorted)
candidatesby_taskr-   chosenr   groups         r!   final_authority_packet_selectorr9   4   sz     13G 4199b)0034)+F!--/  -t

w Mr#   c                      e Zd ZU 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<   y)CallbackEventr   r   r   kindboolidentity_oknormal_already_completedFauthority_settled_via_normalTbatch_final_depends_on_trackr   observed_dispatch_cron_id!observed_normal_collector_cron_id"observed_fallback_callback_cron_idN)	r%   r&   r'   r(   r@   rA   rB   rC   rD   r)   r#   r!   r;   r;   F   sV    ML
I""). $.)- $- &(s'-/%s/.0&0r#   r;   c                    | j                   st        S | j                  dk(  rt        S | j                  dk(  r| j                  rt
        S t        S t        d| j                        )z.Deterministic callback classification (9-R.6).r   r   zunknown callback kind )r>   r   r<   r   r?   r	   r
   
ValueErrorevs    r!   classify_callbackrI   W   sY    >>	ww(((	ww*&&--
-bgg[9
::r#   c                Z    t        |       t        k7  ry| j                  ry| j                  S )zA CALLBACK_PENDING fallback blocks the chair decision only if the
    track's authority is NOT already settled via normal AND the batch final
    decision depends on that track (9-R.6).F)rI   r
   r@   rA   rG   s    r!   pending_blocks_chair_decisionrK   d   s-      00	&&***r#   c                  ,    e Zd ZU ded<   ded<   ded<   y)TrackArtifactsr   r   z	List[str]own_artifactscited_artifactsNr%   r&   r'   r(   r)   r#   r!   rM   rM   o   s    Mr#   rM   c                   i }| D ]"  }|j                   D ]  }|j                  ||<    $ g }| D ]U  }|j                  D ]D  }|j                  |      }|||j                  k7  s'|j	                  |j                  ||f       F W |S )zReturn (citing_track, owner_track, artifact) for every cross-track
    citation. Non-empty result -> batch-level CONTAMINATION_HOLD.)rN   r   rO   r   r2   )tracksownertaoutcitedos          r!   cross_track_contaminationrY   v   s    
 E " 	"AzzE!H	"" ')C 3&& 	3E		% A}ajj

AJJ512	33
 Jr#   c                *    t        t        |             S r,   )r=   rY   )rR   s    r!   batch_contaminatedr[      s    )&122r#   c                  @    e Zd ZU ded<   ded<   ded<   ded<   ded<   y)	TrackJoinViewr   r   stater=   terminalcallback_classblocks_chairNrP   r)   r#   r!   r]   r]      s    MJNr#   r]   c           
     0   |rd}nAt        d | D              rd}n,t        d | D              rd}nt        d | D              rd}nd}|| D cg c]<  }|j                  |j                  |j                  |j                  |j
                  d	> c}|d
S c c}w )aZ  Resolve a single batch-level next action.

    Precedence:
      1. contamination          -> BATCH_HOLD_CONTAMINATION
      2. any HOLD_FOR_CHAIR     -> CHAIR_DECISION_REQUIRED
      3. any blocking pending   -> AWAIT_PENDING_CALLBACK
      4. any non-terminal       -> CONTINUE_LOOP
      5. all terminal & clean   -> CONSOLIDATE_FOR_CHAIR
    BATCH_HOLD_CONTAMINATIONc              3  :   K   | ]  }|j                   d k(    yw)HOLD_FOR_CHAIRN)r^   .0vs     r!   	<genexpr>z$batch_next_action.<locals>.<genexpr>   s     >QQWW((>s   CHAIR_DECISION_REQUIREDc              3  4   K   | ]  }|j                     y wr,   )ra   rf   s     r!   ri   z$batch_next_action.<locals>.<genexpr>   s     1Q^^1s   AWAIT_PENDING_CALLBACKc              3  6   K   | ]  }|j                      y wr,   )r_   rf   s     r!   ri   z$batch_next_action.<locals>.<genexpr>   s     1^1s   CONTINUE_LOOPCONSOLIDATE_FOR_CHAIR)r   r^   r_   r`   ra   )batch_next_actionrR   contaminated)anyr   r^   r_   r`   ra   )track_viewsrq   actionrh   s       r!   rp   rp      s     +	>+>	>*	1[1	1)	1[1	1 (# !	
  JJJJ"#"2"2 !	
 % 	
s   ABN)r5   zSequence[PacketCandidate]r$   zDict[str, PacketCandidate])rH   r;   r$   r   )rH   r;   r$   r=   )rR   Sequence[TrackArtifacts]r$   zList[Tuple[str, str, str]])rR   ru   r$   r=   )rs   zSequence[TrackJoinView]rq   r=   r$   zDict[str, object])__doc__
__future__r   dataclassesr   typingr   r   r   r   r	   r
   r   r   r   r   r9   r;   rI   rK   rM   rY   r[   r]   rp   r)   r#   r!   <module>rz      s   , # ! . .9 % !) 7  A A A )$ 1 1 1 
;+   $$3   $($$ $r#   