
    i9                        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
 ddlmZ ddlmZmZ defdZd	edee	e	f   fd
Zd	edefdZdedeeef   fdZdeeef   d	edeeef   fdZdedefdZdeeef   deeeeef   f   fdZdeeef   defdZdedededefdZdedeeef   fdZdeeeeef   f   deeeeeef   f      dee   fdZdeeeeef   f   deeeeeef   f      deeef   fdZ deeef   d ed	eddfd!Z!d ed	edeeeef      fd"Z"d	ededed edeeef   f
d#Z#d&d$Z$e%d%k(  r e$        yy)'u   weekly-retro.py — 주간 회고 시스템

task-timer.py 데이터와 git log를 분석해 팀별 생산성 메트릭을 계산하고
JSON 스냅샷을 저장한다.

Usage:
    python3 weekly-retro.py [--week YYYY-WW] [--workspace /path]
    N)defaultdict)date	timedelta)Path)AnyOptionalreturnc                  f    t        j                         } | j                         }|d    d|d   dS )u7   현재 ISO week를 'YYYY-WW' 형식으로 반환한다.r   -   02d)r   todayisocalendar)r   isos     E/home/jay/workspace/.worktrees/task-2116-dev1/scripts/weekly_retro.pyget_current_weekr      s6    JJLE



C!fXQs1vcl##    weekc                     | j                  d      \  }}t        |      }t        |      }t        j                  ||d      }|t	        d      z   }||fS )ua   'YYYY-WW' 형식의 week 문자열로부터 해당 주의 (월요일, 일요일)을 반환한다.r   r      days)splitintr   fromisocalendarr   )r   year_strwnum_stryearwnummondaysundays          r   get_week_periodr"   !   sS    CHhx=Dx=D!!$a0FiQ''F6>r   c                 x    t        |       \  }}|t        d      z
  }|j                         }|d    d|d   dS )u8   'YYYY-WW'에서 이전 주의 'YYYY-WW'를 반환한다.   r   r   r   r   r   )r"   r   r   )r   r    _prev_mondayr   s        r   get_prev_weekr'   ,   sH    %IFA9!,,K

!
!
#C!fXQs1vcl##r   
tasks_filec                     | j                         si S 	 t        j                  | j                               }|j	                  di       }t        |t              si S |S # t        j                  t        f$ r i cY S w xY w)u   task-timers.json을 읽어 tasks dict를 반환한다.

    파일이 없거나 파싱 실패 시 빈 dict를 반환한다.
    tasks)	existsjsonloads	read_textget
isinstancedictJSONDecodeErrorOSError)r(   datar*   s      r   
load_tasksr5   9   st    
 	zz*..01 $" 5%&I  '* 	s   AA A A;:A;r*   c                 *   | si S t        |      \  }}i }| j                         D ]\  \  }}|j                  d      dk7  r|j                  dd      }|s0	 t        j                  |dd       }||cxk  r|k  sUn X|||<   ^ |S # t
        $ r Y lw xY w)u   주어진 week에 해당하며 status가 'completed'인 태스크만 필터링한다.

    start_time의 ISO date가 해당 주(월~일) 범위 내에 있는 태스크만 포함한다.
    status	completed
start_time N
   )r"   itemsr/   r   fromisoformat
ValueError)	r*   r   r    r!   resulttask_idtaskstart_time_str	task_dates	            r   filter_tasks_by_weekrD   J   s    
 	$T*NFFF #88H,,3	**>#2+>?I Y(&("F7O# M  		s   B	BBduration_secondsc                     | dkD  ry| dk\  ryy)u   소요 시간에 따라 세션을 분류한다.

    - deep:   > 1800초 (30분 초과)
    - medium: 600초 이상 1800초 이하 (10분 이상 30분 이하)
    - micro:  < 600초 (10분 미만)
    i  deepiX  mediummicro )rE   s    r   classify_sessionrK   k   s     $	S	 r   c                    | si S t        t              }t        d       }| j                         D ]b  }|j                  dd      }|sd}t	        |j                  dd            }||   j                  |       t        |      }||   |xx   dz  cc<   d i }|j                         D ];  \  }}t        |      }	|	dkD  rt        |      |	z  nd}
|	|
dt        ||         d||<   = |S )	u  completed 태스크들로부터 팀별 메트릭을 계산한다.

    반환:
        {
            "team-id": {
                "task_count": int,
                "avg_duration_seconds": float,
                "fix_pct": float,          # 기본 0.0, 커밋 분석 후 갱신
                "session_pattern": {"deep": int, "medium": int, "micro": int}
            }
        }
    c                      ddddS )Nr   )rG   rH   rI   rJ   rJ   r   r   <lambda>z&compute_team_metrics.<locals>.<lambda>   s    AYZefCg r   team_idunknownrE           r   r   )
task_countavg_duration_secondsfix_pctsession_pattern)r   listvaluesr/   floatappendrK   r<   lensumr1   )r*   team_durationsteam_sessionsrA   rO   durationcategorymetrics	durationscountavg_durs              r   compute_team_metricsrd      s    	 .9->N/:;g/hM .xx	95G);S ABw&&x0#H-gx(A-(. *,G,224 
I,1AI#i.5(3$+#M'$:;	

 Nr   commitsc                     | j                  dd      }|dk(  ry| j                  di       j                  dd      }||z  dz  S )u7   전체 커밋 중 fix 타입 비율(%)을 계산한다.totalr   rQ   by_typefix      Y@r/   )re   rg   	fix_counts      r   compute_fix_pctrm      sI    Wa(Ez[[B/33E1=Iuu$$r   	workspacesinceuntilc           
          	 t        j                  ddt        |       dd| dd| ddd	gd
d
      }|j                  dk7  ry|j                  S # t
        t        f$ r Y yw xY w)uY   git log를 실행하고 stdout을 반환한다. 실패 시 빈 문자열을 반환한다.gitz-Clogz--after=z	T00:00:00z	--before=z	T23:59:59z--format=%h %ad %sz--date=shortT)capture_outputtextr   r:   )
subprocessrunstr
returncodestdoutFileNotFoundErrorr3   )rn   ro   rp   r?   s       r   fetch_git_logr|      s    I5'+E7),$	  
 !}}w' s   A A A A! A!
log_outputc                 F   g d}|D ci c]  }|d }}d|d<   | j                         sd|dS | j                         j                         D cg c]#  }|j                         s|j                         % }}t        |      }|D ]  }|j                  dd      }t        |      dk\  r|d   nd}d	}	|D ]K  }
|j	                         }|j                  |
 d
      s|j                  |
 d      s<||
xx   dz  cc<   d}	 n |	r|dxx   dz  cc<    ||dS c c}w c c}w )u   git log stdout을 파싱하여 커밋 타입별 집계를 반환한다.

    커밋 메시지 패턴: "type:" 또는 "type(scope):" 접두사 (대소문자 무시)
    접두사 없으면 "other"로 분류.
    )featri   refactordocschorer   other)rg   rh          r:   F:(r   T)strip
splitlinesrZ   r   lower
startswith)r}   commit_typestrh   linelinesrg   partssubject
classifiedctyper   s               r   parse_git_logr      s=    @L-9:q!t:G:GGw//&0&6&6&8&C&C&EVdTZZ\VEVJE " 

3"!%jAo%(2
! 	EMMOE5',0@0@E7!0M!#!
	 G!"  w//3 ; Ws   
DD%Dteams
prev_teamsc                    g }| j                         D ]6  \  }}|j                  dd      }|dkD  s|j                  d| d|dd       8 || j                         D ]s  \  }}|j                  |      }||j                  dd	      }|j                  dd	      }|d	kD  sD||z
  |z  }	|	d
kD  sR|j                  d| d| d| d|	dz  dd	       u |S )u   이상치를 감지하고 메시지 목록을 반환한다.

    감지 조건:
    1. fix_pct > 30% 인 팀
    2. 이전 주 대비 작업 수 50% 초과 감소 (prev_teams가 있을 때)
    rT   rQ   g      >@u   fix_pct 30% 초과: z (z.1fz%)rR   r   g      ?u   생산성 급감: u	    (이전 u   건 → 현재 u   건, d   u	   % 감소))r<   r/   rY   )
r   r   	anomaliesrO   r4   rT   	prev_data
curr_count
prev_countdrop_pcts
             r   detect_anomaliesr      s    I P)S1T>3G9Bwsm2NOP
 "[[] 	MGT"w/I "hh|Q7J'mmL!<JA~&3zAd?$$,WIYzl/ZdYeej#c>#.i9	 r   c                 P   |i S t        d | j                         D              }t        d |j                         D              }| j                         D cg c]  }|j                  dd      dkD  s|d    }}|j                         D cg c]  }|j                  dd      dkD  s|d    }}|rt        |      t        |      z  nd}|rt        |      t        |      z  nd}i }	|dk7  r||z
  |z  dz  |	d	<   nd|	d	<   |dk7  r||z
  |z  dz  |	d
<   |	S d|	d
<   |	S c c}w c c}w )uz   이전 주 대비 전체 메트릭 변화율을 계산한다.

    prev_teams가 None이면 빈 dict를 반환한다.
    Nc              3   @   K   | ]  }|j                  d d        ywrR   r   Nrk   .0ds     r   	<genexpr>z compute_trend.<locals>.<genexpr>.  s     Ja155q1J   c              3   @   K   | ]  }|j                  d d        ywr   rk   r   s     r   r   z compute_trend.<locals>.<genexpr>/  s     Oa155q1Or   rR   r   rS   rQ   rj   task_count_change_pctavg_duration_change_pct)r[   rW   r/   rZ   )
r   r   curr_total_countprev_total_countr   curr_durationsprev_durationscurr_avg_durprev_avg_durtrends
             r   compute_trendr   "  s\    	 J5<<>JJO:;L;L;NOO9>fA155Q]_`KadeKea./fNf9C9J9J9LkAPQPUPUVbdePfijPja./kNk@N3~&^)<<TWL@N3~&^)<<TWLE1*:=M*MQa)adi)i%&)-%&s,8<,G<+WZ_+_'( L ,0'(L% gks   D2DD#(D#r4   snapshot_dirc                     |j                  dd       |d| dz  }|j                  t        j                  | dd             y)	ub   스냅샷 데이터를 JSON 파일로 저장한다. 디렉토리가 없으면 자동 생성한다.T)parentsexist_okweek-.jsonFr   ensure_asciiindentN)mkdir
write_textr,   dumps)r4   r   r   filepaths       r   save_snapshotr   K  sC    td3dV511H

4eAFGr   c                     | d| dz  }|j                         sy	 t        j                  |j                               S # t        j                  t
        f$ r Y yw xY w)uY   지정된 주의 스냅샷 파일을 읽어 반환한다. 없으면 None을 반환한다.r   r   N)r+   r,   r-   r.   r2   r3   )r   r   r   s      r   load_snapshotr   R  s\    dV511H??zz(,,.//  '* s   "? AAc                    t        |       \  }}t        |      }t        |      }t        |      }t        ||       }	t	        |	      }
t        |||      }t        |      }t        |      }|
j                         D ]  }||d<   	 t        |       }t        ||      }|r|j                  d      nd}t        |
|      }t        |
|      }| ||d|
|||d}t        |||        |S )ue   주어진 week에 대한 회고 리포트를 생성하고 스냅샷으로 저장한 뒤 반환한다.rT   r   N)startend)r   periodr   re   r   r   )r"   rx   r5   rD   rd   r|   r   rm   rW   r'   r   r/   r   r   r   )r   rn   r(   r   r    r!   	since_str	until_str	all_tasks
week_tasksteam_metrics
git_outputre   global_fix_pct	team_data	prev_weekprev_snapshotr   r   r   reports                        r   build_reportr   b  s    %T*NFFFIFI :&I%i6J (
3L y)Y?JJ'G %W-N!((* .	-	). d#I!,	:M/<""7+$J ,
3E !z:I 
 
F &,-Mr   c                  ,   t        j                  d      } | j                  dd d       | j                  dt        j                  j                  dt        t        t              j                         j                  j                              d       | j                         }|j                  xs
 t               }t        |j                        }|d	z  d
z  }|d	z  dz  dz  }t        ||||      }t!        t#        j$                  |dd             y )NuL   주간 회고 시스템 — task-timer 데이터와 git log를 분석한다.)descriptionz--weeku2   분석할 주 (YYYY-WW 형식, 기본: 현재 주))defaulthelpz--workspaceWORKSPACE_ROOTuU   워크스페이스 루트 경로 (기본: $WORKSPACE_ROOT 또는 /home/jay/workspace)memoryztask-timers.jsonwhisperzretro-snapshots)r   rn   r(   r   Fr   r   )argparseArgumentParseradd_argumentosenvironr/   rx   r   __file__resolveparent
parse_argsr   r   rn   r   printr,   r   )parserargsr   rn   r(   r   r   s          r   mainr     s    $$1  AF
A  
 

/T(^5K5K5M5T5T5[5[1\]d  
 D99*(*DT^^$IX%(::Jx')36GGL!	F 
$**V%
:;r   __main__)r	   N)&__doc__r   r,   r   rv   syscollectionsr   datetimer   r   pathlibr   typingr   r   rx   r   tupler"   r'   r1   r5   rD   rX   rK   rd   rm   r|   r   rV   r   r   r   r   r   r   __name__rJ   r   r   <module>r      s     	  
 # $   $# $# %d
"3 $ $ $4 DcN "S#X c d38n Bu  (*S>*	#tCH~
*Z%T#s(^ % %T # c c 0 0c  0d38n  0P T#s(^#$ c4S>123  
#Y P!T#s(^#$!c4S>123! 
#s(^!RHS#X Hd H# H$ H C HT#s(^4L  7
77 7 	7
 
#s(^7~<: zF r   