
    i0                       d Z ddlmZ ddlZddlZddlZddZ ej                  d      Z ej                  dej                        Z
 ej                  d      Z ej                  dej                  ej                  z        Z ej                  d	ej                  ej                  z        Z ej                  d
ej                        Z ej                  dej                        Z ej                  dej                  ej                  z        Z ej                  dej                        Z ej                  dej                        Z ej                  dej                        Z ej                  dej                  ej                  z        Z ej                  dej                        Z ej                  dej                        ZddZddZdddZddZddZy)u  
gemini_severity_parser.py — Gemini PR 리뷰 High/Medium/Low 통합 판정 (task-2468 P0-3)

task-2467+3에서 시각 priority(High 3건)와 gate high_severity_hits(0건) 불일치 사고 발생
→ 단일 parser로 통합.

기존 gemini_evidence_verify.match_high_severity는 emoji(🔴/❌) / severity:high|critical /
BLOCKING|CRITICAL|MUST FIX / ## High|Critical|Blocking 패턴만 인식.
본 모듈은 추가 패턴까지 포괄:
- emoji 확장: 🔴 ❌ 🚨 ⚠️ ⛔
- heading 확장: ## High / ### Critical / ## Critical / ### High / ### Blocking / #### High 등
- severity label 확장: severity: high|critical / priority: high|critical (대소문자 무관)
- inline label 확장: **High:** / **Critical:** / **[High]** / **[Critical]**
- keyword 확장: BLOCKING / CRITICAL / MUST FIX / MUST_FIX / High Priority / Critical Issue
- code block 내부는 strip (false positive 방지)
    )annotationsNc                j    | s| S t        j                  dd|       }t        j                  dd|      }|S )u?   fenced code block (``` ... ```) 과 inline code (`...`) 제거.z```[\s\S]*?``` z	`[^`\n]*`)resub)bodycleaneds     O/home/jay/workspace/.worktrees/task-2524-dev5/scripts/gemini_severity_parser.pystrip_code_blocksr      s4    ff&T2Gff\30GN    u   [🔴❌🚨⛔]|⚠️z.(?:severity|priority)\s*[:=]\s*(high|critical)zE\b(BLOCKING|CRITICAL|MUST[\s_]FIX|HIGH\s+PRIORITY|CRITICAL\s+ISSUE)\bz'^\s*#{2,6}\s+(High|Critical|Blocking)\bzD^\s*#{2,6}\s+(High\s+Priority|Critical\s+Issue|Critical\s+Problem)\bz3\*\*\s*\[?\s*(High|Critical|Blocking)\s*\]?\s*[:.*]z%!\[\s*(High|Critical|Blocking)\s*\]\(z^\s*#{2,6}\s+(Medium)\bz%(?:severity|priority)\s*[:=]\s*mediumz!\*\*\s*\[?\s*Medium\s*\]?\s*[:.*]u   ⚠️\s+\w*\s*Mediumz^\s*#{2,6}\s+(Low|Minor)\bz"(?:severity|priority)\s*[:=]\s*lowz\*\*\s*\[?\s*Low\s*\]?\s*[:.*]c                   | 	dddg g g dS t        |       }g }g }g }t        j                  |      D ]$  }|j                  d|j	                                 & t
        j                  |      D ]$  }|j                  d|j	                                 & t        j                  |      D ]$  }|j                  d|j	                                 & t        j                  |      D ]2  }|j                  d|j	                         j                                 4 t        j                  |      D ]2  }|j                  d|j	                         j                                 4 t        j                  |      D ]$  }|j                  d|j	                                 & t        j                  |      D ]$  }|j                  d	|j	                                 & t        j                  |      D ]2  }|j                  d|j	                         j                                 4 t        j                  |      D ]$  }|j                  d|j	                                 & t        j                  |      D ]$  }|j                  d|j	                                 & t        j                  |      D ]$  }|j                  d
|j	                                 & t         j                  |      D ]2  }|j                  d|j	                         j                                 4 t"        j                  |      D ]$  }|j                  d|j	                                 & t$        j                  |      D ]$  }|j                  d|j	                                 & t'        |      t'        |      t'        |      |||dS )u  body에서 high/medium/low 매칭 개수 + 매칭 패턴 리스트 반환.

    Returns:
        {"high": int, "medium": int, "low": int,
         "high_hits": list[str], "medium_hits": list[str], "low_hits": list[str]}

    각 매칭은 1건으로 카운트.
    같은 본문에서 같은 패턴 type이 여러 번 등장하면 각각 카운트
    (예: ## High 두 개 = 2건).
    code block 내부는 strip (false positive 방지).
    r   )highmediumlow	high_hitsmedium_hitslow_hitszemoji:zseverity_label:zkeyword:zheading:zheading_priority:zinline:zimage:zemoji_context:)r   _HIGH_EMOJIfinditerappendgroup_HIGH_SEVERITY_LABEL_HIGH_KEYWORD_HIGH_HEADINGstrip_HIGH_HEADING_PRIORITY_HIGH_INLINE_LABEL_HIGH_IMAGE_LABEL_MED_HEADING
_MED_LABEL_MED_INLINE_MED_EMOJI_CONTEXT_LOW_HEADING
_LOW_LABEL_LOW_INLINElen)r   strippedr   r   r   ms         r
   count_severitiesr)   i   s    |1BB
 	

 !&HIKH !!(+ /6!'')-./ "**84 8?1779+678 ##H- 18AGGI;/01 ##H- 98AGGIOO$5#6789 $,,X6 B,QWWY__->,?@AB  ((2 071779+./0 ''1 /6!'')-./ ""8, ;Xaggioo&7%89:;   * :_QWWYK89: !!(+ 2WQWWYK012  ((2 9^AGGI;789 ""8, 8(1779??#4"5678   * 7/!'')567 !!(+ /'!'')-./ Ik"8}" r   c                $    t        |       d   dk\  S )u>   body에 high severity 패턴이 1건 이상 존재하면 True.r      )r)   )r   s    r
   has_high_severityr,      s    D!&)Q..r   c                r   	 t        j                  dd| gdd|      }|j                  }|dk7  s|j                  j	                         s|g fS 	 t        j                  |j                        }||fS # t
        j                  $ r |g fcY S w xY w# t         j                  $ r dg fcY S t        $ r dg fcY S w xY w)u@   gh api {endpoint} 호출 → (returncode, parsed_json_or_empty).ghapiT)capture_outputtexttimeoutr   )

subprocessrun
returncodestdoutr   jsonloadsJSONDecodeErrorTimeoutExpired	Exception)endpointr2   procrcdatas        r
   _gh_apirA      s    ~~5(#dG
 __7$++++-r6M	::dkk*D 4x ## 	r6M	 $$ 2v 2vs<   A
B A1 -B 1BB 
BB B6'B65B6c           
        dddd}g }g }g }g }t        d|  d| d      \  }}t        |t              r|D ]  }	|	j                  d      xs d}
t	        |
      }|dxx   |d   z  cc<   |d	xx   |d	   z  cc<   |d
xx   |d
   z  cc<   |j                  |d          |j                  |d          |j                  |d          |j                  d|	j                  d      |
dd |d   |d	   |d
   d        t        d|  d| d      \  }}t        |t              r|D ]  }|j                  d      xs d}
t	        |
      }|dxx   |d   z  cc<   |d	xx   |d	   z  cc<   |d
xx   |d
   z  cc<   |j                  |d          |j                  |d          |j                  |d          |j                  d|j                  d      |
dd |d   |d	   |d
   d        t        d|  d| d      \  }}t        |t              r|D ]  }|j                  d      xs d}
t	        |
      }|dxx   |d   z  cc<   |d	xx   |d	   z  cc<   |d
xx   |d
   z  cc<   |j                  |d          |j                  |d          |j                  |d          |j                  d|j                  d      |
dd |d   |d	   |d
   d        |d   |d	   |d
   ||||dS )u   PR의 모든 review + comment에서 severity count 통합. gh CLI 호출.

    Returns:
        {"high": int, "medium": int, "low": int,
         "primary": list[dict],
         "high_hits": list[str], "medium_hits": list[str], "low_hits": list[str]}
    r   )r   r   r   zrepos/z/pulls/z/reviewsr    r   r   r   r   r   r   reviewidN   )typerE   body_snippetr   r   r   z	/commentsreview_commentz/issues/issue_comment)r   r   r   primaryr   r   r   )rA   
isinstancelistgetr)   extendr   )repo	pr_numbertotalsall_high_hitsall_medium_hitsall_low_hitsrK   _reviewsrr   svreview_commentscissue_commentss                  r
   parse_pr_review_severitiesr]      sT    '(1Q?F!M!#O LG 6$wykBCJAw'4  	A55=&BD!$'B6Nbj(N88,5MRY&M  K1""2m#45:/NN eeDk $Tc
6
X,%y 	& !6$wyk!KLA/4(  	A55=&BD!$'B6Nbj(N88,5MRY&M  K1""2m#45:/NN(eeDk $Tc
6
X,%y 	&  &hyk KLA~.$' 	A55=&BD!$'B6Nbj(N88,5MRY&M  K1""2m#45:/NN'eeDk $Tc
6
X,%y 	& v"e}"&  r   c                   | sg S t        |       }g }t        j                  |      r|j                  d       t        j                  |      r|j                  d       t
        j                  |      r|j                  d       t        j                  |      st        j                  |      r|j                  d       t        j                  |      r|j                  d       t        j                  |      r|j                  d       |S )u   기존 gemini_evidence_verify.match_high_severity 호환 인터페이스.

    body에서 high-severity 패턴 매칭 결과 반환 (code block 제외 후).
    각 패턴 type별로 최대 1건 반환 (기존 동작 유지).
    u   emoji:🔴/❌/🚨/⚠️/⛔zseverity:high/criticalz0keyword:BLOCKING/CRITICAL/MUST_FIX/HIGH_PRIORITYz(header:##/###/####High/Critical/Blockingz!inline:**High**/Critical/Blockingz$image:![High/Critical/Blocking](...))
r   r   searchr   r   r   r   r   r   r   )r   r'   hitss      r
   match_high_severityra   6  s     	 &HD(#45""8,,-H%FGH%)?)F)Fx)P>?  *78):;Kr   )r   strreturnrb   )r   
str | Nonerc   dict)r   rd   rc   bool)   )r=   rb   r2   intrc   ztuple[int, list | dict])rP   rb   rQ   rh   rc   re   )r   rb   rc   z	list[str])__doc__
__future__r   r8   r   r4   r   compiler   
IGNORECASEr   r   	MULTILINEr   r   r   r   r   r    r!   r"   r#   r$   r%   r)   r,   rA   r]   ra    r   r
   <module>ro      s    #  	 " bjj34 "rzz5r}} 
 

L 

.r}}0L
 $KLL2==    RZZ:BMM  BJJ,bmm  rzz4bllR]]6RSRZZ@"--P
bjj=r}}M  RZZ 8"--H  rzz79UVRZZ=r}}M
bjj:BMMJSl/
*Uzr   