
    j>                       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Zddlm	Z	 dZ
dZdZdZd	Zd
ZdZdZdZdZeeeeeeeegZ ee      D  ci c]  \  } }|| 
 c}} ZdZej0                  j3                  ed      Zej0                  j3                  ed      Z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$d'dZ%d(dZ&d)dZ'yc c}} w )*u  v3.6 Runtime Harness — Layer 2: Spawn Detector.

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

Contract:
- detect_spawn_state(task_id, schedule_id) -> dict
  Returns {"state": <9-state enum>, "signals": {...}, "reason": str}

- 9 states: NOT_REGISTERED, REGISTERED, FIRED, SESSION_SEEN, WORK_STARTED,
            ARTIFACT_SEEN, CALLBACK_REGISTERED, DONE, UNKNOWN

- Cross-validation across ≥2 signals required for most states.
- CRITICAL: When signals insufficient/conflicting → UNKNOWN.
  "spawn 0" single-source assertion is FORBIDDEN.
- No backward state transitions (only forward or → UNKNOWN).
- system_prompt path direct comparison — NO grep -v cokacdir filter (known bug).
    )annotationsN)Optionalz4CHAIR-AUTH-TASK-2704-V36-CONTROL-PLANE-P0-MVP-260528NOT_REGISTERED
REGISTEREDFIREDSESSION_SEENWORK_STARTEDARTIFACT_SEENCALLBACK_REGISTEREDDONEUNKNOWNz/home/jay/workspacezmemory/eventszmemory/task-timers.jsonz/home/jay/.cokacdirc                    	 t        | ||xs t        |xs t        |xs t              S # t        $ r}t
        i d| ddcY d}~S d}~ww xY w)a  Detect the spawn state for task_id using multi-signal cross-validation.

    Returns:
        {
            "state": str,         # 9-state enum value
            "signals": dict,      # raw signal values
            "reason": str,        # human-readable decision reason
            "signal_count": int,  # number of positive signals observed
        }

    Never raises. Returns UNKNOWN on any internal error.
    )task_idschedule_id
events_dirtimers_filecokacdirz/detect_spawn_state internal error (safe-fail): r   statesignalsreasonsignal_countN)_detect_spawn_state_impl_EVENTS_DIR_TIMERS_FILE	_COKACDIR	Exceptionr   )r   r   r   r   r   excs         9/home/jay/workspace/scripts/harness/v36/spawn_detector.pydetect_spawn_stater    ?   sa    &
'#!0[#3|*
 	
  
GuM	
 	

s   '* 	AA AAc                    | t         k(  s	|t         k(  ryt        j                  | d      t        j                  |d      k\  S )zReturn True if state_a is >= state_b in the progression order.

    UNKNOWN is treated as incomparable (returns False for any comparison).
    F)r   _STATE_ORDINALget)state_astate_bs     r   state_ger'   c   s;    
 'W/gr*n.@.@".MMM    c                r   t        j                          }i }t        | |      }||d<   |dv|d<   |st        | |      }||d<   t        |      |d<   t	        j                  t
        j                  j                  ||  d            }t        |      dkD  |d<   ||d	<   d
}	|rCt
        j                  j                  |d| d      }
t
        j                  j                  |
      }	|	|d<   t               }d
}d }t               }|D ]  }|s||k7  sd}|} n ||d<   ||d<   ||d<   t        | |      }||d<   |d uxr |dk  |d<   t        | ||      }||d<   |d uxr |dk  |d<   t	        j                  t
        j                  j                  ||  d            }||d<   t        |      dkD  |d<   t	        j                  t
        j                  j                  ||  d            }t        |      dkD  |d<   d
}|rBt
        j                  j                  || d      }t
        j                  j                  |      }||d<   |d   r|dv rt        t        |dt!        |            S |d   r$|d   s|dv rt        t"        |d t!        |            S |d   rt        t$        |d!t!        |            S t'        |d   |d   |d   |g      }|d   r |d"k\  rt        t(        |d#t!        |            S |r|rt        t*        |d$t!        |            S |r"|	s|d   rt        t,        |d%t!        |            S |d   r |d   rt        t.        |d&t!        |            S |d    xr& |d    xr |d    xr |d    xr |d    xr |d    }|rt        t0        |d't!        |            S t        t2        |d(t!        |            S ))Ntimer_status)absenttimer_presentr   schedule_id_presentz.dispatched*r   dispatch_marker_presentdispatch_marker_pathsFschedule_historyz.logschedule_history_presentTbot_session_activebot_session_hexanu_session_hexworktree_mtime_secondsi  worktree_freshartifact_mtime_secondsartifact_freshz.done*done_markersdone_marker_presentz.callback-*callback_marker_presentz.outputbot_output_present)	completed!completed_owner_decision_acceptedz%done_marker_present + timer completedz&callback_marker_present + done contextzrecent artifact mtime < 900s   z+dispatch_marker + corroborating work signalz2bot_session_active with distinct system_prompt hexz1schedule_id + schedule_history or dispatch_markerz#timer_running + schedule_id_presentz>all key signals absent (timer, schedule_id, session, artifact)ua   signals present but insufficient or conflicting for firm state determination — poll next sample)time_get_timer_status_get_schedule_id_from_timerboolglobospathjoinlenisfile_get_anu_session_hex_list_claude_processes_get_worktree_mtime_seconds_get_artifact_mtime_seconds_resultr   
_pos_countr   r
   sumr	   r   r   r   r   r   )r   r   r   r   r   nowr   r*   dispatch_markersr1   history_pathr4   r2   r3   bot_processesproc_hexr5   r7   r9   callback_markersr<   bot_output_pathwork_started_signals
key_absents                           r   r   r   o   s    ))+CG %Wk:L*GN+;>GO 1';G(GM%)+%6G!" yyjWI\:R!ST),-=)>)BG%&'7G#$  %ww||H.@[MQUBVW#%77>>,#? *BG&' +,OO*,M! O3!%&O %7G !!0G!0G 9#F(>G$% 6d B cG]`cGcG 9*cR(>G$% 6d B cG]`cGcG 99RWW\\*	6HIJL*GN%(%6%:G!" yyjWI[:Q!RS),-=)>)BG%& '',,xK=1HIWW^^O<$6G ! $%,:l*ltW&MzZaObcc ()%&,:l*l*G5]_ijq_rss  }g/MzZaObcc )* !$%	   ().Ba.G|W.[]gho]pqq o|W.bdnovdwxx 0G<U4Vug'Z\fgn\opp G,A$Bz7,QS]^eSfgg
 O$$ 	/-..	/,--	/ 122	/ ())		/
 -..  ~w0pr|  ~E  sF  G  	G k7	 r(   c                    | |||dS )Nr    r   s       r   rN   rN      s    $	 r(   c                H    d}| j                         D ]  }|du s|dz  } |S )zCount positive boolean signals.r   T   )values)r   countvs      r   rO   rO     s4    E^^ 9QJE Lr(   c                (   	 t         j                  j                  |      syt        |d      5 }t	        j
                  |      }d d d        j                  di       }| |vry||    j                  dd      S # 1 sw Y   5xY w# t        $ r Y yw xY w)Nr+   utf-8encodingtasksstatusunknownrE   rF   rI   openjsonloadr$   r   r   r   fhdatare   s        r   rA   rA   
  s    
ww~~k*+0 	!B99R=D	!"%%W~!!(I66	! 	!  s3   B B A9B $B 9B>B 	BBc                &   	 t         j                  j                  |      sy t        |d      5 }t	        j
                  |      }d d d        j                  di       }| |vry ||    j                  d      S # 1 sw Y   4xY w# t        $ r Y y w xY w)Nrb   rc   re   r   rh   rl   s        r   rB   rB     s    
ww~~k*+0 	!B99R=D	!"%%W~!!-00	! 	!  s3   B B A8B $B 8B=B 	BBc                 d   t         j                  j                  dd      } | r| S 	 t        dd      5 }|j	                         j                  dd      j                  dd	      }d
d
d
       dd
l}|j                  d      }|r|j                  d      S 	 y
# 1 sw Y   4xY w# t        $ r Y y
w xY w)zGet the hex identifier of the current ANU (orchestrator) session.

    Reads from the ANU_SESSION_HEX env var (set by the session itself),
    or attempts to identify from the CLAUDE_SESSION_ID / system_prompt path.
    Returns None if unavailable.
    ANU_SESSION_HEX z/proc/self/cmdlinerbrb   replaceerrors  Nr   system_prompt_([0-9a-f]{16})r]   )rE   environr$   ri   readdecodert   researchgroupr   )env_hexrm   cmdliner}   ms        r   rJ   rJ   &  s     jjnn.3G	&- 	Wggi&&wy&AII&RUVG	W 	II5w?771:  	W 	W  s(   B# 2B$0B# B B# #	B/.B/c                    ddl } g }	 t        j                  d      D ]  }|j                         s	 d| d}t	        |d      5 }|j                         j                  dd	      j                  d
d      }ddd       dvrf| j                  d|      }|r!|j                  |j                  d             nd|v r|j                  d        	 |S # 1 sw Y   ]xY w# t        t        f$ r Y w xY w# t        $ r Y |S w xY w)u   Return list of system_prompt hex values for running claude processes.

    Uses direct /proc inspection. NO grep -v cokacdir filter (spec §1.1).
    Returns list of hex strings (may include None for processes without hex).
    r   Nz/procz/proc/z/cmdliners   rb   rt   ru   rw   rx   claudery   r]   )r}   rE   listdirisdigitri   r{   r|   rt   r~   appendr   PermissionErrorFileNotFoundErrorr   )r}   hexes	pid_entrycmdline_pathrm   r   r   s          r   rK   rK   @  s    EG, 	I$$&!'	{(;,- _ ggi..wy.IQQRXZ]^G_ 7*II=wGLL,(LL&	& L_ _ $%67  LsY   )C3 C2C6CC3 A
CC3 C	CC0-C3 /C00C3 3	D ?D c                `   	 t         j                  j                  t        d      }t         j                  j	                  |      syt         j                  j                  ||  d      }t        j
                  |      }|syt        d |D              }t        ||z
        S # t        $ r Y yw xY w)zEReturn seconds since last modification of any task worktree, or None.z
.worktreesNz-*c              3     K   | ]C  }t         j                  j                  |      s#t         j                  j                  |       E y wNrE   rF   existsgetmtime.0ps     r   	<genexpr>z._get_worktree_mtime_seconds.<locals>.<genexpr>j  s/     W1RWW^^TUEV277++A.W
   $A$A)	rE   rF   rG   
_WORKSPACEisdirrD   maxintr   )r   rQ   worktrees_basepattern	worktreeslatest_mtimes         r   rL   rL   `  s    j,?ww}}^,'',,~'"~>IIg&	W	WW3%&& s   AB! :B! B! !	B-,B-c                    	 t         j                  j                  ||  d      }t        j                  |      }|syt	        d |D              }t        ||z
        S # t        $ r Y yw xY w)zOReturn seconds since last modification of any task-related event file, or None.z.*Nc              3     K   | ]C  }t         j                  j                  |      s#t         j                  j                  |       E y wr   r   r   s     r   r   z._get_artifact_mtime_seconds.<locals>.<genexpr>w  s/     S1PQAR277++A.Sr   )rE   rF   rG   rD   r   r   r   )r   r   rQ   r   filesr   s         r   rM   rM   p  sg    '',,zgYb>:		'"SSS3%&& s   :A A 	A)(A))NNNN)r   strr   Optional[str]r   r   r   r   r   r   returndict)r%   r   r&   r   r   rC   )r   r   r   r   r   r   r   r   r   r   r   r   )
r   r   r   r   r   r   r   r   r   r   )r   r   r   r   )r   r   r   r   r   r   )r   r   r   r   r   r   )r   r   )r   zlist[Optional[str]])r   r   rQ   floatr   Optional[int])r   r   r   r   rQ   r   r   r   )(__doc__
__future__r   rD   rj   rE   
subprocessr@   typingr   CHAIR_AUTHORIZATION_IDr   r   r   r   r	   r
   r   r   r   _STATE_ORDER	enumerater#   r   rF   rG   r   r   r   r    r'   r   rN   rO   rA   rB   rJ   rK   rL   rM   )iss   00r   <module>r      s  " #   	   O  "
+ 
 		 $-\#:;41a!Q$;"
ggll:7ww||J(AB!	 "& $!%"!
!
!
 !
 	!

 !
 
!
HNFFF F 	F
 F 
FR4@ 
w	 <s   C"