
    i                         d Z ddlZddlZddlZg dZdedefdZdededefd	Zd
e	e   dedej                  fdZdedefdZddededefdZy)uP  
git_evidence.py - git 커밋 증거 검증 verifier
task-2031: 코드 커밋 없이 .done 생성 방지

3가지 검증:
1. COMMIT_EXISTS: task ID가 포함된 커밋 최소 1건
2. NO_UNCOMMITTED: uncommitted 변경 없음
3. NON_EMPTY_COMMIT: 마지막 커밋이 빈 커밋이 아님

non-code task (문서만/리서치만) → SKIP
    N)zmemory/heartbeats/zmemory/events/zlogs/zmemory/daily/zwhisper/zbot-activity.jsonztoken-ledger.jsonzmemory/pipeline-status.jsonzmemory/preview-state.jsonzmemory/merge-log.jsonzmemory/bot_settings_sync.jsonzmemory/memory-check-log.jsonz!dashboard/data/refine-status.jsonz"dashboard/data/refine-history.jsonz
.heartbeatzmemory/.task-counterzmemory/task-timers.jsonzmemory/logs/zmemory/reports/zmemory/tasks/filepathreturnc                    | j                  dd      }t        D ]k  }|j                  d      r|j                  |      s& y|j                  d      r||v s|j                  |      sO y|j                  d|z         s||k(  sk y y)u<   시스템이 자동 생성/수정하는 파일인지 판별.\/.TF)replaceSYSTEM_AUTO_FILES
startswithendswith)r   
normalizedpatterns      T/home/jay/workspace/.worktrees/task-2116-dev1/teams/shared/verifiers/git_evidence.py_is_system_auto_filer   *   s    !!$,J$ c"""7+c"*$
(=(=g(F ""3=1Z75J     task_idworkspace_rootc                    t         j                  j                  |dd|  d      }t         j                  j                  |      sy	 t	        |dd      5 }|j                         }ddd       t        j                  d	t        j                        }|sy|j                  d
      }t        t        j                  d|            S # 1 sw Y   axY w# t        $ r Y yw xY w)u@   task 파일의 ## 레벨 섹션에서 non-code 키워드 판별.memorytasksz.mdFrzutf-8)encodingNu   ## 레벨\s*\n(.*?)(?=\n## |\Z)   uB   코드 수정 없음|문서 업데이트만|문서만|리서치만)ospathjoinisfileopenreadresearchDOTALLgroupboolOSError)r   r   	task_pathfcontentmsections          r   _is_non_code_taskr+   =   s    ^Xw7)3PI77>>)$
)S73 	qffhG	 II8'299M''!*BIIcelmnn	 	  s0   C C&/C /C CC 	CCargscwdc                 >    t        j                  dg| z   |ddd      S )u   git 명령 실행 헬퍼.gitT   )r-   capture_outputtexttimeout)
subprocessrun)r,   r-   s     r   _run_gitr6   O   s(    >>	$ r   c                     	 t        ddg|       }|j                  dk(  r|j                  j                         S 	 | S # t        j
                  t        f$ r Y | S w xY w)u,   git rev-parse로 프로젝트 루트 탐지.z	rev-parsez--show-toplevelr   )r6   
returncodestdoutstripr4   TimeoutExpiredr%   )r   results     r   _find_project_rootr=   Z   sl    ;(9:NK!==&&(( "  %%w/ s   6< AAc                 \   t        | |      rddgdS t        |      }g }g }	 t        dddd|  g|      }|j                  j	                         j                         D cg c]  }|j	                         s| }}t        |      }|dk(  r'|j                  d	|  d
       |j                  d       n|j                  d|  d| d       	 t        ddg|      }
t        g d|      }|
j                  j	                         j                         D cg c]  }|j	                         s| }}|j                  j	                         j                         D cg c]  }|j	                         s| }}|D cg c]  }t        |      r| }}|D cg c]  }t        |      r| }}t        |      t        |      z   t        |      z
  t        |      z
  }|s|r<|j                  dt        |       dt        |       d       |j                  d       n!d}|dkD  r	|d| dz  }|j                  |       	 t        ddd|  ddg|      }|j                  j	                         }|rt        dd| d| g|      }|j                  j	                         j                         D cg c]  }|j	                         s| }}t        |      }|dk(  r#|j                  d       |j                  d        n'|j                  d!| d       n|j                  d"       |rd$||d%S d&|dS c c}w # t        j                  t        f$ r0}	|j                  d|	        |j                  d       Y d}	~	d}	~	ww xY wc c}w c c}w c c}w c c}w # t        j                  t        f$ r0}	|j                  d|	        |j                  d       Y d}	~	d}	~	ww xY wc c}w # t        j                  t        f$ r0}	|j                  d#|	        |j                  d        Y d}	~	d}	~	ww xY w)'ul   
    git 커밋 증거 검증.

    Returns:
        {"status": "PASS"|"FAIL"|"SKIP", "details": [...]}
    SKIPu4   non-code task (문서/리서치) — git 검증 SKIP)statusdetailslogz	--onelinez--allz--grep=r   zFAIL COMMIT_EXISTS: u    커밋 0건COMMIT_EXISTSzPASS COMMIT_EXISTS: u    커밋 u   건u*   FAIL COMMIT_EXISTS: git 명령 실패 — Ndiff--name-only)rD   z--cachedrE   u0   FAIL NO_UNCOMMITTED: uncommitted 변경 존재 (z unstaged, z staged)NO_UNCOMMITTEDu.   PASS NO_UNCOMMITTED: uncommitted 변경 없음u    (시스템 자동 파일 u   건 제외)u+   FAIL NO_UNCOMMITTED: git 명령 실패 — z--format=%Hz-1z^..u5   FAIL NON_EMPTY_COMMIT: 빈 커밋(변경 파일 0건)NON_EMPTY_COMMITu%   PASS NON_EMPTY_COMMIT: 변경 파일 uI   SKIP NON_EMPTY_COMMIT: task ID 커밋 없음 (COMMIT_EXISTS에서 처리)u-   FAIL NON_EMPTY_COMMIT: git 명령 실패 — FAIL)r@   rA   failed_checksPASS)r+   r=   r6   r9   r:   
splitlineslenappendr4   r;   r%   r   )r   r   proj_dirrA   failedr<   llinescommit_countediff_resultcached_resultr'   
diff_filescached_files	real_diffreal_cachedexcluded_countmsghash_result	last_hashdiff_files_result
file_linesdiff_file_counts                           r   verifyra   e   s    .1NO
 	

 ".1HGF'5+w''8KLhW"MM//1<<>Lq!'')LL5z1NN1',GHMM/*NN1'(<.PSTU(6A !DhO!,!3!3!9!9!;!F!F!HVAAGGIaV
V#0#7#7#=#=#?#J#J#LZaPQPWPWPYZZ *J12Fq2IQJ	J".NQ6J16MqNNZ3|+<<s9~MPST_P``NNMcR[nM]]hilmxiyhz  {C  D  EMM*+BC!3N3C;OONN3*Gwwi0-F
  &&,,.	 (9+S(DEx! &7%=%=%C%C%E%P%P%R`VWV]V]V_!`J`!*oO!#VW01!FFWWZ[\NNfg
  WvNN11w M %%w/ 'CA3GHo&&' WZJN %%w/ (DQCHI&''( a %%w/ *FqcJK())*s   =L1  L,6L,:AL1 AN M=(M=,,N N.N2N 8N	NN N$N(BN ;A.O" )O?OAO" ,L1 1M:
%M55M:=N O*%OOO" "P+;%P&&P+)z/home/jay/workspace)__doc__r   r    r4   r
   strr$   r   r+   listCompletedProcessr6   r=   dictra    r   r   <module>rh      s   
 
 	  03 4 &s C D $49 3 :+F+F s s P2C P2 P2 P2r   