
    j)G                       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m	Z	 ed   Z
 G d de      Z G d d	e      Zd$d
Zd%dZd%dZd%dZg dZg 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edk(  r eej>                        dk  r& e dejB                          ejD                  d       ej>                  d   Z# e$e#dd !      5 Z% ejL                  e%      Z'ddd        ee'      Z( ee(      Z) e  ejT                  e)jW                         d"d#             yy# 1 sw Y   DxY w).u   
codex_review_loop_decider.py
task-2711 — ANU_CODEX_REVIEW_LOOP_DECIDER
chair_authorization_id: CHAIR-AUTH-TASK-2711-ANU-CODEX-REVIEW-LOOP-DECIDER-260530

Python ≥3.9 호환. 표준 라이브러리만 사용.
    )annotationsN)Literal
NamedTupleOptional)AUTO_REVISION_CONTINUECHAIR_DECISION_REQUIRED
LOCK_READYPILOT_READY_BUT_NEEDS_CHAIRCRITICAL_ESCALATIONc                      e Zd ZU ded<   ded<   ded<   ded<   ded<   ded	<   d
ed<   ded<   ded<   dZded<   dZded<   y)CodexReviewInputstrtask_idintversionround_numberoverall_verdictpilot_readinessdictaxis_countslistremaining_recommendationsboollocked_statuschair_authorization_idF"chair_minor_doc_cleanup_authorizedNOptional[list]prior_rounds_history)__name__
__module____qualname____annotations__r   r        </home/jay/workspace/scripts/anu/codex_review_loop_decider.pyr   r      sL    LL##/4&4+/./r$   r   c                  J    e Zd ZU ded<   ded<   ded<   ded<   ded<   ded	<   y
)DecisionResultDecisionEnumdecisionr   	rationalenext_actionr   risk_triggers_matchedchair_facing_summaryaudit_marker_pathN)r   r    r!   r"   r#   r$   r%   r'   r'   *   s%    Nr$   r'   c                   dj                  d | D              }g }|D ]S  }|j                         r0|j                         r |j                  |j	                                C|j                  |       U dj                  |      S )ud   remaining_recommendations 의 모든 문자열을 합쳐 영문만 소문자 정규화한 텍스트. c              3  2   K   | ]  }t        |        y wNr   .0rs     r%   	<genexpr>z_make_blob.<locals>.<genexpr>9   s     0c!f0    )joinisasciiisalphaappendlower)	remainingjoinedresultchs       r%   
_make_blobrC   7   si    XX0i00FF ::<BJJLMM"((*%MM"	
 776?r$   c                4     g d}t         fd|D              S )u%   Critical 7 doctrine 키워드 매칭.)z
critical 7chair_requiredcritical_escalationfeedback_criticalc              3  &   K   | ]  }|v  
 y wr2   r#   r5   kwblobs     r%   r7   z"_check_trigger1.<locals>.<genexpr>L        -brTz-   anyrK   keywordss   ` r%   _check_trigger1rR   D       H -H---r$   c                4     g d}t         fd|D              S )u+   실제 dispatch/PR/push/merge/GitHub write.)
zdispatch.pybot_settingsu   실제 dispatchz pr zpr/pushzpull requestpushmergezgithub writezgit pushc              3  &   K   | ]  }|v  
 y wr2   r#   rI   s     r%   r7   z"_check_trigger4.<locals>.<genexpr>]   rL   rM   rN   rP   s   ` r%   _check_trigger4rY   O   s    H -H---r$   c                J     g d}t         fd|D              ryd v rd v ryy)u   immutable scope edit 요구.)zfinish-task.shztask-scope-guardzsession-watchdog	qc_verifymerge_queue_executorreal_merge_hooksanu_v3zimmutable scopec              3  &   K   | ]  }|v  
 y wr2   r#   rI   s     r%   r7   z"_check_trigger5.<locals>.<genexpr>m   s     
0"2:
0rM   Tallowed_existing_file_edits	immutableFrN   )rK   immutable_filess   ` r%   _check_trigger5rc   `   s2    	O 
0
00$,1Dr$   )markerevidencerecorded_atz	task-2706z	task-2707z	task-2708z	task-2709z	task-2710)
reclassify	overwriteu   덮어u	   재분류c                j   | D ]  }g }t        |      D ]S  }|j                         r0|j                         r |j                  |j	                                C|j                  |       U dj                  |      t        fdt        D              }t        fdt        D              }|s|s y y)u  기존 evidence overwrite/reclassify 시도.

    remaining 문자열 중 하나가 evidence-reference 토큰과
    mutation 동사(reclassify/overwrite/덮어/재분류)를 동시에 포함할 때만 trigger.
    '정정'이나 '변경' 단독은 trigger 안 됨.
    r9   c              3  &   K   | ]  }|v  
 y wr2   r#   )r5   tokitem_normalizeds     r%   r7   z"_check_trigger6.<locals>.<genexpr>   s     Nc3/1NrM   c              3  &   K   | ]  }|v  
 y wr2   r#   )r5   verbrl   s     r%   r7   z"_check_trigger6.<locals>.<genexpr>   s     Ot4?2OrM   TF)	r   r;   r<   r=   r>   r:   rO   _EVIDENCE_TOKENS_MUTATION_VERBS)r?   item
item_charsrB   has_evidencehas_mutationrl   s         @r%   _check_trigger6ru      s      
d) 	&Bzz|

!!"((*-!!"%		&
 ''*-N=MNNOOOL r$   c                4     g d}t         fd|D              S )u   권한 확대 요구.)znew allowed_pathu   allowed_path 추가u   권한 확대u   권한확대znew chair_authzchair_authorization scopec              3  &   K   | ]  }|v  
 y wr2   r#   rI   s     r%   r7   z"_check_trigger2.<locals>.<genexpr>   rL   rM   rN   rP   s   ` r%   _check_trigger2rx      s    H -H---r$   c                4     g d}t         fd|D              S )u   forbidden target 변경 요구.)	forbiddenu   §11.3forbidden_pathszforbidden targetc              3  &   K   | ]  }|v  
 y wr2   r#   rI   s     r%   r7   z"_check_trigger3.<locals>.<genexpr>   rL   rM   rN   rP   s   ` r%   _check_trigger3r}      rS   r$   c                (   g }| D ]S  }|j                         r0|j                         r |j                  |j                                C|j                  |       U dj	                  |      }t        d t        j                  d|      D              }|S )u=   텍스트를 정규화하여 길이≥2 토큰 집합 반환.r9   c              3  >   K   | ]  }t        |      d k\  s|  yw)   N)len)r5   ts     r%   r7   z$_normalize_tokens.<locals>.<genexpr>   s     TqARSTs   u   [\s,./·★\-]+)r;   r<   r=   r>   r:   setresplit)textrA   rB   
normalizedtokenss        r%   _normalize_tokensr      sw     F ::<BJJLMM"((*%MM"	
 JTBHH%7DTTFMr$   c                   |rt        |      dk  ry|dd }dj                  d | D              }t        |      }|syg }|D ];  }|j                  dg       }|j	                  dj                  d |D                     = |j	                  |       d	}|D ]&  }	t        |	      }
||
z  }t        |      d
k\  s"|d
z  }( |dk\  S )u   §5.4 동일 blocker 3회 반복 검사.

    현재(N) + 직전 2개 round(N-1, N-2) 중 ≥2/3 round에서
    현재 remaining 핵심 토큰이 동일하게 등장하면 True.
    r   FNr0   c              3  2   K   | ]  }t        |        y wr2   r3   r4   s     r%   r7   z/_check_same_blocker_3_rounds.<locals>.<genexpr>   s     FqCFFr8   r?   c              3  2   K   | ]  }t        |        y wr2   r3   r4   s     r%   r7   z/_check_same_blocker_3_rounds.<locals>.<genexpr>   s     #AqCF#Ar8   r      )r   r:   r   getr=   )r   r   recent_priorscurrent_textcurrent_tokensround_textsprpr_remainingmatch_countrt	rt_tokensoverlaps               r%   _check_same_blocker_3_roundsr      s      3';#<q#@ )-M88F,EFFL&|4N K Cvvk2.388#AL#AABC |$
 K %b)	 9,w<11K !r$   c                    |sy| j                  d      }|sy|d   }|j                  di       }|j                  d      }|syt        |      }t        |      }t        ||z        S )u   §5.4 FAIL 2회 같은 axis 반복 검사.

    현재 axis_counts.fail_axes와 prior_rounds_history 최근 1개(N-1)
    axis_counts.fail_axes에 공통 axis 존재 시 True.
    F	fail_axesr   )r   r   r   )r   r   current_fail_axes
prev_roundprev_axis_countsprev_fail_axescurrent_setprev_sets           r%   _check_fail_2_same_axisr      sy      #4 &b)J!~~mR8%))+6N '(K>"Hh&''r$   c                    |sy|d   }|j                  di       }|j                  dg       }dd} ||        ||      k7  ryt        |      t        |      k\  S )uZ   §5.4 stagnation: 현재 axis 분포 == 직전 round axis 분포 AND remaining ≥ 직전.Fr   r   r?   c                b    | j                         D ci c]  \  }}|dk7  s|| c}}S c c}}w )Nr   )items)ackvs      r%   _counts_onlyz'_check_stagnation.<locals>._counts_only!  s+    !#@AqK/?1@@@s   ++)r   r   returnr   )r   r   )r   r   r   r   r   prev_remainingr   s          r%   _check_stagnationr     si      %b)J!~~mR8^^K4NA K L1A$BB()S-@@@r$   c                    d|  d| dS )Nzmemory/events/z.codex-review-decision-rz.jsonr#   )r   r   s     r%   _audit_marker_pathr   .  s    G9$<\N%PPr$   c           	     $   t        | j                        }t        | j                  | j                        }g }t        |      r|j                  d       t        |      r|j                  d       t        |      r|j                  d       t        | j                        r|j                  d       |rSd| j                   d| j                   d| d| j                   g}t        d	d
| dd|dj                  |      |      S g }d}t        |      r|j                  d       t        |      r|j                  d       g }| j                  dkD  r|j                  d| j                   d       t        | j                  | j                        r|j                  d       t!        | j"                  | j                        r|j                  d       t%        | j"                  | j                  | j                        r|j                  d       |s|r|rdj                  |      }g }|r|j                  d| d       |r|j                  d|        d| j                   d| j                   g}|r|j                  d|        |r|j                  d|        |j                  d| j                          t        ddj                  |      d z   d!|dj                  |      |      S | j&                  d"v rt)        | j                        d#k(  ru| j*                  d$u rgd%| j                   d&| j,                   d| j                   d'| j&                   d(g}t        d)d'| j&                   d*d+g dj                  |      |      S | j.                  d,v rh| j0                  d$u rZd-| j                   d| j                   d.| j.                   d/g}t        d0d.| j.                   d1d2g dj                  |      |      S t        d3d4d5g d|      S )6ui  회장 verbatim 5 enum + risk gating + loop boundary.

    5-step precedence (위에서부터 평가, 첫 매치 반환):
      Step 1: CRITICAL_ESCALATION (trigger 1,4,5,6)
      Step 2: CHAIR_DECISION_REQUIRED (trigger 2,3 + §5.4 boundary)
      Step 3: LOCK_READY
      Step 4: PILOT_READY_BUT_NEEDS_CHAIR
      Step 5: AUTO_REVISION_CONTINUE (default)
    r            z[CRITICAL_ESCALATION] task_id=z round=u   트리거: zremaining: r   u   §4.3 risk trigger ut    매칭으로 CRITICAL_ESCALATION 결정. ANU auto loop 즉시 중단하고 회장에 즉시 보고해야 합니다.u2   ANU auto loop 즉시 중단 + 회장 즉시 보고
)r)   r*   r+   r,   r-   r.   r9   r         u   max round 초과 (round_number=z > 7)u$   동일 blocker 3회 반복 (§5.4.1)u&   FAIL 2회 같은 axis 반복 (§5.4.2)u5   stagnation (axis 분포 동일 + remaining 미감소)z; u   §4.3 trigger u    매칭u   §5.4 loop boundary 위반: z"[CHAIR_DECISION_REQUIRED] task_id=u   경계 위반: r   z + uM   으로 CHAIR_DECISION_REQUIRED 결정. ANU 회장 보고 후 verbatim 대기.u#   ANU 회장 보고 + verbatim 대기)PASSPASS_WITH_RECOMMENDATIONSr   Fz[LOCK_READY] task_id=z	 version=zoverall_verdict=z", remaining=0, locked_status=Falser	   ux   , remaining_recommendations가 비어 있고, locked_status=False이므로 LOCK_READY 결정. 회장 lock 인가 대기.u&   ANU 회장 보고 + lock 인가 대기)READYREADY_WITH_RECOMMENDATIONSz&[PILOT_READY_BUT_NEEDS_CHAIR] task_id=zpilot_readiness=z*, chair_minor_doc_cleanup_authorized=Falser
   ux   이나 chair_minor_doc_cleanup_authorized=False이므로 PILOT_READY_BUT_NEEDS_CHAIR 결정. 회장 pilot 인가 대기.ue   ANU 회장 보고 + pilot 별도 결정 대기 (신규 fresh task ID + 별도 chair_authorization_id)r   ut   CRITICAL/CHAIR/LOCK_READY/PILOT 조건 미충족. minor refinement only → ANU 자동 v+1 revision drafting 진행.uH   ANU 자동 v+1 revision drafting + Codex round+1 재요청 (silent loop))rC   r   r   r   r   rR   r=   rY   rc   ru   r'   r:   rx   r}   r   r   r   r   r   r   r   r   r   r   r   )	inputrK   amp	triggeredsummary_lineschair_triggerschair_boundary_reasonboundary_violationsrationale_partss	            r%   decider   6  s    e556D
U]]E,>,>
?C
 Itttu667,U]]O75CUCUBVW)%%99:;

 *%i[ 1] ] M"+!%=!9!

 
	
 Nta ta   A""%DUEWEWDXX]#^_ $'')C)C 	""#IJ u00%2L2LM""#KL 5::E<V<V 	""#Z[,$(II.A$B!""^N3C7#KL""%ABWAX#YZ 1wuGYGYFZ[
   ;~.>!?@  ?3F2G!HI{5+J+J*KLM.

?+_` >"0!%=!9!

 
	
  	!FF//0A55( $EMM?)EMM?'RWRdRdQefu4455WX
 !"5#8#8"9 :] ] A"$!%=!9!

 
	
  	!HH44= 5U]]O75K]K]J^_u4455_`
 2"5#8#8"9 :. .
I #%!%=!9!
 	
& )Q _ 
 
r$   c                    t        | d   | d   | d   | d   | d   | d   | d   | d   | d	   | j                  d
d      | j                  dd            S )uz   dict(예: fixture JSON 로드 결과)를 CodexReviewInput으로 변환.
    누락 옵션 필드는 기본값 사용.
    r   r   r   r   r   r   r   r   r   r   Fr   N)r   r   r   r   r   r   r   r   r   r   r   )r   r   )ds    r%   	from_dictr     sz     ))~&+,+,m$"#$?"@( !9:+,551UW\+]UU#94@ r$   __main__r   z:Usage: python3 codex_review_loop_decider.py <fixture.json>)filer   r6   zutf-8)encodingF)ensure_asciiindent)r?   r   r   r   )rK   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'   )r   r   r   r   ),__doc__
__future__r   jsonr   systypingr   r   r   r(   r   r'   rC   rR   rY   rc   ro   rp   ru   rx   r}   r   r   r   r   r   r   r   r   r   argvprintstderrexitfixture_pathopenfloaddatainprA   dumps_asdictr#   r$   r%   <module>r      s   #  	 
 0 0 0z 0Z 
..",	 2
..)#)() 
)X(((( 
(<AA#A )A 
	A6Qmh. z
388}qJQTQ[Q[\88A;L	lC'	2 atyy| D/CC[F	*$**V^^%E!
DE  s   (D>>E