
    3j4F                       U d Z ddlm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mZ ddl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 dd	lmZmZ dd
l m!Z!m"Z"m#Z# ddl$m%Z%m&Z& dddddddZ'de(d<    G d de)      Z*d dZ+e G d d             Z,e G d d             Z-e G d d             Z. G d d      Z/d!dZ0y)"u  anu_v3.parallel_batch_coordinator — top-level parallel batch coordinator.

Authority: task-2553+17.md §1 / §2 / §4 / §9 + §12 (9-R.1..9-R.7).

Single entry that, given a parallel batch plan:
  1. derives a deterministic batch_id
  2. registers per-track callback_track_record (5-field) into a registry
  3. builds the dependency matrix + runs overlap / contamination checkers
  4. drives a 13-state track loop machine per track
  5. selects per-task final authority packets (normal > fallback, ts)
  6. classifies duplicate / pending / mismatch callbacks
  7. resolves a single batch-level next action
  8. writes parallel-batch-state.json + a chair-only consolidated summary
  9. (Track3) folds goal-driven loop plans, splitting conflicting
     sub-features to follow-ups (no Track2 silent drop)

Pure stdlib. Persists ONLY new deliverable files; never mutates existing
tracked files (9-R.1).
    )annotationsN)	dataclassfield)Path)DictListOptionalSequence)BatchDependencyMatrix	TrackSpec)	CallbackEventPacketCandidateTrackArtifactsTrackJoinViewbatch_next_actionclassify_callbackcross_track_contaminationfinal_authority_packet_selectorpending_blocks_chair_decision)CallbackTrackRecordCallbackTrackRegistry)GoalRequestLoopPlangenerate_loop_plan)TrackLoopStateis_terminal            )TRACK_MISMATCHCONTAMINATION_HOLDCALLBACK_PENDINGDUPLICATE_CALLBACK_IGNOREDNORMAL_COLLECTOR_ACCEPTED zDict[str, int]_CLASS_SEVERITYc                      e Zd ZdZy)TrackedPathWriteRefusedz9-R.1/9-R.2: a write was attempted against an existing git-tracked
    path. Only NEW git-untracked deliverables may be written; tracked files
    are byte-0 immutable for this task.N)__name__
__module____qualname____doc__     8/home/jay/workspace/anu_v3/parallel_batch_coordinator.pyr*   r*   ?   s    +r0   r*   c                ^   	 t        j                  ddt        | j                        ddgdd      }|j                  dk7  ry|j
                  j                         }t        j                  dd|d	d
t        | j                               gdd      }|j                  dk(  S # t        $ r Y yw xY w)zTrue iff *p* is git-tracked (``git ls-files --error-unmatch`` succeeds
    in the repo that owns it). Outside any git repo -> False (untracked).gitz-Cz	rev-parsez--show-toplevelT)capture_outputtextr   Fzls-filesz--error-unmatch)	
subprocessrunstrparent
returncodestdoutstripresolve	Exception)ptopreporcs       r1   _is_git_trackedrC   E   s    nnD#ahh-6GH

 >>Qzz!^^D$
,=s199;?OP

 }}!! s   ?B  AB   	B,+B,c                      e Zd ZU ded<   ded<   ded<   ded<   ded<    ee      Zded	<    ee      Zded
<    ee      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<   y)	TrackPlanr8   track_idtask_iddispatch_cron_idnormal_collector_cron_idfallback_callback_cron_iddefault_factoryz	List[str]expected_filesforbidden_write_targets
depends_onown_artifactscited_artifactsPLANNEDinitial_stater   intretry_ceilingN)r+   r,   r-   __annotations__r   listrM   rN   rO   rP   rQ   rS   rU   r/   r0   r1   rE   rE   [   s~    ML!!"" %d ;NI;).t)DYD!$7J	7$T:M9:!&t!<OY<"M3"M3r0   rE   c                  >    e Zd ZU ded<   ded<    ee      Zded<   y)		BatchPlanr8   batch_labelzList[TrackPlan]tracksrK   zList[GoalRequest]goal_requestsN)r+   r,   r-   rV   r   rW   r\   r/   r0   r1   rY   rY   k   s    ',T'BM$Br0   rY   c                  ,    e Zd ZU ded<   ded<   ded<   y)CoordinatorResultr8   batch_idDict[str, object]state
summary_mdN)r+   r,   r-   rV   r/   r0   r1   r^   r^   r   s    MOr0   r^   c                      e Zd ZddZedd       ZddZddZ	 d	 	 	 ddZ	 	 	 	 ddZ		 	 	 	 ddZ
dd	Z	 	 d 	 	 	 	 	 d!d
Zd"dZd#dZdddddddZed$d       Zd%dZd%dZ	 	 	 	 	 	 d&dZy)'ParallelBatchCoordinatorc                   || _         | j                  |      | _        t               | _        i | _        i | _        i | _        i | _        |j                  D ]  }| j                  j                  t        |j                  |j                  |j                  |j                  |j                                t#        |j                  |j$                  |j&                        | j
                  |j                  <    t)        |j                  D cg c]D  }t+        |j                  |j,                  |j.                  |j0                  |j2                        F c}      | _        y c c}w )N)rF   rG   rH   rI   rJ   )rF   ra   rU   )rF   rM   rN   rO   rP   )plan_derive_batch_idr_   r   registry_track_states_loop_plans_callback_classes_callback_blocksr[   registerr   rF   rG   rH   rI   rJ   r   rS   rU   r   r   rM   rN   rO   rP   	depmatrix)selfrf   tps      r1   __init__z!ParallelBatchCoordinator.__init__z   s0   	--d3-/8:02
 2413++ 	BMM""#[[JJ%'%8%8-/-H-H.0.J.J /=&& ../Dr{{+	 / ++	  [[#%#4#4,.,F,F!}}"$"2"2	
	s   A	E!c                   | j                   dz   dj                  t        d | j                  D                    z   }t	        j
                  |j                  d            j                         d d }d| j                    d| S )N|c              3  R   K   | ]  }|j                    d |j                    ! yw):N)rF   rG   ).0ts     r1   	<genexpr>z<ParallelBatchCoordinator._derive_batch_id.<locals>.<genexpr>   s#     D1ajj\199+.Ds   %'utf-8   zbatch--)rZ   joinsortedr[   hashlibsha256encode	hexdigest)rf   basisdigests      r1   rg   z)ParallelBatchCoordinator._derive_batch_id   sw      3&DDD*
 
 W 56@@B3BG(()6(33r0   c                     | j                   |   S N)ri   )ro   rF   s     r1   track_statez$ParallelBatchCoordinator.track_state   s    !!(++r0   c                @    | j                   |   j                  |       y r   )ri   
transition)ro   rF   dsts      r1   advancez ParallelBatchCoordinator.advance   s    8$//4r0   Nc           	        |xs i }| j                   j                  D ]  }| j                   j                  D ]  }|j                  j	                  |j
                        s|j                  |j
                  k(  sB|j                  |j                        }t        ||j                  |j                  d            | j                  |j                  <     | j                  S )Nr/   )rf   r\   r[   rF   endswithgoal_idrG   
bind_trackr   getrj   )ro   	conflictsgrrp   bindings        r1   fold_goal_loopsz(ParallelBatchCoordinator.fold_goal_loops   s     O	)))) 	Bii&& ;;''

3rzzRZZ7O mmBKK8G4Fr{{B!?5D$$R[[1	 r0   c                    t        |      S r   )r   )ro   
candidatess     r1   select_authority_packetsz1ParallelBatchCoordinator.select_authority_packets   s     /z::r0   c                >   i }i | _         || _        |D ]  }|j                  |j                  |j                  |j
                  d}| j                  j                  |j                  |      \  }}|j                  xr ||_	        t        |      }|j                  |j                        }|t        |   t        |   kD  r|||j                  <   t        |      }	| j                   j                  |j                  d      xs |	| j                   |j                  <   	 |S )u  Classify observed callbacks (HIGH-1/HIGH-2/HIGH-3).

        HIGH-1: the 4-tuple is validated against the cron IDs *observed on
        the event* (``observed_*_cron_id``), never reconstructed from the
        registry — a real cron-ID drift now surfaces as TRACK_MISMATCH
        instead of a self-fulfilling pass.
        HIGH-2: the returned map is keyed by bare ``track_id`` (the exact
        key ``batch_next_action()`` looks up); multiple events on one track
        collapse to the most-severe class.
        HIGH-3: per-track chair-blocking is recorded via
        ``pending_blocks_chair_decision`` for ``batch_next_action()``.
        )rG   rH   rI   rJ   F)rl   rk   rG   observed_dispatch_cron_id!observed_normal_collector_cron_id"observed_fallback_callback_cron_idrh   validate_callbackrF   identity_okr   r   r(   r   )
ro   eventsoutevobserved_identityok_clsprevblockss
             r1   classify_callbacksz+ParallelBatchCoordinator.classify_callbacks   s    ! "!$ 	B::$&$@$@,.,P,P-/-R-R	! MM33.EB  ^^2BN#B'C772;;'D|s3od6KK#&BKK 226F%%))"++u=G !!"++.!	& 
r0   c           
         t        | j                  j                  D cg c].  }t        |j                  |j
                  |j                        0 c}      S c c}w )N)rF   rP   rQ   )r   rf   r[   r   rF   rP   rQ   )ro   rp   s     r1   contaminationz&ParallelBatchCoordinator.contamination   sV    ( ))**  [["$"2"2$&$6$6	
 		
s   3Ac           
        || j                   }|| j                  }t        | j                               }g }| j                  j
                  D ]  }| j                  |j                     }|j                  |j                  d      }|dk(  xr% t        |j                  |j                  d            }|j                  t        |j                  |j                  t        |j                        ||              t        ||      S )u  Resolve the single batch-level next action.

        HIGH-3: a ``CALLBACK_PENDING`` track blocks the chair decision only
        when ``pending_blocks_chair_decision`` said so (9-R.6 non-blocking
        rule) — recorded by the last ``classify_callbacks()`` pass or passed
        in explicitly. With no callbacks classified nothing blocks (the
        no-arg path is unchanged).
        r'   r$   F)rF   ra   terminalcallback_classblocks_chair)rk   rl   boolr   rf   r[   ri   rF   r   appendr   ra   r   r   )	ro   callback_classescallback_blockscontaminatedviewsrp   tscbr   s	            r1   r   z*ParallelBatchCoordinator.batch_next_action   s     ##55""33OD..01%'))"" 	B##BKK0B!%%bkk26B-- $##BKK73F LL[[(((2#%!'	 !55r0   c                :   | j                         }d| j                  | j                  j                  | j                  j                         | j                  j                         | j                  j                         D ci c]  \  }}||j                          c}}| j                  j                         D ci c]  \  }}||j                          c}}| j                         D cg c]  \  }}}|||d c}}}|d   d	S c c}}w c c}}w c c}}}w )Nzanu_v3.parallel_batch_state.v1)citingownerartifactr   )	schemar_   rZ   callback_track_registrydependency_matrixtrack_statesgoal_loop_plansr   r   )r   r_   rf   rZ   rh   to_dictrn   ri   itemsrj   r   )ro   bnatidstlpabcs           r1   build_statez$ParallelBatchCoordinator.build_state   s   $$&69900'+}}'<'<'>!%!7!7!9151C1C1I1I1K&-c2RZZ\! 261A1A1G1G1I &-c2RZZ\! 
 "&!3!3!5 Q1 qa8 "%%8!9!
 	
 s   D
<D.Dc           
        | j                         }g }|j                  d| j                          |j                  d       |j                  d       |j                  d       |j                  d| j                  j                   d       |j                  d|d    d       |j                  d	t        | j                  j                         d
t        | j                                |d   }|j                  d|sdn|        |j                  d       |j                  d       | j                  j                         D ]C  \  }}t        |j                        rdnd}|j                  d| d|j                   d| d       E | j                  r|j                  d       |j                  d       | j                  j                         D ]E  \  }}|j                  d| d|j                   d|j                  rd|j                   ndz          G |j                  d       dj                  |      dz   S )Nu*   # Parallel Batch Consolidated Summary — r'   us   > Chair-only: this summary compresses to the chair's final decision points only (task-2553+17.md §4(11) / §6⑧).z- batch_label: ``z- batch_next_action: **r   z**z
- tracks: z | goal_loop_plans: r   z- cross_track_contamination: NONEz ## Per-track chair decision viewTERMINALzin-loopz- `u   ` → **z** ()z## Track3 goal-loop fold-inu   ` → status **z, follow-up split: 
)r   r   r_   rf   rZ   lenr[   rj   ri   r   r   ra   statussplit_followupsr|   )ro   ra   linescontamr   r   r   r   s           r1   build_consolidated_summaryz3ParallelBatchCoordinator.build_consolidated_summary5  s)     "A$--QRRG	
 	R'		(=(='>a@A%e,?&@%AD	
 	TYY--./ 0  #D$4$4 568	
 '+#v02	
 	R78))//1 	GGC%0%:z	HLL3se8BHH:T(1EF	G LLLL67++113 R#obii[; -- .b.@.@-AB	 	Ryy$&&r0   z.parallel-batch-state.jsonz*"schema": "anu_v3.parallel_batch_state.v1")name_suffixcontent_markerz.parallel-batch-summary.mdz%# Parallel Batch Consolidated Summary)ra   summaryc                   t        |      rt        d| d      |j                         r]| j                  |   }|j                  j                  |d         }|s	 |j                  d      }|d   |v }|st        d| d	| d
      |j                  j                  dd       |j                  |d       y# t        t        f$ r d}Y Xw xY w)a  HIGH-4 / 9-R.2 write-guard, precise envelope:

          * git-tracked path                      -> REFUSE (byte-0 immutable)
          * git-untracked & non-existent          -> ALLOW  (NEW deliverable)
          * git-untracked & existing, and the path
            is a sanctioned coordinator deliverable
            (own state/summary)                   -> ALLOW  (idempotent
                                                     overwrite-by-design)
          * git-untracked & existing, NOT a
            sanctioned deliverable                -> REFUSE (never clobber an
                                                     unrelated untracked file)
        z#refusing to write git-tracked path z2 (9-R.1/9-R.2: tracked files are byte-0 immutable)r   ry   encodingr   Fz9refusing to overwrite existing untracked non-deliverable z; (9-R.2: only NEW untracked paths or the coordinator's own z deliverable may be written)T)parentsexist_okN)rC   r*   exists_DELIVERABLEnamer   	read_textOSErrorUnicodeDecodeErrorr9   mkdir
write_text)r   r?   contentkindspec
sanctionedexistings          r1   _guarded_writez'ParallelBatchCoordinator._guarded_writep  s     1)5aS 9D D  88:##D)Dm)<=J' {{G{<H!%&6!78!CJ -Oc & <> 
 	
td3	Ww/  !34 '!&J's   B9 9CCc                    t        |      }| j                  |t        j                  | j	                         dd      d       |S )Nr   F)indentensure_asciira   )r   r   jsondumpsr   ro   pathr?   s      r1   write_statez$ParallelBatchCoordinator.write_state  s?    JJJt'')!%H	

 r0   c                ^    t        |      }| j                  || j                         d       |S )Nr   )r   r   r   r   s      r1   write_summaryz&ParallelBatchCoordinator.write_summary  s+    JAt>>@)Lr0   c                    | j                  |       | j                  |       t        | j                  | j	                         | j                               S )N)r_   ra   rb   )r   r   r^   r_   r   r   )ro   
state_pathsummary_paths      r1   r7   zParallelBatchCoordinator.run  sL    
 	$<( ]]""$668
 	
r0   )rf   rY   returnNone)rf   rY   r   r8   )rF   r8   r   r   )rF   r8   r   r8   r   r   r   )r   z"Optional[Dict[str, Sequence[str]]]r   zDict[str, LoopPlan])r   zSequence[PacketCandidate]r   zDict[str, PacketCandidate])r   zSequence[CallbackEvent]r   zDict[str, str])r   zList[tuple])NN)r   zOptional[Dict[str, str]]r   zOptional[Dict[str, bool]]r   r`   )r   r`   )r   r8   )r?   r   r   r8   r   r8   r   r   )r   
str | Pathr   r   )r   r   r   r   r   r^   )r+   r,   r-   rq   staticmethodrg   r   r   r   r   r   r   r   r   r   r   classmethodr   r   r   r7   r/   r0   r1   rd   rd   y   s   &
R 4 4,5
 ?C ; 	 ;3;	#;
%-%	%P

 6:59"62"6 3"6 
	"6J
*)'d 8J

 8E
	L "0 "0H


 !
 
	
r0   rd   c                   t        j                  t        |       j                  d            }|d   D cg c]  }t	        |d   |d   |d   |d   |d   |j                  d	g       |j                  d
g       |j                  dg       |j                  dg       |j                  dg       |j                  dd      |j                  dd             }}t        |d   |      S c c}w )zABuild a BatchPlan from a parallel-batch fixture JSON (read-only).ry   r   r[   rF   rG   rH   rI   rJ   rM   rN   rO   rP   rQ   rS   rR   rU   r   )rF   rG   rH   rI   rJ   rM   rN   rO   rP   rQ   rS   rU   rZ   )rZ   r[   )r   loadsr   r   rE   r   rY   )fixture_pathdatarw   r[   s       r1   load_plan_from_fixturer     s    ::d<(22G2DED  h  	z]iL12%&'A%B&'(C&D55!126$%EE*CR$Huu\2.%%4EE"3R8%%;%%3	
F " m!4VDD#s   BC%)r?   r   r   r   )r   r   r   rY   )1r.   
__future__r   r~   r   r6   dataclassesr   r   pathlibr   typingr   r   r	   r
   anu_v3.batch_dependency_matrixr   r   anu_v3.batch_join_policyr   r   r   r   r   r   r   r   r   anu_v3.callback_track_registryr   r   anu_v3.goal_loop_plannerr   r   r   anu_v3.track_loop_stater   r   r(   rV   RuntimeErrorr*   rC   rE   rY   r^   rd   r   r/   r0   r1   <module>r     s   ( #    (  1 1 K
 
 
 O N ? "#!"
# +l +,    C C C   u
 u
p	Er0   