
    ti	Y              
          d Z ddlZddlZddlZddlZddlmZ dZdZdZ	ddd	d
dZ
dddddZdedefdZdefdZdefdZdefdZdedeeef   fdZde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eef   fdZdd d!d"Zd#edededz  fd$Zd#edededz  fd%Zd&eded#edeee   ef   fd'Zdedeee   ef   fd(Zd)ee   d*ee   fd+Zded)ee   d*ee   defd,Zdefd-Z d. Z!e"d/k(  r e!        yy)0u@  
sync-check.py — 3개 파일 간 모델 정보 불일치 자동 감지 스크립트

체크 대상:
  1. /home/jay/.cokacdir/bot_settings.json       — Source of Truth (읽기 전용)
  2. /home/jay/workspace/memory/organization-structure.json — 조직도
  3. /home/jay/.claude/projects/-home-jay--cokacdir-workspace-autoset/memory/MEMORY.md — 아누 메모리 (읽기 전용)

Usage:
    python3 sync-check.py           # 체크만 (읽기 전용)
    python3 sync-check.py --fix     # 불일치 자동 수정 (org_json + engine_summary만, MEMORY.md 수정 안 함)
    N)Pathz%/home/jay/.cokacdir/bot_settings.jsonz6/home/jay/workspace/memory/organization-structure.jsonzQ/home/jay/.claude/projects/-home-jay--cokacdir-workspace-autoset/memory/MEMORY.mdhermesodinraanu)c38fb9955616e24df3e244a7f4f0d036a5dddf38a8c57168c119085addb0f8b7u   아누u   헤르메스u   오딘u   라r   r   r   r   modelreturnc                 $    d| v ryd| v ryd| v ry| S )Nopussonnethaiku )r   s    !/home/jay/workspace/sync-check.pyshort_modelr   0   s'    5%L    c                  z    t        t        d      5 } t        j                  |       cd d d        S # 1 sw Y   y xY wNutf-8encoding)openBOT_SETTINGS_PATHjsonloadfs    r   load_bot_settingsr"   =   s/    	'	2 ayy|     1:c                  z    t        t        d      5 } t        j                  |       cd d d        S # 1 sw Y   y xY wr   )r   ORG_JSON_PATHr   r   r    s    r   load_org_jsonr&   B   s.    	mg	. !yy|  r#   c                  p    t        t        d      5 } | j                         cd d d        S # 1 sw Y   y xY wr   )r   MEMORY_MD_PATHreadr    s    r   load_memory_mdr*   G   s,    	nw	/ 1vvx  s   ,5bot_settingsc                     i }t         j                         D ]U  \  }}| j                  |i       }|j                  di       }|r#t        t	        |j                                     }nd}|||<   W |S )u6   반환: {"anu": "claude-opus-4-6", "hermes": ..., ...}modelsN)BOT_KEY_TO_PERSONitemsgetnextitervalues)r+   resultbot_keypersonentryr-   r   s          r   get_bot_modelsr8   O   sr    F,224   "-8R(fmmo./EEv Mr   orgr6   c           
      
   | j                  di       j                  di       j                  dg       }d}|D ]  }|j                  d      dk(  s|} n |dg fS |dk(  r)|j                  di       }|j                  d	      }|g d
fS dddd}|j                  |      }|sdg fS |j                  dg       D ]G  }	|	j                  d      |k(  s|	j                  di       }
|
j                  d	      }|ddddd|dd	gfc S  dg fS )ut   
    반환: (모델명, json_path_list)
    json_path_list: org를 따라가는 키 경로 (수정 시 사용)
    	structurecolumnsteamsNteam_iddevelopment-officer   office_leadr   )r;   r<   r=   __dev_office__r@   r   	dev1-team	dev2-team	dev3-teamr   r   r   	sub_teamssub_team_idleadrA   )r0   )r9   r6   r=   
dev_officeteamr@   r   sub_team_maprG   sub_teamrH   s              r   get_org_person_modelrM   a   sD   
 GGK$((B7;;GRHEJ 88I"66J
 Rx nn]B7(aaa L
 ""6*KRxNN;3 y<<&+5<<+DHHW%E;	7<Lk[fhnpwxxx	y 8Or   c                 ,   g }| j                  di       j                  di       }| j                  di       j                  di       }|j                  dg       D ]  }|j                  d      }|r|j                  |       |j                  d      }|r|j                  |       |j                  dg       D ]N  }|j                  d      }|r|j                  |       |j                  dg       D ]  }	|j                  |	        P |j                  dg       D ]  }	|j                  |	         |j                  d	g       D ]N  }
|
j                  d      }|r|j                  |       |
j                  dg       D ]  }	|j                  |	        P |S )
u;   조직도에서 모든 멤버(lead 포함) 리스트 반환r;   r<   rowsr=   r@   rH   rF   memberscenters)r0   append)r9   rP   r<   rO   rJ   r@   rH   rL   sub_leadmcenters              r   collect_all_membersrV      s   Gggk2&**9b9G77;#''3D GR( hh}-NN;' xxNN4  b1 	"H||F+Hx(\\)R0 "q!"		" )R( 	ANN1	)0 ((9b) zz&!NN4 Ir* 	ANN1		 Nr   rP   c                 V   i }| D ]  }|j                  d      }|s|j                  d|j                  dd            }d|v r"|j                  d      d   j                         n|j                         }||vrdg d||<   ||   dxx   d	z  cc<   ||   d
   j                  |        |S )u   
    실제 멤버 목록을 순회하여 모델별 카운트와 멤버 이름 목록 계산.
    반환: {"claude-opus-4-6": {"count": N, "members": [...]}, ...}
    r   nameid?(r   countrP   r]      rP   )r0   splitstriprR   )rP   r4   rT   r   rX   korean_names         r   count_models_from_membersrb      s    
 !F 
5guuVQUU4-.474Kdjjoa(..0TZZ\&'B7F5Mug!#ui ''4
5 Mr   zclaude-opus-4-6zclaude-sonnet-4-6zclaude-haiku-4-5)r   r   r   	memory_mdc                    ddddd}|j                  |      }|r[t        j                  || t        j                        }|r4|j	                  d      j                         }t        j                  |      S ddd	d
d}|j                  |      }|r[t        j                  || t        j                        }|r4|j	                  d      j                         }t        j                  |      S y)u   
    MEMORY.md에서 인물 라인을 찾아 Opus/Sonnet/Haiku 추출.
    역할/모델이 "—" (em dash) 다음에 오는 라인을 우선 매칭.
    반환: "claude-opus-4-6" / "claude-sonnet-4-6" / "claude-haiku-4-5" / None
    +   아누[^—\n]*—[^\n]*(Opus|Sonnet|Haiku)1   헤르메스[^—\n]*—[^\n]*(Opus|Sonnet|Haiku)+   오딘[^—\n]*—[^\n]*(Opus|Sonnet|Haiku)(   라[^—\n]*—[^\n]*(Opus|Sonnet|Haiku)r   r^       아누[^\n]*?(Opus|Sonnet|Haiku)&   헤르메스[^\n]*?(Opus|Sonnet|Haiku)    오딘[^\n]*?(Opus|Sonnet|Haiku)   라[^\n]*?(Opus|Sonnet|Haiku)N)r0   research
IGNORECASEgrouplowerMEMORY_MODEL_MAP)rc   r6   patterns_primarypatrT   keywordpatterns_fallbacks          r   parse_memory_modelrw      s     >F>9	 

v
&C
IIc9bmm4ggaj&&(G#''00 3;3.	 


'C
IIc9bmm4ggaj&&(G#''00r   c                    ddddd}|j                  |      }|rFt        j                  || t        j                        }|r|j	                  d      j                         S ddd	d
d}|j                  |      }|rFt        j                  || t        j                        }|r|j	                  d      j                         S y)uE   MEMORY.md에서 파싱한 원본 키워드 (Opus/Sonnet/Haiku) 반환re   rf   rg   rh   r   r^   ri   rj   rk   rl   N)r0   rm   rn   ro   rp   
capitalize)rc   r6   rs   rt   rT   rv   s         r   parse_memory_model_keywordrz      s     >F>9	 

v
&C
IIc9bmm4771:((** 3;3.	 


'C
IIc9bmm4771:((**r   
bot_modelsc                    g }d}g d}|D ]  }| j                  |      }t        ||      \  }}	t        ||      }
t        ||      }g }d}|r |r||k7  rd}|j	                  d| d|        |rU|
rS||
k7  rNd}d}t
        j                         D ]  \  }}||k(  s|j                         } n |j	                  d| d|        |rd}|j	                  |t        |   |rt        |      nd|rt        |      nd|r|nd||||d		        ||fS )
uw  
    각 인물(anu, hermes, odin, ra)에 대해 3-way 비교.
    반환: (결과_리스트, 불일치_있음)
    결과 항목: {
        "person": str,
        "label": str,
        "bot": str,
        "org": str,
        "memory": str | None,
        "memory_keyword": str | None,
        "mismatch": bool,
        "fixes": list[str],   # 수정 필요 설명
    }
    Fr   Tu   org_json 수정 필요:     → Nu   MEMORY.md 수정 필요: zN/A)	r6   labelbotr9   memorybot_fullorg_fullmismatchfixes)
r0   rM   rw   rz   rR   rr   r/   ry   PERSON_LABELr   )r{   r9   rc   resultshas_mismatchpersonsr6   	bot_model	org_model_	mem_modelmem_keywordr   r   expected_keywordkwmvs                    r   check_person_modelsr     sU   & GL-G (
NN6*	+C8	1&y&9	0FC yI'=HLL3I;eI;OP yI'=H#*002 B?')}}$ LL4[MGWFXYZL %f-1:{9-1:{9-)4+%%%$
	
9(
T L  r   c           	         | j                  di       }t        |       }t        |      }g }d}|j                         D ]k  \  }}|dk(  rt	        |t
              s|j                  dd      }|j                  |dg d      }	|	d   }
||
k7  }|rd}|j                  |||
|	d   |d	       m |j                         D ])  \  }}	||vsd}|j                  |d|	d   |	d   dd	       + ||fS )
u~   
    engine_summary의 count/members ↔ 실제 멤버 카운트 비교.
    반환: (결과_리스트, 불일치_있음)
    engine_summaryFtotalr]   r   r\   TrP   )r   summary_countactual_countactual_membersr   )r0   rV   rb   r/   
isinstancedictrR   )r9   r   rP   actual_countsr   r   	model_keysummary_valr   actual_infor   r   s               r   check_engine_summaryr   b  s3   
 WW-r2N!#&G-g6MGL"0"6"6"8 
	;+t,#3#''	Q23NO"7+ L0L"!. ,"-i"8$	

4 #0"5"5"7 	;N*LNN&%&$/$8&1)&< $ L  r   person_resultsengine_resultsc                    t        d       | D ]c  }|d   }|d   }|d   }|d   }|d   st        d| d| d	| d
| d	       5t        d| d| d	| d
|        |d   D ]  }t        d|         e t        d       |D ]K  }|d   }|d   }	|d   }
|d   st        d| d|	 d|
 d       -t        d| d|	 d|
        t        d       M t        d | D              }|t        d |D              z  }t        d| d       |S )Nu    === 설정 동기화 체크 ===
r~   r   r9   r   r   z[OK] z: bot_settings=z, org_json=z	, memory=u    ✓z[MISMATCH] r   u     → u   
--- engine_summary 검증 ---r   r   r   z
: summary=z	, actual=u"     → engine_summary 수정 필요c              3   ,   K   | ]  }|d    s	d  ywr   r^   Nr   .0rs     r   	<genexpr>z print_results.<locals>.<genexpr>  s     Dqa
mD   
c              3   ,   K   | ]  }|d    s	d  ywr   r   r   s     r   r   z print_results.<locals>.<genexpr>  s     Eq}!Er   u   
=== 결과: u   개 불일치 발견 ===)printsum)r   r   r   r~   bot_sorg_smem_sfixr   s_counta_counttotal_mismatchs               r   print_resultsr     sn   	
-. &'
%%(}E%wk%	RWQXX\]^KwoeWKwiX]W^_`z &sen%&& 

+, 9'
O$N#}E%
7)9WITJKKwj	7)LM689 DNDDNcE^EEEN	N>**B
CDr   c           
         | d   d   d   }d}|D ]  }|j                  d      dk(  s|} n |t        d       | S |D ]  }|d   s	|d	   }|d
   }|t        d |d   D              }	|	s.|dk(  r"|d   d   }
||d   d<   t        d|
 d|        Udddd}|j                  |      }|j                  dg       D ]C  }|j                  d      |k(  s|d   d   }
||d   d<   t        dt        |    d|
 d|           t        d |D              }|rt	        |       }t        |      }| j                  di       }i }|j                         D ]P  \  }}|dk(  rt        |t              s|j                  |dg d      }|d    |d!   |j                  d"d#      d$||<   R |j                         D ]  \  }}||vs|d    |d!   d#d$||<    t        d% |j                         D              }||d<   t        d&| d'       || d<   | S )(u   
    org_json 내 lead.model 수정 + engine_summary 재계산.
    bot_settings.json, MEMORY.md 는 절대 수정하지 않음.
    r;   r<   r=   Nr>   r?   u:   [ERROR] development-office 팀을 찾을 수 없습니다.r   r6   r   c              3   $   K   | ]  }d |v  
 yw)u   org_json 수정 필요Nr   )r   r   s     r   r   zfix_org_json.<locals>.<genexpr>  s     R4;Rs   r   r   r@   r   u"     [FIX] 아누 office_lead.model: r}   rB   rC   rD   rE   rF   rG   rH   z  [FIX] z lead.model: c              3   &   K   | ]	  }|d      yw)r   Nr   r   s     r   r   zfix_org_json.<locals>.<genexpr>  s     AQ1Z=A   r   r   r   r\   r]   rP   role )r]   rP   r   c              3   &   K   | ]	  }|d      yw)r]   Nr   )r   vs     r   r   zfix_org_json.<locals>.<genexpr>  s     =1AgJ=r   u/     [FIX] engine_summary 재계산 완료 (total=))r0   r   anyr   rV   rb   r/   r   r   r   r3   )r9   r   r   r=   rI   rJ   r   r6   r   needs_org_fixoldrK   rG   rL   needs_engine_fixrP   r   current_summarynew_summaryr   valactualr   s                          r   fix_org_jsonr     s    Y'0EJ 88I"66J
 JK
 }8Z= RqzRRU?]+G4C19J}%g.6se5
KL&1;kZL&**62K&NN;; <<.+="6*73C08HV$W-H\&%9$:-uERZQ[\])8 A.AA%c*1': ''"2B7 .335 
	NIsG#c4("&&yA"2MNF!),+&K	"
	 "/!4!4!6 	Iv+#G_%i0*I&	 =(:(:(<==$G?waHI +Jr   c                     t        t        dd      5 }t        j                  | |dd       d d d        t	        dt                y # 1 sw Y   xY w)Nwr   r   F   )ensure_asciiindentz
  [SAVED] )r   r%   r   dumpr   )r9   r!   s     r   save_org_jsonr     sF    	mS7	3 8q		#quQ78	J}o
&'8 8s   AAc                     t        j                  d      } | j                  ddd       | j                         }t	               }t               }t               }t        |      }t        |||      \  }}t        |      \  }}	t        ||      }
|j                  r|
dk(  rt        d       y t        d	       g }|D ]+  }|d
   D ]!  }d|v s|j                  d|d    d|        # - |rt        d       |D ]  }t        |        t        |||      }t        |       t        d       y g }|D ]+  }|d
   D ]!  }d|v s|j                  d|d    d|        # - |rt        d       |D ]  }t        |        y y )NuB   bot_settings / org_json / MEMORY.md 모델 정보 동기화 체크)descriptionz--fix
store_trueuh   불일치 자동 수정 (organization-structure.json + engine_summary만 수정. MEMORY.md는 경고만))actionhelpr   u+   
[INFO] 불일치 없음. 수정 불필요.u   
--- 자동 수정 시작 ---r   u   MEMORY.md 수정 필요z  [WARNING] r~   z: uV   [WARNING] MEMORY.md는 자동 수정되지 않습니다. 수동으로 확인하세요:u   --- 자동 수정 완료 ---z  uP   
[NOTE] MEMORY.md는 자동 수정 대상이 아닙니다. 수동 확인 필요:)argparseArgumentParseradd_argument
parse_argsr"   r&   r*   r8   r   r   r   r   r   rR   r   r   )parserargsr+   r9   rc   r{   r   person_mismatchr   engine_mismatchr   memory_fixesr   r   r   s                  r   mainr      s   $$1uvF
w  
 D %&L
/C I  -J ':*c9&U#NO&:3&?#NO #>>BN xxQ@A./  	LAz L,3 '',qzl"SE(JKL	L jk! a 3?c,-  	BAz B,3 ''"QwZL3%(@AB	B ef! a r   __main__)#__doc__r   r   rm   syspathlibr   r   r%   r(   r.   r   strr   r   r"   r&   r*   r8   tuplelistrM   rV   rb   rr   rw   rz   boolr   r   r   r   r   r   __name__r   r   r   <module>r      s,     	 
 
 < Hd !	  
	s s 4 
t 
  $sCx. $#d #C #E#*d:J4K #R'T 'd4j 'TtDz d39o 4 ! "# "s "sTz "J# s sTz DA!A!	A! A! 4:t	A!N3!d 3!uT$Z-='> 3!r$t* d4j JTd TDJ TT
 TW[ Tn(t (9x zF r   