
     ja              	         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 ddlm	Z	 ddl
Z
 e	e      j                         j                  j                  j                  Z ee      Zeej"                  v rej"                  j%                  e       ej"                  j'                  de       ddlmZmZmZ ddlmZmZmZmZmZ eD  cg c]  } | j<                   c} Z edd	d
dddej@                        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,d"dZ-d"dZ.d"dZ/d"dZ0d"dZ1d"dZ2yc c} w )$u  
회귀 테스트 — utils/critical_escalation_reporter (task-2513)

12건 필수 + 2건 보너스 (총 14건):
  - Critical 7 exact match (test_01)
  - Non-critical suppression (test_02)
  - Duplicate suppression (test_03)
  - EscalationPacket JSON round-trip (test_04)
  - Severity mapping (test_05)
  - format_packet_for_chair 4096자 제한 (test_06)
  - Audit JSONL 생성 검증 (test_07)
  - 회장 §9 critical fixture 6개 replay (test_08)
  - 회장 §10 auto-handled fixture 5개 replay (test_09)
  - FORBIDDEN_PATH_INTRUSION HIGH_CORE audit (test_10)
  - POST_MERGE_SMOKE_FAILED audit append (test_11)
  - STYLE_ONLY_GEMINI auto-handled audit (test_12)
  - Legacy 호환 7개 canonical 매핑 (test_13 - 보너스 G1)
  - Audit JSONL 다건 파싱 검증 (test_14 - 보너스)
    )annotationsN)datetimetimezone)Path)CriticalEscalationTypeEscalationPacket	RiskLevel)LEGACY_CRITICAL_MAPSEVERITY_MAPformat_packet_for_chairis_duplicateprocess_eventi     	      )tzinfoc                    ||| d|xs i dS )u.   최소 필드를 갖춘 이벤트 dict 생성.z
test-suite)task_id	pr_number
event_typesourceevidence )r   r   r   r   s       N/home/jay/workspace/tests/regression/test_critical_escalation_reporter_2513.py_make_eventr   =   s!      N     c                    | dz  dz  dz  S )Nmemoryorchestration-auditcritical-escalations.jsonlr   )workspace_roots    r   _global_audit_pathr"   M   s    H$'<<?[[[r   c                .   t        |       }|j                         sg S |j                  d      j                         D cg c]#  }|j	                         s|j	                         % }}|D cg c]  }t        j                  |       c}S c c}w c c}w )Nutf-8encoding)r"   exists	read_text
splitlinesstripjsonloads)r!   plnliness       r   _read_audit_linesr0   Q   su    >*A88:	"#++w+"?"J"J"L[BPRPXPXPZRXXZ[E[%*+rDJJrN++ \+s    BB.Bc                   t         D ]  }t        t        |      | |z  dt              }|d   dk(  sJ | d|d          |d   |k(  sJ | d|d|d          |d	   
J | d       |d   
J | d       |d   wJ | d        y
)u   7개 CriticalEscalationType 값을 event_type으로 입력하면 모두 classification=='critical'이고
    escalation_type 이 enum value와 정확히 매칭되어야 한다.Tr!   dry_runnowclassificationcriticalz+: classification should be 'critical', got escalation_typez%: escalation_type mismatch. expected=, got=packetNz: packet should not be Noneformatted_text#: formatted_text should not be Nonesuppression_reasonz0: suppression_reason should be None for critical)_CRITICAL_7r   r   _NOW)tmp_pathetyperesults      r   "test_01_critical_seven_exact_matchrB   ]   s     
#e+	
 &':5 	
g@HXAY@\]	
5 '(E1 	
g:5)6&QbJcIfg	
1 h+Rw6Q-RR+&'3bw>a5bb3*+3 	
gEF	
3
r   c                    g d}|D ]t  }t        t        |      | |z  dt              }|d   dk(  sJ | d|d          |d   
J | d	       |d
   
J | d       |d   s
J | d       |d   lJ | d        y)u   Critical 7 외 이벤트는 classification=='auto-handled', packet/formatted_text is None,
    suppression_reason이 비어있지 않아야 한다.)GEMINI_COMPLETEDAUTO_MERGE_SUCCESSRANDOM_UNKNOWN_EVENTSTYLE_ONLY_GEMINIFALSE_POSITIVE_GEMINITr2   r5   auto-handledz: expected 'auto-handled', got r9   Nz: packet should be Noner:   z: formatted_text should be Noner<   z(: suppression_reason should not be emptyr7   z : escalation_type should be Noner   r   r>   )r?   non_critical_typesr@   rA   s       r    test_02_non_critical_suppressionrL   x   s     $ ]#e+	
 &'>9 	
g4V<L5M4PQ	
9 h'JE72I)JJ'&'/ZE7:Y1ZZ/*+_w6^-__+'(0\UG;[2\\0]r   c                   | dz  }d}ddi}t        ||      }t        ||dt              }|d   d	k(  sJ d
|d          t        ||dt              }|d   dk(  sJ d|d          |d   sJ d       t        |      }t	        |      dk(  sJ dt	        |              |d   d   d	k(  sJ d       |d   d   dk(  sJ d       |dz  dz  dz  }t        t        j                  |d   t        |j                               |dt              sJ d       t        t        j                  dt        |j                               |dt              rJ d       y)u   동일 (escalation_type, task_id, evidence_keys) 이벤트를 2회 처리하면
    첫 번째는 'critical', 두 번째는 'duplicate-suppressed' 여야 한다.
    audit JSONL 라인이 2개 생성되어야 한다.zdedup-wsFORBIDDEN_PATH_INTRUSIONfilezutils/automation_contracts.pyr   Tr2   r5   r6   z#1st call should be 'critical', got zduplicate-suppressedz/2nd call should be 'duplicate-suppressed', got r<   z3suppression_reason should not be empty on duplicate   zExpected 2 audit lines, got r   z1st line should be 'critical'   z)2nd line should be 'duplicate-suppressed'r   r   r    r   i  )
window_secr4   z>is_duplicate must report True for repeated event within windowz	task-9999z4is_duplicate must report False for different task_idN)
r   r   r>   r0   lenr   r   rN   listkeys)	r?   wsr@   r   eventresult1result2r/   	audit_logs	            r   test_03_duplicate_suppressionr\      s    
J	B&E78H1EE"dMG#$
2 
-g6F.G-JK2 E"dMG#$(>> 
9'BR:S9VW> '(_*__(b!Eu:?G:3u:,GG?8$%3T5TT38$%)??lAll? X 558TTI77iX]]_ H HH  77X]]_ > >>  r   c                 b   t        ddt        j                  ddddgdddd	
      } t        j                  |       }t        j                  |d      }t        j                  |      }|d   | j                  k(  sJ d       |d   | j                  k(  sJ d       |d   | j                  j                  k(  sJ d       |d   | j                  k(  sJ d       |d   | j                  k(  sJ |d   | j                  k(  sJ d       |d   | j                  k(  sJ |d   | j                   k(  sJ d       y)ur   EscalationPacket을 dataclasses.asdict → json.dumps → json.loads 후
    모든 필드가 동일해야 한다.	task-2513*   zsmoke test failedzmanual intervention requiredrollbackhotfixabc123smoke)committest)r   r   r7   reasonwhy_auto_cannot_continuesafe_optionsrecommended_optionr   F)ensure_asciir   ztask_id mismatchr   zpr_number mismatchr7   zescalation_type mismatchrf   zreason mismatchrg   rh   zsafe_options mismatchri   r   zevidence mismatchN)r   r   POST_MERGE_SMOKE_FAILEDdataclassesasdictr+   dumpsr,   r   r   r7   valuerf   rg   rh   ri   r   )r9   as_dict
serializedrestoreds       r   test_04_packet_json_round_triprs      sU    .FF"!? (+%$g6	F   (GG%8Jzz*%HI&..0D2DD0K F$4$44J6JJ4%&&*@*@*F*FFbHbbFH.A0AA../63R3RRRRN#v':'::S<SS:()V-F-FFFFJ6??2G4GG2r   c                    t        t              dk(  sJ dt        t                      t        j                         D ]X  \  } }t        | t              sJ d| d       |t
        j                  t
        j                  fv rDJ | j                   d|        t        j                  t        j                  t        j                  t        j                  h}|D ]9  }t        |   t
        j                  k(  rJ |j                   dt        |           t        j                  t        j                  t        j                  h}|D ]9  }t        |   t
        j                  k(  rJ |j                   dt        |           y)	ua   SEVERITY_MAP의 모든 7개 매핑이 RiskLevel.HIGH 또는 RiskLevel.HIGH_CORE 이어야 한다.   z(Expected 7 entries in SEVERITY_MAP, got zKey z is not CriticalEscalationTypez,: severity should be HIGH or HIGH_CORE, got z should be HIGH_CORE, got z should be HIGH, got N)rT   r   items
isinstancer   r	   HIGH	HIGH_COREro   rN   9REPLACEMENT_PR_AUTO_CREATION_FAILED_FOR_CONTAMINATED_DIFF.BLOCK_OVERRIDE_REQUIRED_OR_REASON_INSUFFICIENT)DEPENDENCY_CYCLE_OR_SERIAL_ONLY_COLLISION(GEMINI_REAL_BUG_REQUIRES_SCOPE_EXPANSIONREPLACEMENT_PR_FAILEDrk   )r7   
risk_levelhigh_core_expectedethigh_expecteds        r   test_05_severity_mappingr      s   |!a%McR^N_M`#aa!'3'9'9'; 
#/+AB 	
?%%CD	
B inni.A.ABB 	
$$%%QR\Q_`	
B	
 	77XXMMHH	 ! 
B9#6#66 	
xxj2<3C2FG	
6
 	GG4466M
  
B9>>1 	
xxj-l2.>-AB	
1
r   c                   ddz  }t         D ]  }t        t        |j                  d|i      | |j                  z  dt              }|d   dk(  sJ |j                   d	       |d
   }|J |j                   d       t        |      dk  s J |j                   dt        |       d       |d   }|J t        |d      }t        |      dk  rJ |j                   dt        |       d        y)u   모든 7개 critical type에 대해 evidence를 50KB로 채워도
    format_packet_for_chair 결과가 4096자 이하여야 한다.XiP  	large_keyrP   Tr2   r5   r6   z: should be criticalr:   Nr;   i   z: formatted_text length z exceeds 4096r9   i   )max_lenz7: direct format_packet_for_chair(max_len=512) returned z chars)r   r   r   ro   r>   rT   r   )r?   large_evidence_strr@   rA   	formattedr9   directs          r   test_06_format_within_4096r     s*    v' 
{<N.OP#ekk1	
 &':5[%++FZ7[[5+,	$Y5X&YY$9~% 	
{{m3C	N3C=Q	
%
 !!!!(=6{c! 	
{{mRSVW]S^R__ef	
!%
r   c                   | dz  }d}d}t        t        ||      |dt               t        |      }|j	                         sJ d       |j                  d	      j                         D cg c]#  }|j                         s|j                         % }}t        |      d
k(  sJ dt        |              t        j                  |d         }dD ]  }||v rJ d|        |d   |k(  sJ |d   |k(  sJ |d   dk(  sJ |dz  dz  | dz  }	|	j	                         sJ d       t        j                  |	j                  d	            }
t        |
t              sJ d       yc c}w )u   Critical 1건 처리 후:
    - audit JSONL 파일에 라인 1개 존재
    - json.loads 성공
    - ts/task_id/escalation_type/classification/evidence_hash 키 존재
    - per-task 파일도 생성
    zaudit-wsr^   r|   r   Tr2   z$Global audit JSONL file should existr$   r%   rR   zExpected 1 audit line, got r   )tsr   r7   r5   evidence_hashzAudit record missing key: r   r7   r5   r6   r   eventsz.escalation.jsonz*Per-task escalation JSON file should existz*Per-task file should contain a JSON objectN)r   r   r>   r"   r'   r(   r)   r*   rT   r+   r,   rw   dict)r?   rW   r   r@   global_pathr.   r/   recordrequired_keyper_task_pathper_task_datas              r   test_07_audit_jsonl_generationr   /  s    
J	BG7EE7+	 %R(KG!GG"-"7"7"7"I"T"T"VeBZ\ZbZbZdRXXZeEeu:?F9#e*FF?ZZa!F_ Uv%T)CLCS'TT%U )'''#$---"#z111 MH,':J/KKM!O#OO!JJ}666HIMmT*X,XX* fs   ,E$E$c           
     8   g d}|D ]  \  }}}}| d| z  }t        t        |d|dd        |dt              }|d	   d
k(  sJ d| d|d	          |d   |k(  sJ d| d|d|d          |d   |k(  sJ d| d|d|d          |d   J d| d        y)uW   회장 §9 6개 critical fixture 모두 process_event → classification == 'critical'.))zforbidden pathrN   rN   ry   )zreplacement failurerz   rz   ry   )zscope expansionr}   r}   rx   )zdependency cycler|   r|   ry   )zsmoke failurerk   rk   rx   )zBLOCK override insufficientr{   r{   ry   zfixture-ztask-08-N
   r   Tr2   r5   r6   u   [§9 +] classification should be 'critical', got r7   z%] escalation_type mismatch: expected=r8   severityz] severity mismatch: expected=r9   ] packet should not be NonerJ   )r?   fixturesdescr@   expected_etypeexpected_severityrW   rA   s           r    test_08_replay_critical_fixturesr   [  s6   &HP ;C W6e^%6(5'**%*'>?	
 &':5 	
D6DVL\E]D`a	
5 '(N: 	
D6>~>PPVW]^oWpVst	
: j!%66 	
D678I7LFSYZdSeRhi	
6 h+VuTF:U-VV+#Wr   c           
        g d}|D ]y  \  }}| d| z  }t        t        |d|dd        |dt              }|d	   d
k(  sJ d| d|d	          |d   J d| d       |d   J d| d       |d   rpJ d| d        y)u[   회장 §10 5개 auto-handled fixture → classification == 'auto-handled', packet is None.))zstyle-only GeminirG   )zfalse-positive GeminirH   )zoutdated threadOUTDATED_THREAD)zclean replacement PRCLEAN_REPLACEMENT_PR_CREATED)zdependency satisfiedDEPENDENCY_SATISFIEDzauto-ztask-09-Nr   r   Tr2   r5   rI   u   [§10 z/] classification should be 'auto-handled', got r9   z] packet should be Noner:   z] formatted_text should be Noner<   z(] suppression_reason should not be emptyrJ   )r?   r   r   r@   rW   rA   s         r   $test_09_replay_auto_handled_fixturesr     s    H   ee%w'%*'>?	
 &'>9 	
TFI&QaJbIef	
9 h'O6$7N)OO'&'/_6$?^1__/*+dvdV;c-dd+er   c                   | dz  }t        t        dd      |dt              }|d   dk(  sJ d	|d          t        |      }t	        |      d
k\  sJ d       |d   }|d   dk(  sJ d|d          |d   dk(  sJ d|d          y)u   FORBIDDEN_PATH_INTRUSION 이벤트 처리 후:
    - severity == 'HIGH_CORE'
    - audit 라인의 escalation_type == 'FORBIDDEN_PATH_INTRUSION'
    zfpi-wsrN   ztask-10r   Tr2   r   ry   z$severity should be 'HIGH_CORE', got rR   Expected at least 1 audit liner7   z@audit escalation_type should be 'FORBIDDEN_PATH_INTRUSION', got z*audit severity should be 'HIGH_CORE', got Nr   r   r>   r0   rT   r?   rW   rA   r/   r   s        r   &test_10_forbidden_path_high_core_auditr     s    
 
H	B.	B	F *, 
.vj/A.DE, b!Eu:?<<<?2YF#$(BB 
J6RcKdJghB *, 
4VJ5G4JK,r   c                |   | dz  }t        t        dd      |dt               t        |      }t        t        dd      |dt              }|d	   d
k(  sJ d|d	          t        |      }t	        |      t	        |      dz   k(  s"J dt	        |      dz    dt	        |              |d   }|d   dk(  sJ d       y)u^   POST_MERGE_SMOKE_FAILED 처리 → classification == 'critical', audit JSONL에 라인 추가.zsmoke-wsr~   ztask-11-prer   Tr2   rk   ztask-11-smoker5   r6   z)classification should be 'critical', got rR   z	Expected z$ audit lines after smoke event, got r   r7   zCLast audit line escalation_type should be 'POST_MERGE_SMOKE_FAILED'Nr   )r?   rW   lines_beforerA   lines_afterlast_records         r   $test_11_smoke_failure_critical_sevenr     s   	J	B +]C	 %R(L -G	F "#z1 
3F;K4L3OP1 $B'K{s<0144 
C%)**NsS^O_N`a4 b/K()-FF 
MFr   c                   | dz  }t        t        dd      |dt              }|d   dk(  sJ d	|d          t        |      }t	        |      d
k\  sJ d       |d   }|d   dk(  sJ d|d          |j                  d      sJ d       y)u   STYLE_ONLY_GEMINI 처리 후:
    - classification == 'auto-handled'
    - audit 라인의 classification == 'auto-handled'
    - suppressed_reason 필드 비어있지 않음
    zstyle-only-wsrG   ztask-12r   Tr2   r5   rI   z-classification should be 'auto-handled', got rR   r   r   z3audit classification should be 'auto-handled', got suppressed_reasonz<audit suppressed_reason should not be empty for auto-handledN)r   r   r>   r0   rT   getr   s        r   test_12_style_only_audit_taggedr     s     
O	#B';	F "#~5 
7?O8P7ST5 b!Eu:?<<<?2YF"#~5 
=fEU>V=YZ5 ::)* F*r   c           
        t        t              dk(  sJ dt        t                      t        j                         D ]  \  }}| d| z  }t        t	        |d|dd        |dt
        	      }|d
   dk(  sJ d| d|d
          |d   |j                  k(  sJ d| d|j                  d|d          |d   J d| d       |d   J d| d        y)u   LEGACY_CRITICAL_MAP의 7개 legacy 이름 입력 시 모두 classification == 'critical'.
    escalation_type은 canonical enum value (매핑 후 이름) 와 일치해야 한다.ru   z/LEGACY_CRITICAL_MAP should have 7 entries, got zlegacy-ztask-legacy-N   r   Tr2   r5   r6   z[legacy=r   r7   z&] escalation_type should be canonical z, got r9   r   r   z] severity should not be None)rT   r
   rv   r   r   r>   ro   )r?   
legacy_keycanonical_enumrW   rA   s        r   test_13_legacy_critical_compatr   #  sS    "#q( 
9#>Q:R9ST( ':&?&?&A d"
N'*..
l:bq>:J,KL	
 &':5 	
zl"MfUeNfMij	
5 '(N,@,@@ 	
zl"HI]I]H` a+,/1	
@ h+_x
|C^-__+j!-c*Eb/cc-!dr   c           
        | dz  }t        dd      t        dd      t        dd      g}|D ]  }t        ||d	t        
        t        |      }|j	                         sJ d       |j                  d      j                         D cg c]"  }|j                         r|j                         $ }}t        |      dk(  sJ dt        |              t        |      D ]Q  \  }}	 t        j                  |      }	d	v sJ d|dz    d       d|	v sJ d|dz    d       d|	v rEJ d|dz    d        yc c}w # t        j                  $ r+}
t        j                  d|dz    d|
 d|       Y d}
~
wd}
~
ww xY w)ug   3건의 다른 이벤트 처리 후 JSONL 파일 line-by-line json.loads → 3개 모두 파싱 성공.zmulti-wsrN   z	task-14-ar   r~   z	task-14-brk   z	task-14-cTr2   zGlobal audit JSONL should existr$   r%      zExpected 3 audit lines, got zLine rR   z failed json.loads: z
Line content: Nr   z missing 'ts' keyr   z missing 'task_id' keyr5   z missing 'classification' key)r   r   r>   r"   r'   r(   r)   r*   rT   	enumerater+   r,   JSONDecodeErrorpytestfail)r?   rW   r   rX   r   r.   	raw_linesiliner   excs              r   test_14_audit_jsonl_parseabler   A  s   	J	B.D+[A-{CF  HeB$GH %R(KB!BB '''9DDF88: 	
I 
 y>QO">s9~>N OOY' X4	ZZZ%F v~?q1ug->??~F"IeAE72H$II"6)WU1q5'9V+WW)X ## 	ZKK%Aw&:3%?OPTxXYY	Zs   
'D4&D99E7!E22E7)r^   i)#  N)
r   strr   r   r   intr   zdict | Nonereturnr   )r!   r   r   r   )r!   r   r   z
list[dict])r?   r   r   None)r   r   )3__doc__
__future__r   rl   r+   sysr   r   pathlibr   r   __file__resolveparent
_WORKSPACEr   _WORKSPACE_STRpathremoveinsertutils.automation_contractsr   r   r	   "utils.critical_escalation_reporterr
   r   r   r   r   ro   r=   utcr>   r   r"   r0   rB   rL   r\   rs   r   r   r   r   r   r   r   r   r   r   )es   0r   <module>r      sh  & #   
 '   (^##%,,33::
Z SXXHHOON# > " 
  !771qww7aB1X\\:
  	  	
 
 \,
6]<+>dH@!
P
>%YX;WDe<@ NBd<XS 8s   E