
    yYi%                     "   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lmZ ddlmZm	Z	m
Z
 ddlmZ ddlmZ ej                  j!                  d e ee      j'                         j(                  j(                              Zeej,                  vrej,                  j/                  de       	 ddlmZ g d	g d
g dg dg ddZeeee   f   ed<   ddddddZ eee!f   ed<   dedee   fdZ"dededz  fdZdededeeef   defdZ#deee$f   de$de!fd Z%d!edeeef   fd"Z&d#ed$e$dee   fd%Z'd!ed$e$deeef   fd&Z(d'eeef   d(eddfd)Z)d.d*ee   dz  dejT                  fd+Z+d.d*ee   dz  ddfd,Z,e-d-k(  r e,        yy# e$ r dZY w xY w)/u  
pattern-detector.py

보고서 디렉토리에서 패턴을 감지하고 팀별로 집계하여
memory/whisper/team-patterns.json에 저장한다.

사용법:
    python3 pattern-detector.py [--workspace /path] [--days 30]

옵션:
    --workspace : 워크스페이스 루트 경로 (기본: /home/jay/workspace)
    --days      : 최근 N일 내 수정된 보고서만 분석 (기본: 30, 0이면 전체)
    N)defaultdict)datetime	timedeltatimezone)Path)AnyWORKSPACE_ROOT)extract_task_id_from_filename)u   테스트\s*없u
   test\s*없u   테스트\s*미작성u   테스트\s*SKIPu   테스트\s*생략)u   pyright\s*에러zpyright\s*erroru   타입\s*에러)u   scope\s*초과u   범위\s*초과u   추가\s*작업\s*발생u   예상보다\s*커짐)z	QC\s*FAILzqc_verify.*FAILu+   (?<!없음\s)(?<!없는\s)(?<!\w)FAIL(?!\w))u   회귀(?!\s*없)u   (?<!\w)regression(?!\s*없)u   기존\s*테스트\s*실패)test_missingpyright_errorscope_exceededqc_fail
regressionPATTERN_KEYWORDSg333333?g      ?g?g333333?g?)r   r   r   r   r   PATTERN_WEIGHTScontentreturnc                     g }t         j                         D ]D  \  }}|D ]:  }t        j                  || t        j                        s)|j                  |        D F |S )u~   
    보고서 내용에서 패턴 타입 목록을 반환한다.
    동일 패턴은 한 번만 반환 (중복 제거).
    )r   itemsresearch
IGNORECASEappend)r   foundpattern_typekeywordskws        I/home/jay/workspace/.worktrees/task-2507-dev5/scripts/pattern-detector.pydetect_patternsr   R   s_    
 E"2"8"8": h 	ByyWbmm4\*	
 L    filenamec                 x    t         t        |       S t        j                  d|       }|r|j                  d      S y)ur   
    파일명에서 task-id를 추출한다.
    SSOT(utils/task_id_parser) 위임. legacy dot-phase 호환.
    Nz^(task-\d+)   )#_ssot_extract_task_id_from_filenamer   matchgroup)r!   ms     r   r
   r
   `   s9    
 +628<<
*Awwqzr    tasksc                 <   g d}|D ]`  }t        j                  || t         j                  t         j                  z        }|s<|j	                  d      j                         }|s^|c S  t        |      }|r&||v r"||   j                  dd      }|rt        |      S y)u   
    보고서 내용 또는 task-timers.json에서 팀 이름을 추출한다.
    우선순위: 보고서 내용 > task-timers.json > "unknown"
    )u   \*\*팀:\*\*\s*([\w-]+)u   ^팀:\s*([\w-]+)z^team:\s*([\w-]+)z^team_id:\s*([\w-]+)u   팀:\s*([\w-]+)zteam:\s*([\w-]+)zteam_id:\s*([\w-]+)r#   team_id unknown)	r   r   r   	MULTILINEr&   stripr
   getstr)	r   r!   r(   team_patternstpr'   teamtask_idtids	            r   extract_team_from_contentr6   m   s    M  IIb'2==2<<#?@771:##%D ,H5G7e#Gn  B/s8Or    pattern_countstotal_reportsc                 f     |dk(  ryt         fdt        j                         D              }||z  S )uc   
    risk_score = sum(count * weight) / total_reports
    total_reports가 0이면 0.0 반환.
    r   g        c              3   N   K   | ]  \  }}j                  |d       |z    yw)r   N)r/   ).0ptypeweightr7   s      r   	<genexpr>z'calculate_risk_score.<locals>.<genexpr>   s'     c-%""5!,v5cs   "%)sumr   r   )r7   r8   totals   `  r   calculate_risk_scorerA      s4     c?K`K`KbccE=  r    	workspacec                     t        |       dz  dz  }	 |j                  d      }t        j                  |      }|j	                  di       S # t
        $ r i cY S w xY w)u=   task-timers.json을 로드한다. 실패 시 빈 dict 반환.memoryztask-timers.jsonutf-8encodingr(   )r   	read_textjsonloadsr/   	Exception)rB   pathtextdatas       r   load_task_timersrO      s^    	?X%(::D~~w~/zz$xx$$ 	s   8A AAreports_dirdaysc                    | j                         sg S t        | j                  d            }|dkD  rt        j                  t
        j                        t        |      z
  }g }|D ]V  }	 t        j                  |j                         j                  t
        j                        }||k\  r|j                  |       X |S |S # t        $ r Y hw xY w)u   
    보고서 디렉토리에서 .md 파일을 수집한다.
    days > 0이면 최근 days일 내 수정된 파일만 반환.
    days == 0이면 전체 반환.
    z*.mdr   tz)rQ   )existslistglobr   nowr   utcr   fromtimestampstatst_mtimer   rK   )rP   rQ   filescutofffilteredfmtimes          r   collect_report_filesrb      s     	!!&)*Eax.1EE! 	A ..qvvx/@/@X\\RF?OOA&		 L	  s   +AC	CCc           
         t        |       }t        |       dz  dz  }t        ||      }t        d       }d}|D ]\  }	 |j	                  d      }|dz  }|j                  }	t        ||	|      }
t        |      }|D ]  }||
   |   j                  |	        ^ i |j                         D ]  \  }
}|j                         D ci c]  \  }}|t        |       }}}t        ||      }t        |j                               D cg c]  \  }}|t        |      t        |      d }}}|t        |d	      d
|
<    t        d j!                         D              }d}rt#        j%                         fd      }dt'        j(                  t*        j,                        j/                  d      |||dd}|S # t
        $ r Y w xY wc c}}w c c}}w )uT   
    보고서 디렉토리를 분석하여 패턴 결과 dict를 반환한다.
    rD   reportsc                       t        t              S N)r   rV    r    r   <lambda>z!analyze_reports.<locals>.<lambda>   s    kZ^N_ r    r   rE   rF   r#   )typecountrecent_reports   )patterns
risk_scorec              3   :   K   | ]  }|d    D ]	  }|d      yw)rm   rj   Nrg   )r;   	team_dataps      r   r>   z"analyze_reports.<locals>.<genexpr>   s'     j	T]^hTijq7jjs   r+   c                     |    d   S )Nrn   rg   )tteams_results    r   rh   z!analyze_reports.<locals>.<lambda>   s    ,q/,7 r    )keyrS   z%Y-%m-%dT%H:%M:%S)total_reports_analyzedtotal_patterns_foundhighest_risk_team)versionlast_updatedteamssummary)rO   r   rb   r   rH   rK   namer6   r   r   r   lenrA   sortedroundr?   valuesmaxkeysr   rX   r   rY   strftime)rB   rQ   r(   rP   report_filesteam_pattern_filestotal_analyzedreport_pathr   r!   r3   rm   r<   pattern_mapr]   r7   riskpatterns_listtotal_patternsrx   resultrt   s                        @r   analyze_reportsr      s    Y'Ey/H,y8K'T:L ;FF_:`N# =	!++W+=G 	!##((EB"7+ 	=Et$U+228<	== $&L/557 
k@K@Q@Q@STu%U+TT#NNC !'{'8'8': ;
 u	 U"(-
 
 &a.
T
& j\5H5H5JjjN 7
  5>>?RS&4$2!2
		F Mk  		 U
s   F>G"G>	G
Gr   output_pathc                     t        |      }|j                  j                  dd       |j                  t	        j
                  | dd      d       y)	uN   결과를 JSON 파일로 저장한다. 디렉토리가 없으면 생성한다.T)parentsexist_okF   ensure_asciiindentrE   rF   N)r   parentmkdir
write_textrI   dumps)r   r   rL   s      r   save_resultsr     sG    DKKdT2OO

6a8  r    argvc                 V   t        j                  d      }|j                  dt        j                  j                  dt        t        t              j                         j                  j                              d       |j                  dt        dd	
       |j                  |       S )NuE   보고서에서 세션 패턴을 감지하고 팀별로 집계한다.)descriptionz--workspacer	   uU   워크스페이스 루트 경로 (기본: $WORKSPACE_ROOT 또는 /home/jay/workspace))defaulthelpz--days   uJ   최근 N일 내 수정된 보고서만 분석 (기본: 30, 0이면 전체))ri   r   r   )argparseArgumentParseradd_argumentosenvironr/   r0   r   __file__resolver   int
parse_args)r   parsers     r   r   r     s    $$1xyF


/T(^5K5K5M5T5T5[5[1\]d  
 Y	   T""r    c                    t        |       }t        |j                  |j                        }t	        t        |j                        dz  dz  dz        }t        ||       t        t        j                  |dd             y )N)rB   rQ   rD   whisperzteam-patterns.jsonFr   r   )
r   r   rB   rQ   r0   r   r   printrI   r   )r   argsr   r   s       r   mainr   +  sb    dDt~~DIIFFd4>>*X5	ADXXYK%	$**V%
:;r    __main__rf   ).__doc__r   rI   r   r   syscollectionsr   r   r   r   pathlibr   typingr   r   r/   r0   r   r   r   _WORKSPACE_ROOTrL   insertutils.task_id_parserr
   r$   ImportErrorr   dictrV   __annotations__r   floatr   r6   r   rA   rO   rb   r   r   	Namespacer   r   __name__rg   r    r   <module>r      sT     	 	 
 # 2 2  **..!13tH~7M7M7O7V7V7]7]3^_#(("HHOOA'/i

1* $sDI~& B %c5j! S T#Y 
C 
C$J 
""" S>" 		"J!cN!! ! S#X d # $t* 4Ds D# D$sCx. DNc3h c d #T#Y% #1C1C # <tCy4 <4 < zF o  /*.'/s   )F FF