
    yj#                       d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	m
Z
mZmZmZ  ee      j                         j                   Zej                   Z ee      ej(                  vr"ej(                  j+                  d ee             ddlmZ ddlmZmZmZ dZd	Zd
ZdZdZ dZ!dddddddddddddZ"d&dZ#d'd(dZ$d)dZ%d*dZ&dd d!	 	 	 	 	 	 	 d+d"Z'd'd,d#Z(d-d$Z)e*d%k(  r e+ e)             y).u!  hooks/stop_anu_callback_collector_verifier.py — Stop hook (STAGED · live 미적용).

task-2644 ANU_CALLBACK_COLLECTOR_CONTROL_PLANE (회장 verbatim 우선순위 5 + 보강-5).
spec: memory/specs/system_anu_callback_collector_control_plane_spec_260524.md
spec sha256: b27da557d4245bce476cd63f4ab174aefc8a25d2da07ec2c8d2c83b01ee96153

★ 본 hook 은 staged template only · ~/.claude/settings.json 에 등록되지 않은 상태.

회장 verbatim 종료 차단 10 조건 (보강-5 반영 후 §14.6):
    1. callback_envelope_parsed 없으면 fail
    2. context_recovered 없으면 fail
    3. terminal_state_classified 없으면 fail
    4. next_action_decided 없으면 fail
    5. auto_action_dispatched / chair_report_emitted / noop_terminal_recorded /
       batch_wait_recorded 중 하나 없으면 fail
    6. callback_ledger_written 없으면 fail
    7. "callback received / 도착 / 수신" 표현 + source attribution 없으면 fail
    8. schedule_history 사후 조회를 inbound 수신처럼 표현하면 fail
    9. next_action_result 없으면 fail
    10. state_version mismatch / .anu_state stale 인데 SAFE_DEGRADED_MODE /
        HOLD_FOR_CHAIR 둘 다 아니면 fail

추가 보강-5 조건: next_action_result=FAILED + recovery_action 없으면 fail (조건 9 의 보충).

Claude Code Stop hook 계약 (참고):
    - stdin: {"session_id":..., "stop_hook_active":..., "hook_event_name":"Stop"}
    - stdout: JSON · "decision":"block" + "reason" 반환 시 종료 차단
    - exit 0: 일반 · non-zero (2): block 으로도 해석 가능
    )annotationsN)Path)AnyDictListOptionalTuple)source_attribution_guard)SAFE_DEGRADED_ALLOWEDNextActionResultvalidate_branch_invariantz-hooks.stop_anu_callback_collector_verifier.v1ANU_CALLBACK_LEDGER_PATHz$memory/system/.callback_ledger.jsonlANU_LAST_OUTPUT_TEXTCOKACDIR_MODEANU_CALLBACK_COLLECTOR MISSING_CALLBACK_ENVELOPE_PARSEDMISSING_CONTEXT_RECOVERED!MISSING_TERMINAL_STATE_CLASSIFIEDMISSING_NEXT_ACTION_DECIDED+MISSING_AUTO_OR_CHAIR_OR_NOOP_OR_BATCH_FLAGMISSING_CALLBACK_LEDGER_WRITTEN2RECEIVED_PHRASE_WITHOUT_INBOUND_SOURCE_ATTRIBUTION"SCHEDULE_HISTORY_LOOKUP_AS_INBOUNDMISSING_NEXT_ACTION_RESULT5STATE_STALE_OR_MISMATCH_WITHOUT_SAFE_DEGRADED_OR_HOLD%RESULT_FAILED_WITHOUT_RECOVERY_ACTION&TELEGRAM_OUTSIDE_CHAIR_REQUIRED_BRANCH)                        	   
   9b11c                     	 t         j                  j                         ri S t         j                  j                         } | j	                         si S t        j                  |       S # t        $ r i cY S w xY wN)sysstdinisattyreadstripjsonloads	Exception)raws    -hooks/stop_anu_callback_collector_verifier.py_read_stdinr6   P   s\    99Iiinnyy{Izz# 	s   A' /A' A' 'A54A5c                    t         j                  j                  t              }|rt	        |      S | xs  t         j                  j                  dd      }t	        |      t
        z  S )NANU_WORKSPACE_ROOTz/home/jay/workspace)osenvirongetLEDGER_PATH_ENVr   LEDGER_PATH_DEFAULT)workspace_rootexplicitroots      r5   _resolve_ledger_pathrA   \   sL    zz~~o.HH~XRZZ^^,@BWXD:+++    c                R   | j                         sy 	 | j                  d      j                         }d }t	        |      D ]F  }|j                         }|s	 t        j                  |      }||j                  d      |k(  sC|} |S  |S # t        $ r Y y w xY w# t        $ r Y ew xY w)Nzutf-8)encodingcallback_id)	is_file	read_text
splitlinesr3   reversedr0   r1   r2   r;   )ledger_pathrE   linesmatchedlineentrys         r5   _load_latest_ledger_entryrO   d   s     %%w%7BBD )-G 
zz|	JJt$E %))M":k"IGN
 N    		s#    B B	BB	B&%B&c                    t         j                  j                  t        d      j	                         j                         t        k(  ry| j                  d      du ryy)N Tcollector_modeF)r9   r:   r;   COLLECTOR_MODE_ENVr0   upperCOLLECTOR_MODE_VALUE)stdin_payloads    r5   _is_collector_sessionrW   z   sJ    	zz~~("-335;;=AUU)*d2rB   rQ   Tlast_output_textrR   c                  g }|sd|fS | 4|j                  t        d          |j                  t        d          d|fS | j                  d      s|j                  t        d          | j                  d      s|j                  t        d          | j                  d      s|j                  t        d	          | j                  d
      }|s|j                  t        d          | j                  d      | j                  d      | j                  d      | j                  d      f}t        d |D              s|j                  t        d          | j                  d      s|j                  t        d          | j                  d      }t	        j
                  ||      \  }}|r|j                  t        d          t	        j                  ||      r|j                  t        d          | j                  d      }	|	s|j                  t        d          |	t        j                  j                  k(  r)| j                  d      s|j                  t        d          | j                  d      }
|
dv r |t        vr|j                  t        d          t        |       }||j                  t        d          t        |      |fS )u6   10 + 2 추가 조건 검증. (block, failures) 반환.Fr#   r   Tenvelope_parsedcontext_recoveredr   terminal_state_classifiedr    next_action_decidedr!   auto_action_dispatchedchair_report_emittednoop_terminal_recordedbatch_wait_recordedc              3  2   K   | ]  }t        |        y wr+   )bool).0fs     r5   	<genexpr>zevaluate.<locals>.<genexpr>   s     -1tAw-s   r"   callback_ledger_writtensource_attributionr$   r%   next_action_resultr&   recovery_actionr(   state_freshness_status>   STALEMISSINGMISMATCHr'   r)   )appendCONDr;   anyr
   detect_received_misuse"detect_schedule_history_as_inboundr   FAILEDvaluer   r   rd   )ledger_entryrY   rR   failuresdecidedaction_flagssource_attrmisuse_resultstate_status	invariants               r5   evaluater      sd    HhQ Q X~ -.Q /0Q 78Q 45GQ  	12/012./	L ---Q 56Q ""#78K(??@PR]^IFAQ BBCSU`aQ 23FQ !((...|7G7GHY7ZT
###$<=L77//OODH%),7IT
#>8##rB   c                   | | n	t               }t        |      }|j                  d      xs t        j                  j                  d      }|j                  d      xs( t        j                  j                  t
        d      xs d}t               }|rt        ||      nd }t        |||      \  }}t        |t        |      ||d u||d}	|rd|	d<   d	d
j                  |      z   |	d<   |	S )NrE   ANU_CALLBACK_IDrY   rQ   rX   )schemarR   rJ   rE   ledger_entry_loadedrx   blockr   decisionu7   ANU_CALLBACK_COLLECTOR_CONTROL_PLANE Stop hook 차단: z, reason)r6   rW   r;   r9   r:   LAST_OUTPUT_ENVrA   rO   r   SCHEMAstrjoin)
rV   payload	collectorrE   rY   rJ   rN   r   rx   outs
             r5   runr      s    ,8mkmG%g.I++m,Q

?P0QK&' 	::>>/2.	 
 '(KCL%k;?RVEu7GXabOE8 #;'"$D0C !JEii!" 	H JrB   c                 T   	 t               } t        j
                  j	                  t        j                  | d             t        j
                  j                          | j                  d      ryy# t        $ r-}t        j                  j	                  d| d       Y d }~yd }~ww xY w)Nz.[stop_anu_callback_collector_verifier] error: 
r   F)ensure_asciir   r   )
r   r3   r,   stderrwritestdoutr1   dumpsflushr;   )r~   excs     r5   mainr      s     JJTZZU;<JJzz'  

I#bQRs   
A1 1	B':#B""B'__main__)returnDict[str, Any]r+   )r>   Optional[str]r   r   )rJ   r   rE   r   r   Optional[Dict[str, Any]])rV   r   r   rd   )rw   r   rY   r   rR   rd   r   zTuple[bool, List[str]])rV   r   r   r   )r   int),__doc__
__future__r   r1   r9   r,   pathlibr   typingr   r   r   r   r	   __file__resolveparent_HERE_REPOr   pathinsertutilsr
   !utils.callback_next_action_runnerr   r   r   r   r<   r=   r   rS   rU   rq   r6   rA   rO   rW   r   r   r   __name__
SystemExit rB   r5   <module>r      s:  : #  	 
  3 3 	X ''u:SXXHHOOAs5z" *  
9,< ($ / 
 *"*$4(;+#?
1
2 	,, 	D$*D$ D$ 	D$
 D$N>
 z
TV
 rB   