
    ># jk/                        U d Z ddlZddlZddlZddlZddlZdddddddddd	Zeeef   e	d<    ej                  d	ej                        Z ej                  d
ej                        ZdededefdZdedefdZdededz  fdZdededz  fdZdedz  dedz  fdZdedeedz  ef   fdZdedee   fdZdee   dedee   fdZ	 	 	 d"dedededz  dedz  def
dZd#d Zed!k(  r e        yy)$u  
qc_report_guard.py — 보고서 정직성 강제 (Guard MVP Phase 1)

qc-result JSON ↔ 보고서 verdict 불일치 차단.
task-2431 사고: qc_result=WARN 인데 보고서=OVERALL PASS → 여기서 FAIL.

Source-of-truth 룰:
  우선 1: YAML frontmatter qc_verdict 필드
  우선 2: ## QC Verdict 섹션 직속 한 줄
  둘 다 없으면 → FAIL (보고서 정직성 강제)
    NPASSWARNPASS_WITH_WARNFAIL)	r   zOVERALL PASSr   zOVERALL WARNr   zPASS with WARNzPASS WITH WARNr   zOVERALL FAIL_VERDICT_NORMALIZEz^qc_verdict\s*:\s*(.+)$z^##\s+QC Verdict\s*$textposreturnc                 >    | d| }|j                  d      }|dz  dk(  S )u:   pos 위치가 코드 블록(```...) 안에 있으면 True.N```      )count)r   r	   beforer   s       H/home/jay/workspace/.worktrees/task-2537-dev4/scripts/qc_report_guard.py_is_in_code_blockr   (   s*    $3ZFLLEAI!    linec                 v    | j                         }|j                  d      ryt        j                  d|      ryy)uC   인용 블록(> 로 시작) 또는 특정 prefix 패턴이면 True.>Tu3   ^(이전 표현|정정된 표현|이전|정정)\s*:F)lstrip
startswithrematch)r   strippeds     r   _is_in_quote_blockr   0   s3    {{}H3	xxFQr   c                 *   t        j                  d| t         j                        }|sy|j                  d      }t        j                  |      }|sy|j                  d      j                         j                  d      j                  d      }|r|S dS )u-   YAML frontmatter에서 qc_verdict 값 추출.z^---\s*\n(.*?)\n---\s*\nNr   "')r   r   DOTALLgroup_FRONTMATTER_KEY_REsearchstrip)r   fm_matchfm_textmraws        r   _extract_frontmatter_verdictr)   ;   s~     xx3T299EHnnQG""7+A
''!*



"
"3
'
-
-c
2C34r   c                 4   t         j                  |       }|sy|j                         }| |d }|j                         D ]X  }|j	                         }|s|j                  d      r yt        |      r5||j                  |      z   }t        | |      rV|c S  y)ud   ## QC Verdict 섹션 직속 첫 번째 비어있지 않은 줄 추출 (인용/코드 블록 제외).N#)	_QC_VERDICT_SECTION_REr#   end
splitlinesr$   r   r   indexr   )r   r'   section_start	remainingr   r   pos_in_texts          r   _extract_section_verdictr3   I   s    %%d+AEEGM]^$I$$& ::<s#  d##iood&;;T;/ r   r(   c                 R    | y| j                         }t        j                  |      S )uM   raw verdict 문자열 → 표준값 (PASS/WARN/FAIL). 매칭 안 되면 None.N)r$   r   get)r(   cleaneds     r   _normalize_verdictr7   c   s&    
{iikG!!'**r   report_textc                     t        |       }t        |       }t        |      }t        |      }|r|r||k7  rdd| d| dfS |dfS |r|dfS |r|dfS y)	u   
    보고서에서 verdict 추출.
    반환: (normalized_verdict, source_label)
    source_label: "frontmatter" | "## QC Verdict" | "none"
    Nu"   frontmatter/section 불일치 (fm=z, sec=)zfrontmatter+## QC Verdictfrontmatterz## QC Verdict)Nnone)r)   r3   r7   )r8   fm_rawsec_rawfm_normsec_norms        r   extract_report_verdictrA   k   s     *+6F&{3G (G!'*H8 h=fXVG9TUVVV333	%%	((r   checks_summaryc                 ^    | j                         D cg c]  \  }}|dv s| c}}S c c}}w )u8   checks_summary에서 WARN/FAIL 상태 키 목록 반환.r   r   )items)rB   kvs      r   _find_warn_fail_keysrH      s+    (..0J$!QA9I4IAJJJs   ))keysc                     g }|j                         }d}| D ][  }d}d}|D ]<  }|j                         j                  d      r| }&|r)t        |      r5||v s:d} n |rK|j	                  |       ] |S )uQ   키 중 보고서 본문(인용/코드 외)에서 등장하지 않는 것 반환.Fr   T)r.   r$   r   r   append)rI   r8   missinglinesin_codekeyfoundr   s           r   _check_keys_in_reportrQ      s    G""$EG   	Dzz|&&u-%+!$'d{	 NN3! " Nr   task_id	workspacereport_pathqc_result_pathc                    g }d}d}g }|%t         j                  j                  |dd|  d      }|%t         j                  j                  |dd|  d      }t         j                  j                  |      sdd	| gd
dg dS 	 t	        |d      5 }t        j                  |      }	ddd       	j                  dd      }|	j                  di       }t         j                  j                  |      s|j                  d|        d||dg dS 	 t	        |d      5 }|j                         }ddd       t              \  }}||j                  d| d       d||dg dS t        j                  ||      }||f}h d}d}||k(  r|j                  d| d| d       n||vr|j                  d| d|        |dv r1|r/t        |      }|r"t        ||      }|r|j                  d|        t        |      dk(  }|||||dS # 1 sw Y   axY w# t        $ r}
dd|
 gddg dcY d}
~
S d}
~
ww xY w# 1 sw Y   
xY w# t        $ r}
dd|
 g|dg dcY d}
~
S d}
~
ww xY w) u   
    반환:
      {
        "ok": bool,
        "violations": list[str],
        "json_verdict": str,
        "report_verdict": str | None,
        "missing_warns": list[str],
      }
    UNKNOWNNmemoryeventsz
.qc-resultreports.mdFu   qc-result 파일 없음: MISSING)ok
violationsjson_verdictreport_verdictmissing_warnsutf-8encodingu   qc-result JSON 파싱 실패: PARSE_ERROR	qc_resultrB   u   보고서 파일 없음: u   보고서 읽기 실패: u=   verdict 마커 누락 — 보고서 정직성 강제 (source=r:   >   r   r   r   r   r   r   r   r   )r   r   u#   MISMATCH (★ 사고 차단): JSON=u    인데 보고서=z (OVERALL PASS)zMISMATCH: JSON=u    vs 보고서=rD   u#   WARN/FAIL 항목 보고서 누락: r   )ospathjoinexistsopenjsonload	Exceptionr5   rK   readrA   r   rH   rQ   len)rR   rS   rT   rU   r^   r_   r`   ra   fqc_dataerB   r8   source_label	json_norm	norm_pairok_pairs	sago_pairwarn_fail_keysr]   s                       r   checkr~      s     JL!%N!M i8yPZE[\ggll9h	gYc?S 77>>.)6~6FGH%"
 	


.73 	#qiilG	# ;;{I6L";;'7<N 77>>+&5k]CD$("
 	


+0 	#A&&(K	# $:+#F NLKL>YZ[	
 $("
 	
 #&&|\BIN+IH !II1,?QR`Qaapq	
 
(	"l^>.9IJ	

 $$-n=1.+NM!!9-I 
ZA	B $(& i	# 	# 
;A3?@)"
 	

0	# 	# 
6qc:;("
 	

sl   H H&H I H4,I H
H 	H1H,&H1,H14H>9I 	I 
II I c                  .   t        j                  d      } | j                  ddd       | j                  ddd	
       | j                  dd d
       | j                  dd d
       | j                         }t	        |j
                  |j                  |j                  |j                        }|j                  xs9 t        j                  j                  |j                  dd|j
                   d      }d}t        j                  j                  |      r5	 t        |d      5 }|j                         }d d d        t              \  }}t#        d|j
                   t$        j&                         t#        d|d    t$        j&                         |d   r|d   nd}t#        d| d| dt$        j&                         |d   rt#        d t$        j&                         n(|d!   D ]   }	t#        d"|	 t$        j&                         " |d#   r!t#        d$|d#    t$        j&                         |d   rd%nd&}
t#        d'|
 t$        j&                         t%        j(                  |d   rd(       y d)       y # 1 sw Y   GxY w# t         $ r Y Hw xY w)*NuE   qc_report_guard.py — 보고서 정직성 강제 (Guard MVP Phase 1))descriptionz	--task-idTu   task ID (예: task-2434))requiredhelpz--workspace/home/jay/workspaceu7   워크스페이스 루트 (기본: /home/jay/workspace))defaultr   z--report-pathu;   보고서 경로 (기본: <ws>/memory/reports/<task_id>.md)z--qc-result-pathuA   qc-result 경로 (기본: <ws>/memory/events/<task_id>.qc-result))rR   rS   rT   rU   rX   rZ   r[   r<   rb   rc   z[qc-report-guard] task=)filez  qc-result JSON verdict : r_   r`   u   (없음)z  report verdict         : u     ← 출처 (r:   r]   u!     매칭 결과              : OKr^   u     매칭 결과              : ra   u     WARN 항목 누락         : zPASS (rc=0)zFAIL (rc=1)z[qc-report-guard] OVERALL: r   r   )argparseArgumentParseradd_argument
parse_argsr~   rR   rS   rT   rU   rk   rl   rm   rn   ro   rs   rA   rr   printsysstderrexit)parserargsresultrT   rx   ru   rt_
rv_displayrG   overalls              r   mainr   *  sm   $$[F d9ST
/DV  X
Z  \
*D`  bD..$$**	F "" bggll)~S-A'K L	ww~~k"	kG4 VVX4R8OA| 
#DLL>
2D	'~(>'?
@szzR-34D-E():J	'
|>,q
QX[XbXbcd|1D% 	JA3A37cjjI	J o/0G/HIPSPZPZ[%d|mG	'y
1

CHH&,Q&A&/   		s*   J $I:5J :J?J 	JJ__main__)r   NN)r
   N)__doc__r   rp   rk   r   r   r   dictstr__annotations__compile	MULTILINEr"   r,   intboolr   r   r)   r3   r7   tuplerA   listrH   rQ   r~   r   __name__ r   r   <module>r      s  
   	 	 
 &&&
& DcN 
 !bjj!;R\\J #$;R\\J C c d S T  s  sTz  3 3: 4+C$J +3: + cDj#o0F 4K K$s) K
S	  S	 : +"!%	@@@ t@ $J	@
 
@J2'j zF r   