
    im                        d Z ddlZddlZddlZddlZdZej                  j                  ed      Z	d Z
	  e
       Zej                  Zej                  Zej                  Zej                  Zej                   Zej"                  ZdZej(                  j+                  e d	      Zd
ZdZdZdZdZdZdZdZdZdZ ejB                  d        Z"ejB                  d        Z#ejB                  d        Z$ejB                  d        Z%ejB                  d        Z&ejB                  d        Z'ejB                  d        Z(ejB                  d        Z)ejB                  d        Z* G d d      Z+ G d d       Z, G d! d"      Z- G d# d$      Z. G d% d&      Z/ G d' d(      Z0 G d) d*      Z1 G d+ d,      Z2 G d- d.      Z3y# e$ r dZY 9w xY w)/uT   
TDD 단위 테스트: meeting-audit.py
작성자: 하누만 (개발4팀 테스터)
    Nz/home/jay/workspace/scriptszmeeting-audit.pyc                     t         j                  j                  dt              } | J dt                t         j                  j	                  |       }| j
                  J d       | j
                  j                  |       |S )Nmeeting_auditzCannot load spec from zspec.loader is None)	importlibutilspec_from_file_location_MODULE_PATHmodule_from_specloaderexec_module)specmods     I/home/jay/workspace/.worktrees/task-2116-dev1/tests/test_meeting_audit.py_load_meeting_auditr      sr    >>11/<PDD5l^DD
..
)
)$
/C;;"9$99"KKC J    TFu?   meeting-audit.py 모듈이 아직 구현되지 않았습니다.reasonzJ/home/jay/workspace/memory/meetings/2026-04-11-insuwiki-review-trust-ux.mdzC/home/jay/workspace/skills/agent-meeting/references/persona-list.mduj  # Agent 미팅: 테스트용 미팅

**날짜**: 2026-04-11
**소집 이유**: 테스트
**참여 페르소나**: 토르 (Thor), 로키 (Loki)
**미팅 모드**: sync
**토론 깊이**: normal
**총 사이클 수**: 3

## Cycle 1

내용 1

## Cycle 2

내용 2

## Cycle 3

내용 3

## 3문서 반영

계획서와 맥락노트, 체크리스트 반영 완료.
u}  # Agent 미팅: DA 포함 테스트

**날짜**: 2026-04-11
**소집 이유**: DA 테스트
**참여 페르소나**: 토르 (Thor), 로키 (Loki)
**미팅 모드**: hybrid
**토론 깊이**: thorough
**총 사이클 수**: 3

## Cycle 1

내용 1

## Cycle 2

내용 2

## Cycle 3 — Devil's Advocate

### Devil's Advocate

**지정**: 로키

1. **실패 시나리오**: 시스템 실패 가능성 분석
2. **후회 이유**: 현재 접근법의 후회 요소
3. **더 단순한 대안**: 단순한 대안 제안

**반박**: 위 우려에 대한 팀의 반박 내용.
**판정**: 반박 수용. DA 우려 대응책 설계에 포함.
u  # Agent 미팅: DA 없는 테스트

**날짜**: 2026-04-11
**소집 이유**: DA 없음 테스트
**참여 페르소나**: 토르 (Thor), 로키 (Loki)
**미팅 모드**: sync
**토론 깊이**: normal
**총 사이클 수**: 2

## Cycle 1

내용 1

## Cycle 2

내용 2
u!  # Agent 미팅: 미등록 페르소나 테스트

**날짜**: 2026-04-11
**소집 이유**: 미등록 페르소나 테스트
**참여 페르소나**: 엔키(백엔드), 이쉬타르(프론트엔드), 로키 (Loki)
**미팅 모드**: sync
**토론 깊이**: normal
**총 사이클 수**: 1
u   # Agent 미팅: 로키 없는 테스트

**날짜**: 2026-04-11
**소집 이유**: 로키 없음 테스트
**참여 페르소나**: 토르 (Thor), 미미르 (Mimir)
**미팅 모드**: sync
**토론 깊이**: normal
**총 사이클 수**: 1
u:  # Agent 미팅: 3문서 반영 테스트

**날짜**: 2026-04-11
**소집 이유**: 3문서 테스트
**참여 페르소나**: 토르 (Thor), 로키 (Loki)
**미팅 모드**: sync
**토론 깊이**: normal
**총 사이클 수**: 1

## 3문서 반영

계획서, 맥락노트, 체크리스트 모두 반영 완료.
u$  # Agent 미팅: 3문서 미언급 테스트

**날짜**: 2026-04-11
**소집 이유**: 3문서 미언급 테스트
**참여 페르소나**: 토르 (Thor), 로키 (Loki)
**미팅 모드**: sync
**토론 깊이**: normal
**총 사이클 수**: 1

## 합의 사항

아무 문서 언급 없음.
u  # 페르소나 목록

| 페르소나 | 팀 | 전문성 관점 |
|---------|-----|-----------|
| 토르 (Thor) | 개발2팀 / 백엔드 | 고성능 서버 |
| 불칸 (Vulcan) | 개발1팀 / 백엔드 | API 설계 |
| 프레이야 (Freya) | 개발2팀 / 프론트 | 인터랙티브 UI |
| 이리스 (Iris) | 개발1팀 / 프론트 | 컴포넌트 설계 |
| 미미르 (Mimir) | 개발2팀 / UX | 데이터 기반 UX |
| 아테나 (Athena) | 개발1팀 / UX | 유저 플로우 |
| 헤임달 (Heimdall) | 개발2팀 / 테스트 | 보안 중심 QA |
| 아르고스 (Argos) | 개발1팀 / 테스트 | 엣지 케이스 |
| 로키 (Loki) | 레드팀 | 보안 취약점 |
| 야누스 (Janus) | DevOps 센터 | 인프라 |
| 마아트 (Ma'at) | QC 센터 | 독립 품질 검증 |
| 비너스 (Venus) | 디자인 센터 | 디자인 방향성 |
| 오딘 (Odin) | 개발2팀장 | 아키텍처 |
| 헤르메스 (Hermes) | 개발1팀장 | 풀스택 |
c                 P    | dz  }|j                  t        d       t        |      S )Nzpersona-list.mdutf-8encoding)
write_textPERSONA_LIST_CONTENTstr)tmp_pathps     r   tmp_persona_listr      s'    $$ALL%L8q6Mr   c                 P    | dz  }|j                  t        d       t        |      S )Nzminimal-meeting.mdr   r   )r   MINIMAL_MEETING_CONTENTr   r   fs     r   minimal_meetingr!      s'    ''ALL(7L;q6Mr   c                 P    | dz  }|j                  t        d       t        |      S )Nzda-meeting.mdr   r   )r   DA_MEETING_CONTENTr   r   s     r   
da_meetingr$      s&    ?"ALL#gL6q6Mr   c                 P    | dz  }|j                  t        d       t        |      S )Nzno-da-meeting.mdr   r   )r   NO_DA_MEETING_CONTENTr   r   s     r   no_da_meetingr'      s'    %%ALL&L9q6Mr   c                 P    | dz  }|j                  t        d       t        |      S )Nzunreg-persona-meeting.mdr   r   )r   UNREGISTERED_PERSONA_CONTENTr   r   s     r   unregistered_persona_meetingr*      s'    --ALL-L@q6Mr   c                 P    | dz  }|j                  t        d       t        |      S )Nzno-loki-meeting.mdr   r   )r   NO_LOKI_CONTENTr   r   s     r   no_loki_meetingr-      s&    ''ALL7L3q6Mr   c                 P    | dz  }|j                  t        d       t        |      S )Nzthree-docs-meeting.mdr   r   )r   THREE_DOCS_CONTENTr   r   s     r   three_docs_meetingr0      s'    **ALL#gL6q6Mr   c                 P    | dz  }|j                  t        d       t        |      S )Nzno-three-docs-meeting.mdr   r   )r   NO_THREE_DOCS_CONTENTr   r   s     r   no_three_docs_meetingr3     s'    --ALL&L9q6Mr   c                 H    | dz  }|j                  dd       t        |      S )Nzempty-meeting.md r   r   )r   r   r   s     r   empty_meetingr6   	  s&    %%ALLgL&q6Mr   c                   *    e Zd Zd Zd Zd Zd Zd Zy)TestParseMeetingFilec                     t        t              }t        |t              sJ |d   dk(  sJ |d   dk(  sJ |d   dk(  sJ d|v sJ t        |d   t              sJ t        |d         d	k\  sJ y
)uB   실제 미팅 파일을 파싱하여 메타데이터 추출 확인total_cycles   modehybriddepththoroughcontentpersonas   N)parse_meeting_fileREAL_MEETING_FILE
isinstancedictlistlen)selfresults     r   test_parse_real_meeting_filez1TestParseMeetingFile.test_parse_real_meeting_file  s    #$56&$'''n%***f~)))g*,,,F"""&,d3336*%&!+++r   c                 D    t        |      }dD ]  }||v rJ d|         y)u9   파싱 결과에 필수 키가 모두 포함되어야 함r:   rA   r<   r>   r@      필수 키 누락: NrC   rI   r!   rJ   keys       r    test_parse_returns_required_keysz5TestParseMeetingFile.test_parse_returns_required_keys"  s4    #O4K 	>C&==$7u"===	>r   c                 X    t        |      }t        |d   t              sJ |d   dk(  sJ y)u2   총 사이클 수가 정수로 파싱되어야 함r:      N)rC   rE   intrI   r!   rJ   s      r   test_parse_cycle_count_integerz3TestParseMeetingFile.test_parse_cycle_count_integer(  s4    #O4&0#666n%***r   c                 D    t        |      }t        |d   t              sJ y)u)   personas가 리스트 타입이어야 함rA   N)rC   rE   rG   rV   s      r   test_parse_personas_listz-TestParseMeetingFile.test_parse_personas_list.  s!    #O4&,d333r   c                 (    t        |      }|d   sJ y)u-   content 필드가 비어 있지 않아야 함r@   NrO   rV   s      r   test_parse_content_not_emptyz1TestParseMeetingFile.test_parse_content_not_empty3  s    #O4i   r   N)__name__
__module____qualname__rK   rR   rW   rY   r[    r   r   r8   r8     s    
,>+4
!r   r8   c                   @    e Zd ZdedefdZd Zd Zd Zd Z	d Z
d	 Zy
)TestCheckCycleCountcyclesreturnc                     |g ddddS )Nsyncnormalr5   rM   r_   )rI   rb   s     r   _make_parsedz TestCheckCycleCount._make_parsed?  s    "
 	
r   c                 |    | j                  d      }t        |d      }|d   dk(  sJ |d   dk(  sJ |d   dk(  sJ y)	u   Lv.2 + 2사이클 → PASSr;   levelstatusPASSactualexpected_minrB   Nrg   check_cycle_countrI   parsedrJ   s      r   test_check_cycle_count_passz/TestCheckCycleCount.test_check_cycle_count_passH  sW    ""1%"63h6)))h1$$$n%***r   c                     | j                  d      }t        |d      }|d   dk(  sJ |d   dk(  sJ |d   dk(  sJ d	|v sJ y
)u+   Lv.4 + 2사이클 → FAIL (expected_min=3)r;      ri   rk   FAILrm   rn   rT   messageNro   rq   s      r   test_check_cycle_count_failz/TestCheckCycleCount.test_check_cycle_count_failQ  se    ""1%"63h6)))h1$$$n%***F"""r   c                 T    | j                  d      }t        |d      }|d   dk(  sJ y)u7   Lv.1 → 사이클 수 체크 안 함 → PASS (스킵)r   rB   ri   rk   rl   Nro   rq   s      r   test_check_cycle_count_lv1_skipz3TestCheckCycleCount.test_check_cycle_count_lv1_skip[  s1    ""1%"63h6)))r   c                 |    | j                  d      }t        |d      }|d   dk(  sJ |d   dk(  sJ |d   dk(  sJ y)	uA   Lv.3 + 2사이클 (경계값) → PASS (expected_min=2, actual=2)r;   rT   ri   rk   rl   rn   rm   Nro   rq   s      r   )test_check_cycle_count_lv3_exact_boundaryz=TestCheckCycleCount.test_check_cycle_count_lv3_exact_boundaryb  W    ""1%"63h6)))n%***h1$$$r   c                 |    | j                  d      }t        |d      }|d   dk(  sJ |d   dk(  sJ |d   dk(  sJ y	)
u5   Lv.3 + 1사이클 → FAIL (expected_min=2, actual=1)rB   rT   ri   rk   rv   rn   r;   rm   Nro   rq   s      r   'test_check_cycle_count_lv3_insufficientz;TestCheckCycleCount.test_check_cycle_count_lv3_insufficientk  r}   r   c                 L    | j                  d      }t        |d      }d|v sJ y)u3   결과에 message 키가 항상 포함되어야 함rB   r;   ri   rw   Nro   rq   s      r   )test_check_cycle_count_result_has_messagez=TestCheckCycleCount.test_check_cycle_count_result_has_messaget  s,    ""1%"63F"""r   N)r\   r]   r^   rU   rF   rg   rs   rx   rz   r|   r   r   r_   r   r   ra   ra   >  s3    
3 
4 
+#*%%#r   ra   c                   @    e Zd ZdedefdZd Zd Zd Zd Z	d Z
d	 Zy
)TestCheckPersonaValidationrA   rc   c                     d|ddddS )NrB   re   rf   r5   rM   r_   )rI   rA   s     r   rg   z'TestCheckPersonaValidation._make_parsed  s     
 	
r   c                     | j                  ddg      }t        ||      }|d   dk(  sJ |d   g k(  sJ t        |d   t              sJ t	        |d         dk\  sJ y)	u=   등록된 페르소나만 → PASS, unregistered 비어있음   토르 (Thor)   로키 (Loki)rk   rl   unregistered
registeredrB   N)rg   check_persona_validationrE   rG   rH   rI   r   rr   rJ   s       r   test_check_persona_registeredz8TestCheckPersonaValidation.test_check_persona_registered  sw    ""O_#EF)&2BCh6)))n%+++&.5556,'(A---r   c                     | j                  ddg      }t        ||      }|d   dk(  sJ t        |d         dk\  sJ ddj                  |d         v st	        d	 |d   D              sJ y
y
)u&   미등록 페르소나 존재 → WARNu   엔키(백엔드)r   rk   WARNr   rB      엔키 c              3   $   K   | ]  }d |v  
 yw)r   Nr_   ).0us     r   	<genexpr>zMTestCheckPersonaValidation.test_check_persona_unregistered.<locals>.<genexpr>  s     BqUV8q=Bq   N)rg   r   rH   joinanyr   s       r   test_check_persona_unregisteredz:TestCheckPersonaValidation.test_check_persona_unregistered  s    ""$7#IJ)&2BCh6)))6.)*a///388F>$:;;sBqZ`aoZpBq?qqq?q;r   c                 h    | j                  ddg      }t        ||      }|d   dk(  sJ |d   du sJ y)u   로키 미참석 → FAILr   u   미미르 (Mimir)rk   rv   loki_presentFNrg   r   r   s       r   test_check_persona_loki_missingz:TestCheckPersonaValidation.test_check_persona_loki_missing  sK    ""O5H#IJ)&2BCh6)))n%...r   c                 T    | j                  ddg      }t        ||      }|d   du sJ y)u#   로키 참석 → loki_present=Truer   r   r   TNr   r   s       r   test_check_persona_loki_presentz:TestCheckPersonaValidation.test_check_persona_loki_present  s7    ""O_#EF)&2BCn%---r   c                 l    | j                  ddg      }t        ||      }dD ]  }||v rJ d|         y)"   결과에 필수 키 포함 확인r   r   )rk   r   r   r   rN   Nr   )rI   r   rr   rJ   rQ   s        r   +test_check_persona_result_has_required_keyszFTestCheckPersonaValidation.test_check_persona_result_has_required_keys  sL    ""O_#EF)&2BCK 	>C&==$7u"===	>r   c                     t        t              }t        |t              }|d   dk(  sJ |d   du sJ t	        |d         dk\  sJ y)uH   실제 미팅 파일: 로키 미참석 + 미등록 페르소나 → FAILrk   rv   r   Fr   rB   N)rC   rD   r   DEFAULT_PERSONA_LISTrH   rq   s      r   $test_check_persona_real_meeting_filez?TestCheckPersonaValidation.test_check_persona_real_meeting_file  sX    #$56)&2FGh6)))n%...6.)*a///r   N)r\   r]   r^   rG   rF   rg   r   r   r   r   r   r   r_   r   r   r   r     s4    
T 
d 
.r/.>0r   r   c                   B    e Zd Zd Zd Zd Zd Zd Zd Zd Z	d Z
d	 Zy
)TestCheckDAc                 \    t        |      }t        |d      }|d   dk(  sJ |d   dk\  sJ y)u   Lv.3 + DA 존재 → PASSrT   ri   rk   rl   da_sections_foundrB   NrC   check_darI   r$   rr   rJ   s       r   test_check_da_required_presentz*TestCheckDA.test_check_da_required_present  s?    #J/&*h6))))*a///r   c                 \    t        |      }t        |d      }|d   dk(  sJ |d   dk(  sJ y)u   Lv.3 + DA 미존재 → FAILrT   ri   rk   rv   r   r   Nr   rI   r'   rr   rJ   s       r   test_check_da_required_missingz*TestCheckDA.test_check_da_required_missing  s?    #M2&*h6))))*a///r   c                 H    t        |      }t        |d      }|d   dk(  sJ y)u(   Lv.2 + DA 미존재 → PASS (선택적)r;   ri   rk   rl   Nr   r   s       r   test_check_da_optional_lv2z&TestCheckDA.test_check_da_optional_lv2  +    #M2&*h6)))r   c                 H    t        |      }t        |d      }|d   dk(  sJ y)u(   Lv.1 + DA 미존재 → PASS (선택적)rB   ri   rk   rl   Nr   r   s       r   test_check_da_optional_lv1z&TestCheckDA.test_check_da_optional_lv1  r   r   c                 F    t        |      }t        |d      }|d   du sJ y)u=   DA 3대 질문 (실패/후회/단순한 대안) 존재 확인rT   ri   three_questionsTNr   r   s       r   test_check_da_three_questionsz)TestCheckDA.test_check_da_three_questions  s,    #J/&*'(D000r   c                 F    t        |      }t        |d      }|d   du sJ y)u   반박 존재 확인rT   ri   rebuttal_foundTNr   r   s       r   test_check_da_rebuttal_foundz(TestCheckDA.test_check_da_rebuttal_found  s,    #J/&*&'4///r   c                 F    t        |      }t        |d      }|d   du sJ y)u   판정 존재 확인rT   ri   verdict_foundTNr   r   s       r   test_check_da_verdict_foundz'TestCheckDA.test_check_da_verdict_found  s+    #J/&*o&$...r   c                 ^    t        |      }t        |d      }dD ]  }||v rJ d|         y)r   rT   ri   )rk   r   r   r   r   rN   Nr   )rI   r$   rr   rJ   rQ   s        r   &test_check_da_result_has_required_keysz2TestCheckDA.test_check_da_result_has_required_keys  s@    #J/&*h 	>C&==$7u"===	>r   c                     t        t              }t        |d      }|d   dk(  sJ |d   dk\  sJ |d   du sJ |d	   du sJ |d
   du sJ y)uO   실제 미팅 파일: DA 섹션 존재 + 3대 질문 + 반박 + 판정 → PASSru   ri   rk   rl   r   rB   r   Tr   r   N)rC   rD   r   rq   s      r   test_check_da_real_meeting_filez+TestCheckDA.test_check_da_real_meeting_file  s{    #$56&*h6))))*a///'(D000&'4///o&$...r   N)r\   r]   r^   r   r   r   r   r   r   r   r   r   r_   r   r   r   r     s/    00**10/>	/r   r   c                   6    e Zd Zd Zd Zd Zd Zd Zd Zd Z	y)	TestCheckThreeDocsc                 V    t        |      }t        |      }|d   dk(  sJ |d   du sJ y)u8   '3문서 반영' 또는 관련 키워드 언급 → PASSrk   rl   	mentionedTNrC   check_three_docsrI   r0   rr   rJ   s       r   test_check_three_docs_mentionedz2TestCheckThreeDocs.test_check_three_docs_mentioned  s=    #$67!&)h6)))k"d***r   c                 V    t        |      }t        |      }|d   dk(  sJ |d   du sJ y)u   3문서 미언급 → WARNrk   r   r   FNr   )rI   r3   rr   rJ   s       r   #test_check_three_docs_not_mentionedz6TestCheckThreeDocs.test_check_three_docs_not_mentioned  s=    #$9:!&)h6)))k"e+++r   c                 J    t        |      }d}t        ||      }|d   du sJ y)u4   task-id 제공 + 경로 없음 → files_exist=FalsezNONEXISTENT-TASK-99999task_idfiles_existFNr   )rI   r0   rr   fake_task_idrJ   s        r   )test_check_three_docs_with_task_id_no_dirz<TestCheckThreeDocs.test_check_three_docs_with_task_id_no_dir!  s3    #$67/!&,? m$---r   c                     d}|dz  |z  }|j                  d       |dz  j                  d       |dz  j                  d       |d	z  j                  d
       t        |      }t        ||      }|d   J y)uH   task-id 제공 + 경로 존재 → files_exist=True 또는 확인 가능zTEST-TASK-0013docsT)parentszplan.mdu	   계획서z
context.mdu   맥락노트zchecklist.mdu   체크리스트r   r   N)mkdirr   rC   r   )rI   r0   r   r   docs_dirrr   rJ   s          r   /test_check_three_docs_with_task_id_existing_dirzBTestCheckThreeDocs.test_check_three_docs_with_task_id_existing_dir*  s     "g%/t$	I	))+6	L	 ,,^<	N	"../@A#$67 "&':m$000r   c                 Z    t        |      }t        |      }dD ]  }||v rJ d|         y)r   )rk   r   r   rN   Nr   )rI   r0   rr   rJ   rQ   s        r   .test_check_three_docs_result_has_required_keyszATestCheckThreeDocs.test_check_three_docs_result_has_required_keys?  s?    #$67!&)9 	>C&==$7u"===	>r   c                 B    t        |      }t        |d      }|d   J y)u"   task-id 없으면 files_exist=NoneNr   r   r   r   s       r   1test_check_three_docs_no_task_id_files_exist_nonezDTestCheckThreeDocs.test_check_three_docs_no_task_id_files_exist_noneG  s*    #$67!&$7m$,,,r   c                 ^    t        t              }t        |      }|d   dk(  sJ |d   du sJ y)u;   실제 미팅 파일: 3문서 반영 언급 없음 → WARNrk   r   r   FN)rC   rD   r   rq   s      r   'test_check_three_docs_real_meeting_filez:TestCheckThreeDocs.test_check_three_docs_real_meeting_fileN  s=    #$56!&)h6)))k"e+++r   N)
r\   r]   r^   r   r   r   r   r   r   r   r_   r   r   r   r     s%    +,.1*>-,r   r   c                   $    e Zd Zd Zd Zd Zd Zy)TestRunAuditFullc                 l    t        |d      }t        |t              sJ dD ]  }||v rJ d|         y)uE   전체 감사 실행 결과가 올바른 JSON 구조를 가져야 함rT   ri   cycle_countpersona_validationda_check
three_docsu   감사 결과에 키 누락: N	run_auditrE   rF   rP   s       r   "test_run_audit_full_json_structurez3TestRunAuditFull.test_run_audit_full_json_structure]  sH    ?!4&$'''R 	HC&=G$A#"GG=	Hr   c                     t        |d      }dD ]/  }d||   v s
J | d       ||   d   dv rJ | d||   d            y)	u)   각 섹션에 status 키가 있어야 함r;   ri   r   rk   u   에 status 누락rl   r   rv   u    .status가 유효하지 않음: N)r   )rI   r!   rJ   sections       r   &test_run_audit_each_section_has_statusz7TestRunAuditFull.test_run_audit_each_section_has_statuse  s    ?!4V 	WGvg.M7);L0MM.'?8, 1  W :6'?8;T:UV	W 	Wr   c                 D    t        |dd      }t        |t              sJ y)uA   task_id 파라미터 전달 시 에러 없이 실행되어야 함r;   zTASK-TEST-001)rj   r   Nr   rV   s      r   test_run_audit_with_task_idz,TestRunAuditFull.test_run_audit_with_task_idq  s     ?!_M&$'''r   c                 l    t        |d      }t        j                  |d      }t        |      dkD  sJ y)u)   결과가 JSON 직렬화 가능해야 함r;   ri   Fensure_asciir   N)r   jsondumpsrH   )rI   r!   rJ   json_strs       r   #test_run_audit_serializable_to_jsonz4TestRunAuditFull.test_run_audit_serializable_to_jsonv  s0    ?!4::f598}q   r   N)r\   r]   r^   r   r   r   r   r_   r   r   r   r   \  s    H
W(
!r   r   c                       e Zd Zd Zd Zy)TestEmptyMeetingFilec                     	 t        |      }|*|j                  dd      dk(  s|j                  d      J yyy# t        t        t        f$ r Y yw xY w)u2   빈 파일 → 적절한 에러 또는 전체 FAILNr:   r   )rC   get
ValueErrorKeyErrorAttributeError)rI   r6   rJ   s      r   test_empty_meeting_filez,TestEmptyMeetingFile.test_empty_meeting_file  sd    	'6F !zz.!49VZZ=W=___=_9 "Hn5 		s   5: AAc                 <   	 t        |d      }|ht        |t              rW|j                         D cg c])  }t        |t              sd|v s|j	                  d      + }}t        d |D              sJ yyyc c}w # t        t        t        t        f$ r Y yw xY w)u5   빈 파일로 run_audit 실행 시 FAIL 또는 예외r;   ri   Nrk   c              3   $   K   | ]  }|d v  
 yw))rv   r   Nr_   )r   ss     r   r   zDTestEmptyMeetingFile.test_empty_meeting_run_audit.<locals>.<genexpr>  s     CQ1 00Cr   )
r   rE   rF   valuesr   r   r   r   r   FileNotFoundError)rI   r6   rJ   vstatusess        r   test_empty_meeting_run_auditz1TestEmptyMeetingFile.test_empty_meeting_run_audit  s    	}A6F!j&>5;]]_n
STVZH[`hlm`mAEE(OnnC(CCCC '?!n Hn6GH 		s.   1A? A:	A:A:!A? :A? ?BBN)r\   r]   r^   r   r  r_   r   r   r   r     s    	
r   r   c                       e Zd Zd Zd Zy)TestNonexistentFilec                    d}	 t        |      }|t        |t              rd|v sJ yy# t        $ r Y yt        $ rJ}dt        |      j                         v s%dt        |      j                         v sY d}~yY d}~yY d}~yd}~ww xY w)uJ   존재하지 않는 파일 파싱 → FileNotFoundError 또는 에러 dict(/home/jay/workspace/nonexistent-12345.mdNerrorz	not foundzno such file)rC   rE   rF   r  	Exceptionr   lower)rI   	fake_pathrJ   es       r   test_nonexistent_file_parsez/TestNonexistentFile.test_nonexistent_file_parse  s    >		]'	2F>j&>7fCTUUCT>  	 	]#a&,,.0Nc!flln4TX\4T0	]s   #) 	BB6BBc                     d}	 t        |d      }|t        |t              rd|v sJ yy# t        $ r Y yt        $ r Y yw xY w)uP   존재하지 않는 파일로 run_audit → FileNotFoundError 또는 에러 dictr	  r;   ri   Nr
  )r   rE   rF   r  r  )rI   r  rJ   s      r   test_nonexistent_file_run_auditz3TestNonexistentFile.test_nonexistent_file_run_audit  sU    >		y2F>j&>7fCTUUCT>  	 		s   %+ 	AA AN)r\   r]   r^   r  r  r_   r   r   r  r    s    ]r   r  c                   z   e Zd Zej                  j                  ej                  j                  e	       d      d        Z
ej                  j                  ej                  j                  e	       d      d        Zej                  j                  ej                  j                  e	       d      d        Zy)TestRunAuditRealFileu2   실제 미팅 파일이 존재하지 않습니다.r   c                    t        t        d      }t        |t              sJ |d   }|d   dk(  sJ d|d           |d   dk(  sJ |d	   d
k(  sJ |d   }|d   dk(  sJ d|d           |d   du sJ t	        |d         dk\  sJ |d   }|d   dk(  sJ d|d           |d   dk\  sJ |d   du sJ |d   du sJ |d   du sJ |d   }|d   dk(  sJ d|d           |d   du sJ y)uX  
        실제 미팅 파일 + --level 4 기준 검증:
        - cycle_count: FAIL (actual=2, expected_min=3)
        - persona_validation: FAIL (로키 미참석 + 미등록 페르소나 존재)
        - da_check: PASS (DA 섹션, 3대 질문, 반박, 판정 모두 존재)
        - three_docs: WARN (3문서 반영 언급 없음)
        ru   ri   r   rk   rv   z cycle_count should be FAIL, got rm   r;   rn   rT   r   z'persona_validation should be FAIL, got r   Fr   rB   r   rl   zda_check should be PASS, got r   r   Tr   r   r   r   zthree_docs should be WARN, got r   N)r   rD   rE   rF   rH   )rI   rJ   ccpvdatds         r   test_run_audit_real_filez-TestRunAuditRealFile.test_run_audit_real_file  s    ,A6&$''' M"(|v%X)I"X,'XX%(|q   .!Q&&& ()(|v%_)PQST\Q]P^'__%.!U***2n%&!+++ J(|v%U)Fr(|n'UU%%&!+++#$,,,"#t+++/"d*** L!(|v%W)HH'WW%+%'''r   c                 X    t        t        d      }|d   }|d   dk(  sJ |d   dk(  sJ y)uC   실제 미팅 파일 + Lv.2: cycle_count PASS (2사이클 >= min 1)r;   ri   r   rk   rl   rm   N)r   rD   )rI   rJ   r  s      r   test_run_audit_real_file_lv2z1TestRunAuditRealFile.test_run_audit_real_file_lv2  s?     ,A6M"(|v%%%(|q   r   c                     t        t        d      }t        j                  |d      }t	        |      dkD  sJ t        j
                  |      }|d   d   dv sJ y	)
uE   실제 미팅 파일 감사 결과가 JSON 직렬화 가능해야 함rT   ri   Fr   r   r   rk   r   N)r   rD   r   r   rH   loads)rI   rJ   r   restoreds       r   *test_run_audit_real_file_json_serializablez?TestRunAuditRealFile.test_run_audit_real_file_json_serializable  sZ     ,A6::f598}q   ::h'&x04LLLLr   N)r\   r]   r^   pytestmarkskipifospathexistsrD   r  r  r  r_   r   r   r  r    s    [[BGGNN+<==Fz{#( |#(J [[BGGNN+<==Fz{! |! [[BGGNN+<==Fz{M |Mr   r  )4__doc__importlib.utilr   r   r#  r   _SCRIPTS_DIRr$  r   r   r   r   rC   rp   r   r   r   r   _MODULE_AVAILABLEr  r!  r"  
pytestmarkrD   r   r   r#   r&   r)   r,   r/   r2   r   fixturer   r!   r$   r'   r*   r-   r0   r3   r6   r8   ra   r   r   r   r   r   r  r  r_   r   r   <module>r,     s[  
   	 
 -ww||L*<=
')M&99%77,EE%%H$55''I [[$5 5>  A

 a \ 
 6 @ &	  	   6                  !! !!R:# :#D;0 ;0FE/ E/ZD, D,X! !L < D8M 8My  s   AF5 5G ?G 