
    U}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mZ  ee	      j                         j                  j                  Z ej                  d      ZdZedz  dz  Zdd	Zdd
Zd ZddZddZedk(  r e e             y)uc  hooks.spawn_confirmed_boot_hook — 봇 부팅 시 spawn-confirmed marker 생성.

task-2946 (P0 4096자 절벽 해소) — task-2942 가 프롬프트 최상단에 주입하던
"세션 시작 즉시 마커 생성" 지시(197자)를 **봇 부팅 경로**로 이전한다.

배경:
  dispatch 는 ``cokacdir --cron`` 으로 봇 세션을 예약하는데, 전달 채널이
  프롬프트 4096자 초과 시 silent drop 한다(task-2945 실측). team_prompts 의
  base 프롬프트가 이미 4,040자대였으므로 마커 지시 197자가 dev1~7 을 절벽
  밖으로 밀어냈다. 마커 지시는 **프롬프트에서 제거**하고, 봇 세션이 실제로
  뜰 때 UserPromptSubmit 훅이 마커를 대신 생성한다.

부수 효과 (의도된 개선):
  기존 방식은 "봇이 지시를 읽고 첫 명령으로 실행" 에 의존했다 — 봇이 순서를
  어기면 마커가 늦거나 없었다. 훅 방식은 세션이 프롬프트를 받는 시점에
  **무조건** 발화하므로 판정이 봇의 순종도와 무관해진다.

판정 계약 (scripts/harness/v36/terminal_state_classifier.py::_verify_bot_spawn):
  ``{events_dir}/{task_id}.spawn-confirmed-*.json`` glob 만 본다. bot_id 는
  대조에 쓰이지 않는 메타데이터이므로 best-effort 로 채운다.

false-positive 방지 (중요):
  이 훅은 **모든** Claude 세션(회장 채팅 포함)의 UserPromptSubmit 에서 돈다.
  단순히 "task-NNNN" 문자열만 보고 마커를 쓰면, 회장이 채팅에서 task id 를
  언급하기만 해도 dispatch 가 "봇이 떴다"고 오판한다. 따라서 dispatch 프롬프트
  고유 지문 2개가 **모두** 있을 때만 쓴다:
    1) ``memory/tasks/<task_id>.md``  (build_prompt 가 항상 넣는 작업파일 경로)
    2) ``collector_role=ANU``         (self-collector doctrine block, 전 팀 공통)

무손상 원칙:
  훅은 봇 세션을 절대 죽이면 안 된다. 어떤 예외에서도 exit 0 이며 stdout 에
  아무것도 쓰지 않는다(UserPromptSubmit stdout 은 프롬프트에 주입되므로
  출력하면 그 자체가 프롬프트를 늘린다 — 절벽 회귀 방지).
    )annotationsN)Pathz(memory/tasks/(task-[A-Za-z0-9_.+-]+)\.mdzcollector_role=ANUlogszspawn_confirmed_boot_hook.logc                l    | rt         | vryt        j                  |       }|r|j                  d      S dS )u   dispatch 프롬프트에서 task_id 를 추출한다.

    지문 2개가 모두 있을 때만 task_id 를 돌려준다. 그 외에는 None
    (= 일반 대화이므로 marker 를 쓰면 안 된다).
    N   )_DOCTRINE_FINGERPRINT_TASK_FILE_REsearchgroup)promptms     6/home/jay/workspace/hooks/spawn_confirmed_boot_hook.pyextract_task_idr   6   s7     *&8V$A1771:$$    c                    | j                  d      xs# t        j                  j                  d      xs d}|rt        |      j                  nd}|xs dS )u   봇 식별자 (판정에 쓰이지 않는 메타데이터 — best-effort).

    cokacdir 봇 세션의 cwd 는 ``/home/jay/.cokacdir/workspace/<ID>`` 이다.
    cwdPWD unknown)getosenvironr   name)payloadr   r   s      r   resolve_bot_idr   B   sE    
 ++e

;

u 5
;C 49>>bD9r   c                 F   ddl } t        dz  dz  }	 | j                  j                  d|      }||j                  y| j                  j                  |      }|j                  j                  |       |j                  S # t        $ r}t        d|        Y d}~yd}~ww xY w)u  ``write_spawn_confirmed_marker`` 를 **파일 경로로** 로드한다.

    ``from dispatch.spawn_verification import ...`` 를 쓰면 dispatch 패키지
    __init__ 전체(수십 모듈 + .env.keys 로드 + 로거 설정)가 **모든 세션의 모든
    프롬프트마다** 실행된다. spawn_verification 은 stdlib 만 쓰도록 설계된
    모듈이므로 패키지를 거치지 않고 직접 로드해 부작용과 지연을 없앤다.
    r   Ndispatchzspawn_verification.py_spawn_verification_bootu1   [spawn-boot-hook] 모듈 로드 실패 (무시): )
importlib.util
_REPO_ROOTutilspec_from_file_locationloadermodule_from_specexec_modulewrite_spawn_confirmed_marker	Exception_log)	importlibpathspecmodexcs        r   _load_marker_writerr.   L   s     
"%<<D	~~556PRVW<4;;.nn--d3$/// @FGs   *A? AA? ?	B BB c                    	 t         j                  j                  dd       t         j                  dd      5 }|j	                  | dz          d d d        y # 1 sw Y   y xY w# t
        $ r Y y w xY w)NT)parentsexist_okazutf-8)encoding
)	_LOG_PATHparentmkdiropenwriter'   )linefhs     r   r(   r(   c   sh    td;^^C'^2 	"bHHTD[!	" 	" 	" s.   8A$ AA$ A!A$ !A$ $	A0/A0c                    	 t         j                  j                         } 	 | j	                         rt        j                  |       ni }t        |t              sy|j                  d      xs d}t        |t              syt        |      }|syt               }|y	  ||t        |            }t        d| d|        y# t        $ r Y yw xY w# t        $ r d| i}Y w xY w# t        $ r}t        d| d|        Y d}~yd}~ww xY w)uG   UserPromptSubmit 훅 진입점. 어떤 경우에도 0 을 반환한다.r   r   r   Nz[spawn-boot-hook] z marker=u    실패 (무시): )sysstdinreadr'   stripjsonloads
isinstancedictr   strr   r.   r   r(   )rawr   r   task_idwriterr*   r-   s          r   mainrI   l   s   iinn"%(YY[$**S/b
 gt$[["(bFfc"f%G "F~Dg~g67!'(4&9: =  
  "S/",  D!'*<SEBCCDs:   B? 'C #C! ?	C
CCC!	D*D  D__main__)r   rE   returnz
str | None)r   rD   rK   rE   )r:   rE   rK   None)rK   int)__doc__
__future__r   rA   r   rer=   pathlibr   __file__resolver6   r    compiler	   r   r5   r   r   r.   r(   rI   __name__
SystemExit r   r   <module>rX      s   !D #  	 	 
 (^##%,,33
 

FG,  "AA		%."J z
TV
 r   