
     jU                       U 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Zddl	Z	ddl
mZ ddlmZmZ ddlmZ ddlmZ ddlmZmZmZ ej,                  ej.                  ej0                  ej2                  ej4                  ej6                  ej8                  d	Zd
ed<   ej,                  ej>                  ej.                  ej>                  ej0                  ej@                  ej2                  ej>                  ej4                  ej>                  ej6                  ej@                  ej8                  ej@                  iZ!ded<   ej,                  dej.                  dej0                  dej2                  dej4                  dej6                  dej8                  diZ"ded<   ej,                  dej.                  dej0                  dej2                  dej4                  dej6                  dej8                  diZ#ded<   ej,                  dd gej.                  d!d"gej0                  d#d$gej2                  d%d&gej4                  d'd(gej6                  d)d*gej8                  d+d,giZ$d-ed.<   ej,                  dej.                  d!ej0                  d#ej2                  d%ej4                  d'ej6                  d)ej8                  d+iZ%ded/<   	 	 	 	 	 	 	 	 dFd0Z&	 dGdd2	 	 	 	 	 	 	 	 	 	 	 	 	 dHd3Z'dId4Z(dJd5Z)	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dKd6Z*	 	 	 	 	 	 	 	 	 	 dLd7Z+dMd8Z,	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dNd9Z-da.d:d;	 	 	 	 	 dOd<Z/dPd=Z0d>d?d@d1dddA	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dQdBZ1dRdCZ2dSdDZ3e4dEk(  r e3        yy)Tuq   utils/critical_escalation_reporter.py — Critical 7종 에스컬레이션 라우터 및 회장 보고 포맷터.    )annotationsN)Callable)datetimetimezone)Path)Any)CriticalEscalationTypeEscalationPacket	RiskLevel)FORBIDDEN_PATH_INVASION/EFFECTIVE_DIFF_CONTAMINATION_REPLACEMENT_FAILEDGEMINI_REAL_BUG_SCOPE_EXPANSION.BLOCK_OVERRIDE_REQUIRED_OR_INSUFFICIENT_REASON(DEPENDENCY_CYCLE_OR_SERIAL_ONLY_CONFLICTREPLACEMENT_PR_ALSO_FAILEDPOST_MERGE_SMOKE_FAILUREz!dict[str, CriticalEscalationType]LEGACY_CRITICAL_MAPz'dict[CriticalEscalationType, RiskLevel]SEVERITY_MAPub   PR이 금지 경로(freeze 파일)를 침범했습니다. 자동 병합을 즉시 중단합니다.uL   오염된 diff에 대한 replacement PR 자동 생성이 실패했습니다.uZ   Gemini가 실제 버그를 감지했으며, 수정에 스코프 확장이 필요합니다.uG   블록 오버라이드가 필요하거나 사유가 불충분합니다.uI   의존성 사이클 또는 직렬 전용 충돌이 감지되었습니다.u%   Replacement PR이 실패했습니다.u1   병합 후 smoke 테스트가 실패했습니다.z!dict[CriticalEscalationType, str]_REASON_MAPuU   freeze 파일 침범은 자동 처리 불가. 회장 수동 확인 및 승인 필요.uV   replacement PR 생성 실패 시 자동 복구 로직이 없음. 수동 개입 필요.uW   스코프 확장 결정은 자동화 범위 초과. 회장 승인 없이 진행 불가.uH   블록 오버라이드는 회장만 승인 가능. 자동 처리 불가.uL   의존성 사이클 해소는 수동 재설계 필요. 자동 해결 불가.uQ   replacement PR도 실패한 경우 자동 재시도 불가. 수동 조사 필요.uA   smoke 실패 후 롤백/핫픽스 결정은 회장 승인 필요._WHY_AUTO_MAPu;   PR을 즉시 close하고 freeze 파일 제거 후 재제출u&   freeze 규칙 예외 승인 후 진행u7   원본 PR 보존 후 수동으로 replacement PR 생성u-   오염된 diff 제거 후 원본 PR 재제출u=   스코프 확장 승인 후 별도 태스크로 분리 처리u3   현재 PR 범위 내로 버그 수정 범위 제한u%   충분한 사유 보완 후 재제출u$   회장 수동 오버라이드 승인u(   의존성 순서 재설계 후 재제출u9   충돌하는 PR 중 하나를 먼저 병합 후 재시도u'   replacement PR 수동 생성 및 검토u   원본 PR 롤백 후 재시작u.   즉시 롤백(revert commit) 후 원인 분석u%   핫픽스 PR 생성 후 긴급 배포z'dict[CriticalEscalationType, list[str]]_SAFE_OPTIONS_MAP_RECOMMENDED_OPTION_MAPc                    dj                  t        |            }| j                  dz   |z   dz   |z   }t        j                  |j                               j                         S )u\   evidence_hash 생성: sha256(escalation_type.value + '|' + task_id + '|' + sorted_keys_csv).,|)joinsortedvaluehashlibsha256encode	hexdigest)escalation_typetask_idevidence_keyssorted_keys_csvraws        9/home/jay/workspace/utils/critical_escalation_reporter.py_make_evidence_hashr)   w   sT     hhvm45O


#
%
/#
5
GC>>#**,'1133      )nowc               j   |j                         syt        | ||      }|xs# t        j                  t        j
                        j                         }||z
  }	 |j                  d      j                         }	t        |	      D ]o  }
|
j                         }
|
s	 t        j                  |
      }	 t        j                  |d         j                         }||k  r y|j%                  d      |k(  so y y# t        $ r Y yw xY w# t        j                  $ r Y w xY w# t         t"        f$ r Y w xY w)u<   audit log에서 window_sec 이내 동일 hash 여부 확인.Futf-8encodingtsevidence_hashT)existsr)   r   r,   r   utc	timestamp	read_text
splitlinesOSErrorreversedstripjsonloadsJSONDecodeErrorfromisoformatKeyError
ValueErrorget)r#   r$   r%   audit_log_path
window_secr,   target_hashnow_ts	cutoff_tslineslinerecordrec_tss                r(   is_duplicaterK      s9      "%owNK/X\\(,,/::<F#I(('(:EEG  zz|	ZZ%F	++F4L9CCEF I  ::o&+5" )   ## 		 *% 		s6    C8 D2&D 8	DDDD D21D2c                    | dz  dz  dz  S )u"   글로벌 audit log 경로 반환.memoryzorchestration-auditzcritical-escalations.jsonl )workspace_roots    r(   _global_audit_pathrP      s    H$'<<?[[[r*   c                    | dz  dz  | dz  S )u"   per-task audit json 경로 반환.rM   eventsz.escalation.jsonrN   )rO   r$   s     r(   _per_task_pathrS      s    H$x/WI=M2NNNr*   c        	   
         | ||||||||d	S )u   audit record dict 생성.	r1   r$   	pr_numberr#   classificationseverityr2   sourcesuppressed_reasonrN   rU   s	            r(   _build_audit_recordr[      s)     *(&.
 
r*   c                `   t        |       }|j                  j                  dd       |j                  dd      5 }|j	                  t        j                  |d      dz          d	d	d	       t        | |      }|j                  j                  dd       t        ||       y	# 1 sw Y   ?xY w)
u4   글로벌 JSONL append + per-task JSON atomic write.T)parentsexist_okar.   r/   Fensure_ascii
N)	rP   parentmkdiropenwriter;   dumpsrS   _atomic_write_json)rO   rI   r$   packet_or_decisionglobal_pathfper_task_paths          r(   _append_audit_logrm      s     %^4KTD9			#		0 ?A	

66=>? #>7;Mtd;}&89? ?s   *B$$B-c                   | j                   }t        j                  d|ddd      5 }t        j                  ||dd       |j
                  }ddd       t        j                  t        |              y# 1 sw Y   )xY w)	u&   tempfile + os.replace로 atomic write.wFz.tmpr.   )modedirdeletesuffixr0      ra   indentN)	rc   tempfileNamedTemporaryFiler;   dumpnameosreplacestr)pathdatarc   tmptmp_paths        r(   rh   rh      sk    [[F		$	$fU6G
 			$%:88	
 JJxT# s   &A55A>c        	   
         ||j                   |xs |||j                   |d}	t        ||| t        |    t        |    t        |    t
        |    |	      S )u0   Critical escalation 시 EscalationPacket 생성.)merge_commitrX   
created_atrY   
risk_leveloriginal_evidence)r$   rV   r#   reasonwhy_auto_cannot_continuesafe_optionsrecommended_optionevidence)r   r
   r   r   r   r   )
r#   r$   rV   rX   rY   r   occurred_atr   now_isoenriched_evidences
             r(   _build_packetr      sf     %NN!,Wnn.) '?+!.!?&72?C"	 	r*   i   )max_lenc                  t         dz  a | j                  j                  d      xs d}|dk7  r|dd nd}| j                  j                  dd      }| j                  D cg c]  }|| j                  k7  s| }}dj                  d	 |D              }d
t          d| j                  j                   d| j                   d| j                   d| d| d| j                   d| j                   d| j                   d| d}t        j                  | j                  d      }	d}
|t        |      z
  t        |
      z
  dz
  }t        |	      |kD  r|	d| dz   }	||
z   |	z   }t        |      |kD  r|d| }|S c c}w )u9   회장 보고용 텍스트 포맷. 길이 max_len 보장.   r   zN/AN   rX   UNKNOWNrb   c              3  &   K   | ]	  }d |   yw)z  - NrN   ).0opts     r(   	<genexpr>z*format_packet_for_chair.<locals>.<genexpr>/  s     BSd3%LBs   u   🚨 [Critical-z] z
task: z / PR: #z / merge_commit: z
severity: z
why: z
auto cannot continue: u   
options:
  → [recommended] Fr`   z
evidence:    z...)_critical_counterr   rA   r   r   r   r#   r   r$   rV   r   r   r;   rg   len)packetr   r   	short_sharX   r   other_optionsother_linesheaderevidence_strevidence_prefixmax_evidenceresults                r(   format_packet_for_chairr     s    ??&&~6?%L$0E$9Ra uI"":y9H **cV5N5N.NM  ))BMBBK +,Bv/E/E/K/K.L M )9)9(::KI; WJ  !!'!@!@ A B%889-r	  ::fooEBL"OS[(3+??!CL
<<'#M\2U:o%4F
6{W!M7s   E04E0c                b    	 t        |       S # t        $ r Y nw xY wt        j                  |       S )uE   event_type → CriticalEscalationType. 실패 시 None(auto-handled).)r	   r@   r   rA   )
event_types    r(   _route_event_typer   N  s5    %j11 "":..s   
 	.TF)rO   dry_runno_auditdedup_window_secr,   telegram_sendc                  t        |      }|xs# t        j                  t        j                        }|j                         }	dD 
cg c]  }
| j                  |
      r|
 }}
|rt        d|       | d   }t        | d         }t        | d         }t        | j                  dd            }| j                  d      xs d	}| j                  d
      xs d	}t        | j                  d      xs i       }t        |      }|d	u}t        |j                               }|rt        |r|nt        j                   ||      n6t#        j$                  d| d| j'                               j)                         }|s4t+        |	|||dd	||d	      }|st-        |||d||	d       dd	d	d	d	| |ddS |J t.        |   }t1        |      }t3        ||||||      }|rld| d}t+        |	|||j4                  d|j4                  |||	      }|st-        |||d|j4                  |	d       d|j4                  |j4                  d	d	| ||dS t7        |||||||||		      }t9        |      }|s
| ||       t+        |	|||j4                  d|j4                  ||d		      }|s!t-        |||t;        j<                  |             d|j4                  |j4                  ||| |d	dS c c}
w )uc   이벤트를 수신해 Critical 라우팅, dedup, audit, 포맷을 처리하고 결과 dict 반환.)r$   rV   r   u   필수 필드 누락: r$   rV   r   rY   unknownr   Nr   r   zauto-handled|r   zauto-handledz,not in critical 7 enum (canonical or legacy)rU   )rW   r   r1   )rW   r#   rX   r   formatted_textaudit_appendedr2   suppression_reason)rC   r,   zduplicate within zs windowzduplicate-suppressed)rW   r#   r1   )	r#   r$   rV   rX   rY   r   r   r   r   critical)r   r   r,   r   r4   	isoformatrA   r@   intr}   dictr   listkeysr)   r	   FORBIDDEN_PATH_INTRUSIONr   r    r!   r"   r[   rm   r   rP   rK   r   r   r   dataclassesasdict)eventrO   r   r   r   r,   r   wsnow_dtr   rk   missingr$   rV   r   rY   r   r   r   	canonicalis_criticalr%   r2   audit_recordrX   rB   is_dup
dup_reasonr   r   s                                 r(   process_eventr   [  s{    
n	B.HLL.F G AUQ		RSqUGU1';<<#G{+,I%-.Jeii)45F$yy8@DL#ii6>$K(,UYYz-B-Hb(I 0A/LI4'K*//12M
 
	 (	$:$S$S "..
y*.557ik  *&)'L

 #1SZ[	 -#""*l*"P	
 		
    I&H'+N #F ()9(:(C
*%OO1^^'(

 #9iooelm	 5( ""*l*",	
 		
 !!+
F -V4N $.) '!!#
L v&		
 %$??NN(&,&"	 	[ Vs   KKc                t    t        |       }|j                  d      t        j                  |d         |d<   |S )uB   process_event 결과를 JSON 직렬화 가능한 형태로 변환.r   )r   rA   r   r   )r   outs     r(   _serialize_resultr     s7    
v,C
wwx$#**3x=9HJr*   c                    t        j                  d      } | j                  ddd       | j                  ddd	
       | j                  dt        dd       | j                  ddd       | j	                         }|j                  dddd       |j                  ddd       | j                         }t        |j                        }|j                         s3t        d| t        j                         t        j                  d       	 t        j                  |j                  d            }|j"                   }	 t%        |j&                  ||j(                  |j*                        }t        t        j.                  t1              d!d"#             t        j                  d$       y# t        j                   $ r=}t        d| t        j                         t        j                  d       Y d}~d}~ww xY w# t,        $ r=}t        d | t        j                         t        j                  d       Y d}~d}~ww xY w)%zCLI entrypoint.uB   Critical Escalation Reporter — Critical 7종 이벤트 라우터)descriptionz--event-fileTu   이벤트 JSON 파일 경로)requiredhelpz--workspace-rootr   u!   workspace root 경로 (기본: .))defaultr   z--dedup-windowr+   u   dedup 윈도우(초))typer   r   z
--no-audit
store_trueu   audit log 기록 skip)actionr   z	--dry-runu   dry-run 모드 (기본))r   r   r   z--applyu   실제 telegram 발송zERROR: event file not found: )filer   r.   r/   z#ERROR: invalid JSON in event file: N)rO   r   r   r   zERROR: validation failed: Frt   ru   r   )argparseArgumentParseradd_argumentr   add_mutually_exclusive_group
parse_argsr   
event_filer3   printsysstderrexitr;   r<   r6   r=   applyr   rO   r   dedup_windowr@   rg   r   )parser
mode_groupargs
event_pathr   excr   r   s           r(   mainr     s   $$XF <Z[
*C>ab
(sDG]^
\@WX446JKdQjkIlAYZDdoo&J-j\:L

:///AB
 **nG
..]]!..
 
$**&v.U1
MNHHQK'  3C59

K  *3%0szzBs0   %F/ .H /G?3G::G?	I3II__main__)r#   r	   r$   r}   r%   	list[str]returnr}   )r+   )r#   r	   r$   r}   r%   r   rB   r   rC   r   r,   datetime | Noner   bool)rO   r   r   r   )rO   r   r$   r}   r   r   )r1   r}   r$   r}   rV   r   r#   r}   rW   r}   rX   
str | Noner2   r}   rY   r}   rZ   r   r   dict[str, Any])
rO   r   rI   r   r$   r}   ri   r   r   None)r~   r   r   r   r   r   )r#   r	   r$   r}   rV   r   rX   r   rY   r}   r   r   r   r   r   r   r   r}   r   r
   )r   r
   r   r   r   r}   )r   r}   r   zCriticalEscalationType | None)r   r   rO   z
Path | strr   r   r   r   r   r   r,   r   r   zCallable[[str], None] | Noner   r   )r   r   r   r   )r   r   )5__doc__
__future__r   r   r   r   r;   r{   r   rw   collections.abcr   r   r   pathlibr   typingr   utils.automation_contractsr	   r
   r   r   9REPLACEMENT_PR_AUTO_CREATION_FAILED_FOR_CONTAMINATED_DIFF(GEMINI_REAL_BUG_REQUIRES_SCOPE_EXPANSION.BLOCK_OVERRIDE_REQUIRED_OR_REASON_INSUFFICIENT)DEPENDENCY_CYCLE_OR_SERIAL_ONLY_COLLISIONREPLACEMENT_PR_FAILEDPOST_MERGE_SMOKE_FAILEDr   __annotations__	HIGH_COREHIGHr   r   r   r   r   r)   rK   rP   rS   r[   rm   rh   r   r   r   r   r   r   r   __name__rN   r*   r(   <module>r      sw   w "     	 
  $ '     6NN7M  8H  8H'='f'f6L6{6{0F0p0p"8"N"N 6 N N: 6  33Y5H5HTTV_ViViCCY^^II9K^K^DDiFYFY00)..22INN95  33  6ZTT  WeCC  FbII  LUDD  GR002Y224g2.  33  6MTT  WoCC  F_II  LVDD  GU00  3F224w40  33E06 TTA7W CCG=F II/.L DD2CG 001(3 228/53> : @ 335rTT  WPCC  FEIIKrDDFp002[224d> : 4+44 4 		4  '  '+'' ' 	'
 ' 
' 
'\\
O
  	
      " 4::: : '	:
 
:$$+  	
     &  N   (( ( 		(^/  "% 26ff f 	f
 f f 
f 0f fZ*Z zF r*   