
    Niu$                         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e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/z scripts/gemini_rate_tracker.jsonztests/coverage-report.txtzmemory/canary-status.jsonz'dashboard/data/medium-comments-log.jsonzconfig/constants.json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-2467-dev6/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tasks.mdFr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.   B   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   )r0   capture_outputtexttimeout)
subprocessrun)r/   r0   s     r   _run_gitr9   T   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   )r9   
returncodestdoutstripr7   TimeoutExpiredr(   )r   results     r   _find_project_rootr@   _   sl    ;(9:NK!==&&(( "  %%w/ s   6< AAc                 P   dD ]  }t         j                  j                  |d      j                         }|rAt         j                  j                  t         j                  j                  |d            r|c S |swt         j                  j                  |      st         j                  j                  |d      }t         j                  j                  |      s|c S  t         j                  j                  |dd      }	 ddl}t        |dd	
      5 }|j                  |      }ddd       j                  di       j                  | i       }	dD ]H  }
|	j                  |
d      j                         }|s&t         j                  j                  |      sF|c S  	 t         j                  j                  |dd|  d      }	 t        |dd	
      5 }|D ]q  }dD ]j  }||v s|j                  |d      d   j                         j                  d      }|s=t         j                  j                  |      s]|c c cddd       S  s 	 ddd       t        |      S # 1 sw Y   9xY w# t        t        t        f$ r Y w xY w# 1 sw Y   ;xY w# t        $ r Y t        |      S w xY w)u{  워크트리 경로를 우선순위에 따라 자동 탐지.

    우선순위:
    (A) 환경변수 PROJECT_PATH 또는 WORKTREE_PATH + .git 존재
    (B) /home/jay/workspace/memory/task-timers.json의 worktree_path 또는 project_path
    (C) task 파일에서 "워크트리 경로:" 또는 "프로젝트:" 라인 파싱
    (D) 폴백: workspace_root에서 git rev-parse
    )PROJECT_PATHWORKTREE_PATH z.gitr   ztask-timers.jsonr   Nr   r   r   r   )worktree_pathproject_pathr   )u   워크트리 경로:u   프로젝트:r   z`"')r   environgetr=   r   isdirr   existsjsonr!   loadr(   
ValueErrorKeyErrorsplitr@   )r   r   env_varenv_pathgit_filetimers_path_jsonr*   timersentryfield	candidater)   lineprefixs                  r   _resolve_project_dirr[   j   s>    5  ::>>'2.446bggll8V&DEOh/ww||Hf5Hww~~h'  '',,~x9KLK
+sW5 	#ZZ]F	#

7B'++GR86 	!E		%,224IRWW]]95  	! ^Xw7)3PI	)S73 	-q -G -F~$(JJvq$9!$<$B$B$D$J$J6$R	$y)A#,,	- 	---	- n--1	# 	# Z* 	- 	-   n--	s   I) I%AI) 7I) I) I) J J!4JJ6J;	J J	J I&!I) )J ?J JJ 	J%$J%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)rb   z--cachedrc   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^   r_   failed_checksPASS)r.   r[   r9   r<   r=   
splitlineslenappendr7   r>   r(   r   )r   r   proj_dirr_   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   verifyr      s    .1NO
 	

 $G^<H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   =L2 !L-7L-;AL2 AN M>)M>-,N N/N3N 9N
NN N%N)BN <A.O# *O OAO# -L2 2M;%M66M;>N O+%OOO# #P,<%P''P,)z/home/jay/workspace)__doc__r   r#   r7   r
   strr'   r   r.   listCompletedProcessr9   r@   r[   dictr    r   r   <module>r      s   
 
 	  :3 4 &s C D $49 3 :+F+F s s 0.# 0.s 0.s 0.fP2C P2 P2 P2r   