
    i,                     6   d Z ddlZddlmc mZ ddlZddlZddl	Z	ddl
mZ ddlZej                  j                  dd       ddlmZ  e	j"                  d      Z e	j"                  d      Zdded	ed
efdZdded	ed
efdZd Zd Zd Zd Zd Zd Zd Zd Zy)uy   Progressive Disclosure 레이어 기능 테스트

TC13 ~ TC20: search() layer 파라미터 및 get_by_ids() API 검증.
    N)Pathz/home/jay/workspace)MemoryIndexeruc      ---
    date: "2026-04-05"
    session: 1
    team_id: "dev3"
    task_id: "task-9999"
    tags: [auto-compact, pre-compact]
    auto_generated: true
    ---
    ## 수행한 작업
    - 메모리 인덱서 TDD RED phase 작성
    - SQLite FTS5 테이블 설계 검토

    ## 피드백 및 수정 지시
    - 한국어 검색 성능 확인 필요
u      ---
    name: 위임 규칙 종합
    description: 파일 기반 위임, 논리적 팀, 한정승인 등
    type: feedback
    team_id: "dev3"
    ---
    ### 파일 기반 위임 (절대 규칙)
    - 지시 내용 → 파일 작성 → `--task-file`로 전달.
    - 100자 이내만 `--task` 허용.

    ### 논리적 팀
    - 마케팅/컨설팅/출판/디자인 라우팅 규칙 준수.
	directoryfilenamereturnc                 >    | |z  }|j                  t        d       |S )u+   임시 디렉토리에 diary 파일 생성.utf-8encoding)
write_textDIARY_CONTENTr   r   fs      4/home/jay/workspace/tests/test_memory_progressive.pymake_diary_filer   6   s!    HALLL1H    c                 >    | |z  }|j                  t        d       |S )u,   임시 디렉토리에 memory 파일 생성.r	   r
   )r   MEMORY_CONTENTr   s      r   make_memory_filer   =   s!    HALL'L2Hr   c                 	   t        | dz        }t        |       }t        |      }	 |j                  t        |             |j	                  dd      }|j                          t        |t              }|s!t        j                  d      dz   dt        j                         v st        j                  t              rt        j                  t              ndd	t        j                         v st        j                  |      rt        j                  |      nd	d
t        j                         v st        j                  t              rt        j                  t              nd
t        j                  |      dz  }t        t        j                  |            d}t!        |      }d}||kD  }	|	st        j"                  d|	fd||f      dt        j                         v st        j                  t               rt        j                  t               ndd	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      t        j                  |      dz  }
t        j                  d      dz   d|
iz  }t        t        j                  |            dx}x}	}h d}h d}|D ]  }|D ]  }||v }|st        j"                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d| dt        |j%                                      dz   d|iz  }t        t        j                  |            d} |D ]  }||v}|st        j"                  d |fd!||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d"| d#t        |j%                                      dz   d|iz  }t        t        j                  |            d}  y# |j                          w xY w)$uS   layer='index' 검색 결과에는 id, title, type, score만 포함되어야 한다.test.dbdb_path   위임 규칙indexlayer3   search()가 리스트를 반환하지 않습니다.7
>assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstanceresultslistpy0py1py2py4Nr   >z/%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} > %(py6)slenr$   r%   py3py6u2   layer='index' 검색 결과가 비어있습니다.
>assert %(py8)spy8>   idtypescoretitle>   tagssnippetteam_id	file_pathinz%(py0)s in %(py2)sfielditemr$   r&   u'   layer='index' 결과에 필수 필드 '   '가 없습니다: 
>assert %(py4)sr'   not inz%(py0)s not in %(py2)su;   layer='index' 결과에 포함되어서는 안 될 필드 '   '가 있습니다: )strr   r   
index_filesearchcloser    r"   
@pytest_ar_format_assertmsg@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationr+   _call_reprcomparekeys)tmp_pathr   mem_fileindexerr!   @py_assert3@py_format5@py_assert2@py_assert5@py_assert4@py_format7@py_format9required_fieldsforbidden_fieldsr=   r<   @py_assert1@py_format3s                     r   test_TC13_layer_index_fieldsra   I   sW   (Y&'G)HG,G3x=)...@gt$[$[[&[[[[[[[:[[[:[[[[[[g[[[g[[[[[[t[[[t[[[$[[[[[[w<Q!Q<!QQQ<!QQQQQQ3QQQ3QQQQQQwQQQwQQQ<QQQ!QQQQQQQQQQQ6OB {$ 	zED=yyy5Dyyyyyy5yyy5yyyyyyDyyyDyyyy$KE7Refjkoktktkvfwex"yyyyyyy	z% 	{ET!{iziz{T{ {tztz{ {bzbz { {qzqz { {tztz{ {bzbz "{ {qzqz "{ {izizLUGSfgklplululwgxfyz{ { {gzgz{ {	{{ 	s   -S' 'S9c                    t        | dz        }t        |       }t        |      }	 |j                  t        |             |j	                  dd      }|j                          t        |t              }|s!t        j                  d      dz   dt        j                         v st        j                  t              rt        j                  t              ndd	t        j                         v st        j                  |      rt        j                  |      nd	d
t        j                         v st        j                  t              rt        j                  t              nd
t        j                  |      dz  }t        t        j                  |            d}t!        |      }d}||kD  }	|	st        j"                  d|	fd||f      dt        j                         v st        j                  t               rt        j                  t               ndd	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      t        j                  |      dz  }
t        j                  d      dz   d|
iz  }t        t        j                  |            dx}x}	}h d}h d}|D ]_  }|D ]  }||v }|st        j"                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d| dt        |j%                                      dz   d|iz  }t        t        j                  |            d} |D ]  }||v}|st        j"                  d |fd!||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d"| d#t        |j%                                      dz   d|iz  }t        t        j                  |            d} |j'                  d$d%      }t!        |      }d&}||k  }	|	st        j"                  d'|	fd(||f      dt        j                         v st        j                  t               rt        j                  t               ndd$t        j                         v st        j                  |      rt        j                  |      nd$t        j                  |      t        j                  |      dz  }
t        j                  d)t!        |       d*|      dz   d|
iz  }t        t        j                  |            dx}x}	}b y# |j                          w xY w)+u   layer='summary' 결과에는 id, title, type, score, snippet이 있어야 하고
    snippet은 50자 이하여야 한다. file_path, team_id, tags는 없어야 한다.r   r   r   summaryr   r   r   r    r!   r"   r#   Nr   r(   r*   r+   r,   u4   layer='summary' 검색 결과가 비어있습니다.r/   r0   >   r1   r2   r3   r4   r6   >   r5   r7   r8   r9   r;   r<   r=   r>   u)   layer='summary' 결과에 필수 필드 'r?   r@   r'   rA   rC   u=   layer='summary' 결과에 포함되어서는 안 될 필드 'rD   r6    2   <=)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} <= %(py6)su5   layer='summary' snippet이 50자를 초과합니다: u   자 → )rE   r   r   rF   rG   rH   r    r"   rI   rJ   rK   rL   rM   rN   rO   rP   r+   rQ   rR   get)rS   r   rT   rU   r!   rV   rW   rX   rY   rZ   r[   r\   r]   r^   r=   r<   r_   r`   r6   s                      r   test_TC14_layer_summary_fieldsri   i   s    (Y&'G)HG,G3x=)..	.Bgt$[$[[&[[[[[[[:[[[:[[[[[[g[[[g[[[[[[t[[[t[[[$[[[[[[w<S!S<!SSS<!SSSSSS3SSS3SSSSSSwSSSwSSS<SSS!SSSSSSSSSSSAO7 }$ 	|ED={{{5D{{{{{{5{{{5{{{{{{D{{{D{{{{$MeWTghlmqmvmvmxhygz"{{{{{{{	|% 	}ET!}k|k|}T} }v|v|} }d|d| } }s|s| } }v|v|} }d|d| "} }s|s| "} }k|k|NugUhimnrnwnwnyizh{|} } }i|i|} }	} ((9b)7||r||r!||||r||||||s|||s||||||7|||7|||||||r|||%Z[^_f[gZhhpqxp{#||||||||} 	s   -X/ /Yc                    t        | dz        }t        |       }t        |      }	 |j                  t        |             |j	                  dd      }|j	                  d      }|j                          t        |t              }|s!t        j                  d      dz   dt        j                         v st        j                  t              rt        j                  t              ndd	t        j                         v st        j                  |      rt        j                  |      nd	d
t        j                         v st        j                  t              rt        j                  t              nd
t        j                  |      dz  }t        t        j                  |            d}t!        |      }d}	||	kD  }
|
st        j"                  d|
fd||	f      dt        j                         v st        j                  t               rt        j                  t               ndd	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      t        j                  |	      dz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}x}
}	h d}|D ]  }|D ]  }||v }|st        j"                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d| dt        |j%                                      dz   d|iz  }t        t        j                  |            d}  t&        j(                  }d}
d } |||
|!      }t&        j(                  }d}d } ||||!      }||k(  }|st        j"                  d"|fd#||f      d$t        j                         v st        j                  t&              rt        j                  t&              nd$t        j                  |      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |
      t        j                  |      t        j                  |      d$t        j                         v st        j                  t&              rt        j                  t&              nd$t        j                  |      d%t        j                         v st        j                  |      rt        j                  |      nd%t        j                  |      t        j                  |      t        j                  |      d&z  }t        j                  d'      d(z   d)|iz  }t        t        j                  |            dx}x}
x}x}x}x}x}x}}y# |j                          w xY w)*u   layer='full' 결과에는 file_path, title, type, team_id, tags, snippet, score가
    모두 있어야 하고, layer 미지정 결과와 동일해야 한다.r   r   r   fullr   u@   layer='full' search()가 리스트를 반환하지 않습니다.r   r    results_fullr"   r#   Nr   r(   r*   r+   r,   u1   layer='full' 검색 결과가 비어있습니다.r/   r0   >   r5   r2   r3   r4   r6   r7   r8   r9   r;   r<   r=   r>   u&   layer='full' 결과에 필수 필드 'r?   r@   r'   FT)ensure_ascii	sort_keys==)z%(py9)s
{%(py9)s = %(py2)s
{%(py2)s = %(py0)s.dumps
}(%(py3)s, ensure_ascii=%(py5)s, sort_keys=%(py7)s)
} == %(py20)s
{%(py20)s = %(py13)s
{%(py13)s = %(py11)s.dumps
}(%(py14)s, ensure_ascii=%(py16)s, sort_keys=%(py18)s)
}jsonresults_default)r$   r&   r-   py5py7py9py11py13py14py16py18py20u>   layer='full' 결과와 layer 미지정 결과가 다릅니다.z
>assert %(py22)spy22)rE   r   r   rF   rG   rH   r    r"   rI   rJ   rK   rL   rM   rN   rO   rP   r+   rQ   rR   rq   dumps)rS   r   rT   rU   rl   rr   rV   rW   rX   rY   rZ   r[   r\   r]   r=   r<   r_   r`   @py_assert6@py_assert8@py_assert12@py_assert15@py_assert17@py_assert19@py_assert10@py_format21@py_format23s                              r   "test_TC15_layer_full_compatibilityr      s    (Y&'G)HG,G3x=)~~oV~D!..9lD)m)mm+mmmmmmm:mmm:mmmmmmlmmmlmmmmmmDmmmDmmm)mmmmmm|UqUq UUUqUUUUUU3UUU3UUUUUU|UUU|UUUUUUqUUU"UUUUUUUU[O y$ 	yED=xxx5Dxxxxxx5xxx5xxxxxxDxxxDxxxx$J5'Qdeijnjsjsjuevdw"xxxxxxx	yy
 :: H H$ H:l$G H4:: H&+H7;H:etL HG L  H H6G6GHG L H HAGH H/G/G  H H>Gi  H H>Gi  H HAGH H/G/G # H H>Gi # H H>Gi 27 H H>Gi CG H H>Gi H H HAGH H/G/G LP H H>Gi LP H H>Gi LV H HAGH H/G/G 	H H>Gi 	H H>Gi ',H H>Gi 8<H H>GiL H H6G6GGH H H4G4GH H H H 	s   >Y Y"c                    t        | dz        }t        |      }	 t        j                  t              5  |j                  dd       ddd       |j                          y# 1 sw Y   xY w# |j                          w xY w)u=   layer='invalid' 전달 시 ValueError가 발생해야 한다.r   r   r   invalidr   N)rE   r   pytestraises
ValueErrorrG   rH   )rS   r   rU   s      r   test_TC16_invalid_layer_raisesr      sh    (Y&'GG,G]]:& 	=NN?)N<	= 		= 	= 	s"   A. A"	A. "A+'A. .B c                    t        | dz        }t        |       }t        |       }t        |      }	 |j	                  t        |             |j	                  t        |             |j                  dd      }|j                  dd      }t        |      }d}||kD  }	|	st        j                  d|	fd	||f      d
t        j                         v st        j                  t              rt        j                  t              nd
dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }
t        j                  d      dz   d|
iz  }t        t        j                  |            dx}x}	}t        |      }d}||kD  }	|	st        j                  d|	fd	||f      d
t        j                         v st        j                  t              rt        j                  t              nd
dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }
t        j                  d      dz   d|
iz  }t        t        j                  |            dx}x}	}|d   d   }|d   d   }|j!                  ||g      }|j#                          t%        |t&              }|s!t        j                  d      dz   dt        j                         v st        j                  t$              rt        j                  t$              nddt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  t&              rt        j                  t&              ndt        j                  |      dz  }t        t        j                  |            d}t        |      }d}||k(  }	|	st        j                  d|	fd||f      d
t        j                         v st        j                  t              rt        j                  t              nd
dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }
t        j                  dt        |       d      dz   d|
iz  }t        t        j                  |            dx}x}	}|D ]  }d}||v }|st        j                  d |fd!||f      t        j                  |      d"t        j                         v st        j                  |      rt        j                  |      nd"d#z  }t        j                  d$t'        |j)                                      d%z   d&|iz  }t        t        j                  |            dx}} y# |j#                          w xY w)'u`   파일 2개를 인덱싱한 뒤 get_by_ids()로 조회하면 content 필드가 있어야 한다.r   r   u   메모리 인덱서r   r   r   r   r(   r*   r+   diary_resultsr,   u+   diary 파일 검색 결과가 없습니다.r/   r0   Nmem_resultsu,   memory 파일 검색 결과가 없습니다.r1   u7   get_by_ids()가 리스트를 반환하지 않습니다.r   r    fetchedr"   r#      ro   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)su:   get_by_ids([id1, id2]) 결과 건수가 2여야 하는데 u
   입니다.contentr9   )z%(py1)s in %(py3)sr=   )r%   r-   u9   get_by_ids() 결과에 'content' 필드가 없습니다: 
>assert %(py5)srs   )rE   r   r   r   rF   rG   r+   rI   rQ   rK   rL   rM   rN   rJ   rO   rP   
get_by_idsrH   r    r"   rR   )rS   r   
diary_filerT   rU   r   r   rX   rY   rZ   r[   r\   id1id2r   rV   rW   r=   @py_assert0@py_format4@py_format6s                        r   test_TC17_get_by_ids_basicr      s   (Y&'G *J)HG,G3z?+3x=)  '<GLnn_GnD=!TAT!A%TTT!ATTTTTTsTTTsTTTTTT=TTT=TTT!TTTATTT'TTTTTTTT;S!S!#SSS!SSSSSSsSSSsSSSSSS;SSS;SSSSSS!SSS%SSSSSSSSAt$!nT"$$c3Z0gt$_$__&_______:___:______g___g______t___t___$______w<s1s<1sss<1ssssss3sss3sssssswssswsss<sss1sss Z[^_f[gZhhrssssssss rqyD qqqyDqqqyqqqqqqDqqqDqqqq$]^bcgclclcn^o]p"qqqqqqqr	 	s   KY Y&c                    t        | dz        }t        |      }	 |j                  g       }|j                          t	        |t
              }|s!t        j                  d      dz   dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  t
              rt        j                  t
              ndt        j                  |      dz  }t        t        j                  |            d	}g }||k(  }|st        j                  d
|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d|       dz   d|iz  }	t        t        j                  |	            d	x}}y	# |j                          w xY w)u7   get_by_ids([])는 빈 리스트를 반환해야 한다.r   r   u9   get_by_ids([])가 리스트를 반환하지 않습니다.r   r    resultr"   r#   Nro   z%(py0)s == %(py3)sr$   r-   uA   get_by_ids([])가 빈 리스트를 반환하지 않았습니다: r   rs   rE   r   r   rH   r    r"   rI   rJ   rK   rL   rM   rN   rO   rP   rQ   
rS   r   rU   r   rV   rW   rX   r_   r   r   s
             r   test_TC18_get_by_ids_emptyr      sD   (Y&'GG,G##B'fd#`#``%```````:```:``````f```f``````d```d```#``````e6R<eee6Reeeeee6eee6eeeReee\]c\deeeeeee 	s   H3 3Ic                    t        | dz        }t        |      }	 |j                  dg      }|j                          t	        |t
              }|s!t        j                  d      dz   dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  t
              rt        j                  t
              ndt        j                  |      d	z  }t        t        j                  |            d
}g }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d| d      dz   d|iz  }	t        t        j                  |	            d
x}}y
# |j                          w xY w)uS   get_by_ids([99999])는 해당 ID가 없으면 빈 리스트를 반환해야 한다.r   r   i u>   get_by_ids([99999])가 리스트를 반환하지 않습니다.r   r    r   r"   r#   Nro   r   r   uJ   존재하지 않는 ID 조회 시 빈 리스트를 반환해야 하는데 u   를 반환했습니다.r   rs   r   r   s
             r    test_TC19_get_by_ids_nonexistentr      s   (Y&'GG,G##UG,fd#e#ee%eeeeeee:eee:eeeeeefeeefeeeeeedeeedeee#eeeeee  F6R<  F  F  F6R  F  F  F  F  F  F6  F  F  F6  F  F  FR  F  F  Feflem  nE  F  F  F  F  F  F  F 	s   H5 5Ic           	         t        | dz        }t        |       }t        |       }t        |      }	 |j	                  t        |             |j	                  t        |             |j                  dd      }|j                  dd      }|j                  dd      }|j                          dt        fd	} ||      }	 ||      }
 ||      }|	|
k  }|st        j                  d
|fd|	|
f      dt        j                         v st        j                  |	      rt        j                  |	      nddt        j                         v st        j                  |
      rt        j                  |
      nddz  }t        j                  d|	 d|
 d      dz   d|iz  }t        t        j                   |            d}|
|k  }|st        j                  d
|fd|
|f      dt        j                         v st        j                  |
      rt        j                  |
      nddt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d|
 d| d      dz   d|iz  }t        t        j                   |            d}|	|z  }d}||k  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d|dd|	 d | d!      d"z   d#|iz  }t        t        j                   |            dx}}y# |j                          w xY w)$u   같은 검색어로 layer='index' < 'summary' < 'full' 순으로 바이트 크기가
    증가해야 하며, full 대비 index의 크기가 50% 이하여야 한다.r   r   u   위임r   r   rc   rk   r   c                 `    t        t        j                  | d      j                  d            S )NF)rm   r	   )r+   rq   r}   encode)objs    r   	byte_sizez2test_TC20_token_saving_by_layer.<locals>.byte_size  s#    4::c6==gFGGr   )<)z%(py0)s < %(py2)s
size_indexsize_summaryr>   zindex(u   B) 크기가 summary(u   B) 이상입니다.r@   r'   N	size_fullzsummary(u   B) 크기가 full(g      ?rf   )z%(py0)s <= %(py3)sratior   u;   full 대비 index 크기 비율이 50%를 초과합니다: z.1%z (index=zB, full=zB)r   rs   )rE   r   r   r   rF   rG   rH   intrI   rQ   rK   rL   rM   rN   rJ   rO   rP   )rS   r   r   rT   rU   results_indexresults_summaryrl   r   r   r   r   r_   r`   rW   r   rX   r   r   s                      r   test_TC20_token_saving_by_layerr     s    (Y&'G *J)HG,G3z?+3x=)xw?!...C~~hf~=H# H =)J_-L,'I$qqq:qqqqqq:qqq:qqqqqqqqqqqqqzl:OP\~]p&qqqqqqq)#nnn<)nnnnnn<nnn<nnnnnn)nnn)nnnnx~=OPY{Zm%nnnnnnn"E 5C<  5C                  FeC[P\]g\hhpqzp{{}~     	s   A-M6 6N)z2026-04-05-session-01.md)zdelegation_rules.md)__doc__builtinsrK   _pytest.assertion.rewrite	assertionrewriterI   rq   systextwrappathlibr   r   pathinsertutils.memory_indexerr   dedentr   r   rE   r   r   ra   ri   r   r   r   r   r   r    r   r   <module>r      s   
   
    ( ) .   ! " ! "  t s TX   PT {@}FHB	"rHf&F&r   