
    j8                       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ZdZdZd	Zd
ZdZdZeeeeeegZ ee      D  ci c]  \  } }|| 
 c}} ZdZdZdZdZej2                  j5                  ed      ZefddZ	 d	 	 	 	 	 ddZ	 d	 	 	 	 	 	 	 	 	 d dZ	 d	 	 	 	 	 d!dZddZ d"dZ!	 	 	 	 	 	 	 	 	 	 d#dZ"d$dZ#d%dZ$d&dZ%d'dZ&yc c}} w )(u  v3.6 Runtime Harness — Layer 4: Closeout Marker Watcher.

chair_authorization_id=CHAIR-AUTH-TASK-2704-V36-CONTROL-PLANE-P0-MVP-260528

Contract:
- scan_closeout_markers(events_dir) -> list[dict]
  Synchronous scan — NOT a daemon. Suitable for watchdog or finish-task hook.

- detect_closeout_state(task_id) -> dict
  Returns {"state": <6-state enum>, "markers_found": [...], "priority": int, "reason": str}

- 6 states: WORK_CLOSEOUT_STARTED, FINISH_IN_PROGRESS, CALLBACK_LAUNCHED,
            DONE, ANU_RECEIVED, CHAIR_REPORTED

- 5 closeout marker patterns:
  1. <task_id>.*active.json
  2. <task_id>.harness-mvp-active*
  3. <task_id>.done*
  4. <task_id>.callback-*
  5. <task_id>.completion.txt

- Recovery priority (encoded as priority field):
  normal_callback (1) > closeout_marker_watcher (2) > fallback_safety_net (3)

- signal_anu(task_id, state, priority): writes signal file to
  memory/events/<task_id>.anu-signal-<state>.json (no ANU spawn).
  ANU body picks up signal asynchronously.
    )annotationsN)datetimetimezone)Optionalz4CHAIR-AUTH-TASK-2704-V36-CONTROL-PLANE-P0-MVP-260528WORK_CLOSEOUT_STARTEDFINISH_IN_PROGRESSCALLBACK_LAUNCHEDDONEANU_RECEIVEDCHAIR_REPORTED         z/home/jay/workspacezmemory/eventsc                <    	 t        |       S # t        $ r g cY S w xY w)u   Scan events_dir for all closeout markers across all tasks.

    Returns list of dicts: [{task_id, pattern_matched, marker_path, mtime_seconds_ago}]
    Never raises — returns [] on any error.
    )_scan_closeout_markers_impl	Exception)
events_dirs    B/home/jay/workspace/scripts/harness/v36/closeout_marker_watcher.pyscan_closeout_markersr   F   s&    *:66 	s   
 c                ~    	 t        | |xs t              S # t        $ r}t        g t        d| dcY d}~S d}~ww xY w)ao  Detect closeout state for a specific task_id.

    Returns:
        {
            "state": str,           # 6-state enum
            "markers_found": list,  # matching marker paths
            "priority": int,        # recovery priority (1=normal_callback, 2=watcher, 3=fallback)
            "reason": str,          # decision reason
        }

    Never raises.
    )task_idr   z!detect_closeout_state safe-fail: statemarkers_foundpriorityreasonN)_detect_closeout_state_impl_EVENTS_DIRr   r    PRIORITY_CLOSEOUT_MARKER_WATCHER)r   r   excs      r   detect_closeout_stater!   R   sN     
*!0[
 	
  
*89#?	
 	

s    	<7<<c                P    	 t        | |||xs t              S # t        $ r Y yw xY w)zWrite an ANU signal file to events_dir.

    Does NOT spawn ANU. ANU body picks up the signal asynchronously.
    Returns the signal dict on success, None on failure. Never raises.

    Signal file: memory/events/<task_id>.anu-signal-<state>.json
    r   r   r   r   N)_signal_anu_implr   r   r#   s       r   
signal_anur%   p   s9    !0[	
 	
  s    	%%c                   	 ddl m} 	  || |      S # t        $ r 	 ddl}t        j
                  j                  t        j
                  j                  t              d      }|j                  j                  d|      }||j                  Y y|j                  j                  |      }|j                  j                  |       |j                  }n# t        $ r Y Y yw xY wY w xY w# t        $ r Y yw xY w)ut  watcher 보조 결선: PR diff 의 미선언 artifact 혼입을 *보고만* 한다(차단 X).

    주 차단 결선은 finish-task.sh pre-push 단계가 담당한다. 여기서는
    pr_diff_hygiene_guard.detect_contamination 을 재사용해 read-only 로 감지만
    수행하고, 결과 dict(detection_only=True)를 반환한다. 절대 raise 하지 않는다.
    r   )detect_contaminationNzpr_diff_hygiene_guard.pypr_diff_hygiene_guard)r(   r'   ImportErrorimportlib.utilospathjoindirname__file__utilspec_from_file_locationloadermodule_from_specexec_moduler   )changed_filesexpected_filesr'   	importlib_p_spec_mods          r   detect_pr_diff_contaminationr;      s    >#M>BB  	!bggooh79STBNN::;RTVWE} 4>>2259DLL$$T*#'#<#<  		 !  sK    C& 	C#A/CACC#	CC#CC#"C#&	C21C2c           	     \   g }t        j                          }t        j                  j                  |       s|S t	        j                  t        j                  j                  | d            D ].  }t        |d      }|s|j                  t        |d||             0 t	        j                  t        j                  j                  | d            D ].  }t        |d      }|s|j                  t        |d||             0 t	        j                  t        j                  j                  | d            D ].  }t        |d      }|s|j                  t        |d	||             0 t	        j                  t        j                  j                  | d
            D ].  }t        |d      }|s|j                  t        |d||             0 t	        j                  t        j                  j                  | d            D ].  }t        |d      }|s|j                  t        |d||             0 |S )Nz*.*active.json.*active.jsonactive_jsonz*.harness-mvp-active*z.harness-mvp-activeharness_mvp_activez*.done*z.donedonez*.callback-*z
.callback-callbackz*.completion.txt.completion.txtcompletion_txt)
timer+   r,   isdirglobr-   _extract_task_idappend_marker_entry_extract_task_id_prefix)r   resultsnowr,   r   s        r   r   r      s   G
))+C77==$ 		"'',,z3CDE M"49NN=-sKLM 		"'',,z3JKL T)$0EFNN=2FcRST 		"'',,z9=> F)$8NN=&$DEF 		"'',,z>BC J)$=NN=*dCHIJ 		"'',,z3EFG P)$0ABNN=2BD#NOP
 N    c                   t        j                          }g }t        j                  t        j                  j	                  ||  d            }t        j                  t        j                  j	                  ||  d            }t        j                  t        j                  j	                  ||  d            }t        j                  t        j                  j	                  ||  d            }t        j                  t        j                  j	                  ||  d            }t        j                  t        j                  j	                  ||  d            }	|j                  |       |j                  |       |	r?|	D ]!  }
d|
v st        t        ||	z   t        d      c S  t        t        ||	z   t        d	      S t        |      d
kD  }t        d |D              }|r7|j                  |       |st        |      dk\  rt        t        |t        d      S |r=|j                  |       |D cg c]	  }d|v s| }}|rt        t        |t        d      S |s|rN|r|j                  |       |r#t        d |D              s|j                  |       t        t        |t        d      S |s|rt        t         |t        d      S t        t         g t"        d      S c c}w )Nr=   z.harness-mvp-active*z.done*z.callback-*rB   z.anu-signal-*r   zANU signal CHAIR_REPORTED foundzANU received signal foundr   c              3  0   K   | ]  }d |v xs d|v   yw)notifiedzanu-notifiedN .0ps     r   	<genexpr>z._detect_closeout_state_impl.<locals>.<genexpr>   s!     S1
a>>Q+>>Ss   r   zdone + notified markers presentlaunchzcallback-launch marker presentc              3  $   K   | ]  }d |v  
 yw)rV   NrQ   rR   s     r   rU   z._detect_closeout_state_impl.<locals>.<genexpr>  s     %Lh!m%Ls   uD   completion.txt or callback-cause markers — finish-task in progressuS   closeout marker (active.json or harness-mvp-active) found — work closeout startedu<   no closeout markers found — awaiting first closeout marker)rD   rF   r+   r,   r-   extend_closeout_resultr   PRIORITY_NORMAL_CALLBACKr   lenanyr
   r	   r   r   r   PRIORITY_FALLBACK_SAFETY_NET)r   r   rL   r   r>   harness_mvp
done_filescallback_filesrC   anu_signal_filessfdone_marker_presentnotified_donerT   launch_filess                  r   r   r      s   
))+CM ))BGGLLy5NOPK))BGGLLy@T5UVWK277<<
wiv4FGHJYYrww||J7);8OPQNYYrww||J7)?8STUNyyjWI]:S!TU%% " 	B2%'"!$44,5	 	  ,,$'	
 	
 j/A-S
SSMZ(C
Oq0#(1	  ^,#1CaX]CC#!(0	    0#%L^%L"L  0,R	
 	
 k!,a	
 	
 
$F	 A Ds   .	K8Kc           	     n   t        j                  t        j                        }|j	                         }|j                  d      }ddddj                  |d      }dd| ||||t        d	}|  d
| d}	t        j                  j                  ||	      }
t        j                  |d       |
dz   }	 t        |dd      5 }t        j                  ||dd       d d d        t        j                  ||
       t        j                  j!                  |      r	 t        j"                  |       	 ddlm}  |d| |
||d       |S # 1 sw Y   lxY w# t$        $ r Y /w xY w# t        j                  j!                  |      r&	 t        j"                  |       w # t$        $ r Y w w xY ww xY w# t$        $ r Y |S w xY w)Nz%Y%m%d%H%M%Snormal_callbackcloseout_marker_watcherfallback_safety_net)r   r   r   unknownv1
anu_signal)marker_versionmarker_typer   closeout_stater   priority_namesignal_timechair_authorization_idz.anu-signal-z.jsonT)exist_okz.tmpwzutf-8)encodingFr   )ensure_asciiindentr   )log_runtime_eventanu_signal_written)signal_pathro   r   )
event_typer   payload)r   rL   r   utc	isoformatstrftimegetCHAIR_AUTHORIZATION_IDr+   r,   r-   makedirsopenjsondumpreplaceexistsunlinkr   +scripts.harness.v36.runtime_decision_loggerrx   )r   r   r   r   now_utcts_isots_filerp   signalfilenamerz   tmp_pathfhrx   s                 r   r$   r$   -  s    ll8<<(G F~.G $  
c(I	  #&"8	F ,ugU3H'',,z84KKK
T*V#H	(C'2 	@bIIfbuQ?	@


8[)77>>(#		(#
Q+*"'$	
 M3	@ 	@   77>>(#		(#  $$  Msl   /E =EE E +F' EE 	EE F$>FF$	F F$F  F$'	F43F4c                    	 t        |t        j                  j                  |      z
        }| |||dS # t        $ r d}Y w xY w)N)r   pattern_matchedmarker_pathmtime_seconds_ago)intr+   r,   getmtimer   )r   r   r,   rL   mtime_ss        r   rI   rI   l  sS    cBGG,,T223 *$	   s   +4 AAc                    	 t         j                  j                  |       }d|v r|j                  d      nd}|dkD  r|d| }|j	                  d      r|S y# t
        $ r Y yw xY w)z<Extract task_id from a path by stripping the suffix pattern..r   r   Ntask-r+   r,   basenamefind
startswithr   )r,   suffix_patternr   idx	candidates        r   rG   rG   y  sl    77##D)$'8OhmmC 7 #I##G,   s   AA 	A"!A"c                    	 t         j                  j                  |       }|j                  |      }|dkD  r|d| }|j	                  d      r|S y# t
        $ r Y yw xY w)z7Extract task_id as prefix before separator in basename.r   Nr   r   )r,   	separatorr   r   r   s        r   rJ   rJ     sd    	77##D)mmI&7 #I##G,   s   AA 	AAc                    | |||dS )Nr   rQ   )r   markersr   r   s       r   rY   rY     s     	 rM   )r   strreturnlist)N)r   r   r   Optional[str]r   dict)
r   r   r   r   r   r   r   r   r   Optional[dict])r5   r   r6   zOptional[list]r   r   )r   r   r   r   r   r   )
r   r   r   r   r   r   r   r   r   r   )
r   r   r   r   r,   r   rL   floatr   r   )r,   r   r   r   r   r   )r,   r   r   r   r   r   )
r   r   r   r   r   r   r   r   r   r   )'__doc__
__future__r   rF   r   r+   rD   r   r   typingr   r   r   r   r	   r
   r   r   _CLOSEOUT_ORDER	enumerate_CLOSEOUT_ORDINALrZ   r   r]   
_WORKSPACEr,   r-   r   r   r!   r%   r;   r   r   r$   rI   rG   rJ   rY   )iss   00r   <module>r      s  8 #   	  ' O  0 ) ' !  '0&@AdaQTA   #$    "
ggll:7
 -8 	 !%


 

D !%	  	
 8 &*" B%PWt::: : 	:
 
:~
 }
 Bs   C