
    (iK                       d Z ddlm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ZddlmZ ddlmZ ddlmZmZmZ ddlZdZee
j.                  vre
j.                  j1                  de       ddlmZmZmZmZ dd	lmZ 	 	 	 	 	 d2	 	 	 	 	 	 	 	 	 	 	 d3dZ d4d5dZ!d6dZ"d Z#d Z$d Z%d Z&d Z'd Z(d Z)d Z*d Z+d Z,d Z-d Z.d Z/d Z0e1dk(  rddl2Z2de#fde$fde%fd e&fd!e'fd"e(fd#e)fd$e*fd%e+fd&e,fd'e-fd(e.fd)e/fd*e0fgZ3dZ4 e5e3      Z6e3D ]  \  Z7Z8	  e8         e9d+e7        e4d
z  Z4  e9d.e4 d/e6 d0       e4e6k(  r	 e9d1       y e
jz                  d
       yy# e:$ r)Z; e9d,e7 d-e;         e2jx                          Y dZ;[;zdZ;[;ww xY w)7u)  
tests/track_b/test_story_9_06.py

Story 9.06: EpochKnowledgeWriter — Axiom Persistence (KG + Qdrant)

Black Box Tests (BB):
    BB1  write() with 3 axioms → KG file has 3 new JSONL entries
    BB2  write() with 3 axioms → Qdrant mock received 3 upsert calls with
         axiom_type="distilled" in each payload
    BB3  Qdrant raises on upsert → KG still written, qdrant_upserts=0

White Box Tests (WB):
    WB1  KG write uses open(..., "a") append mode, NOT overwrite ("w")
    WB2  Each axiom gets its own individual Qdrant upsert call (not batch)

Additional / edge-case tests (9 more tests = 14 total):
    EDGE1  WriteResult.kg_file_path equals writer's kg_path (absolute path)
    EDGE2  WriteResult.jsonl_entries == len(axioms)
    EDGE3  WriteResult.qdrant_upserts == len(axioms) on full success
    EDGE4  Empty axiom list → WriteResult(jsonl_entries=0, qdrant_upserts=0)
    EDGE5  KG entry contains correct epoch_id and date fields
    EDGE6  No qdrant_client → qdrant_upserts=0, KG still written
    EDGE7  embed_fn is called per axiom (not skipped when provided)
    EDGE8  WriteResult and its fields are importable from core.epoch package
    EDGE9  KG_FILE_PATH constant points to genesis_evolution_learnings.jsonl

ALL external I/O mocked. tempfile.NamedTemporaryFile used for KG file tests.
    )annotationsN)	dataclass)Path)	MagicMockcallpatchz/mnt/e/genesis-systemEpochKnowledgeWriterWriteResultKG_FILE_PATHQDRANT_COLLECTIONAxiom   c           	     <    t        d| d||||xs d| dg      S )zBuild a single test Axiom.epoch_2026_02_25_03dsaga_)idcontentcategory
confidencesource_saga_idsr   )idxr   r   r   r   s        6/mnt/e/genesis-system/tests/track_b/test_story_9_06.py_make_axiomr   C   s:     s3i('>eC9,=+>     c                d    t        d| dz         D cg c]  }t        |d| d       c}S c c}w )z/Build a list of *count* distinct Axiom objects.r   zAxiom content 
operations)r   r   r   )ranger   )countis     r   _make_axiom_listr#   T   s?     q%!)$ 	^A3#7,O  s   -c                 <    t               } d| j                  _        | S )z4Return a fresh MagicMock simulating a Qdrant client.N)r   upsertreturn_value)qds    r   _make_mock_qdrantr(   \   s    	B!BIIIr   c                    t        d      } t        j                  dddd      5 }|j                  }ddd       	 t	        d      }|j                  | d	
      }t        |dd      5 }|D cg c]#  }|j                         s|j                         % }}d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z   d|iz  }t!        t        j"                  |            dx}x}
}	|j$                  }d}
||
k(  }|st        j                  d|fd||
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |
      dz  }dd|iz  }t!        t        j"                  |            dx}x}}
|D ]Q  }t'        j(                  |      }d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd |iz  }t!        t        j"                  |            dx}}d!}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd |iz  }t!        t        j"                  |            dx}}d"}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd |iz  }t!        t        j"                  |            dx}}d#}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd |iz  }t!        t        j"                  |            dx}}d$}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd |iz  }t!        t        j"                  |            dx}}T 	 t+        j,                  |       y# 1 sw Y   xY wc c}w # 1 sw Y   xY w# t+        j,                         w xY w)%uG   BB1: write() with 3 axioms → KG file has exactly 3 new JSONL entries.   w.jsonlFutf-8modesuffixdeleteencodingNqdrant_clientkg_pathepoch_2026_02_25epoch_idrr2   ==z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenlinespy0py1py3py6zExpected 3 JSONL entries, got 
>assert %(py8)spy8z5%(py2)s
{%(py2)s = %(py0)s.jsonl_entries
} == %(py5)sresultrA   py2py5assert %(py7)spy7r   inz%(py1)s in %(py3)sentryrB   rC   zassert %(py5)srK   r   r   epochdate)r#   tempfileNamedTemporaryFilenamer
   writeopenstripr>   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanationjsonl_entriesjsonloadsosunlink)axiomstmptmp_pathwriterrH   fhlnr?   @py_assert2@py_assert5@py_assert4@py_format7@py_format9@py_assert1@py_assert3@py_format6@py_format8linerQ   @py_assert0@py_format4s                        r   "test_bb1_kg_file_has_3_new_entriesr{   h   s   a F		$	$%'
 	88
%D(Kf/AB (C'2 	<b*,;B
RXXZ;E;	< 5zMQMzQMMMzQMMMMMMsMMMsMMMMMM5MMM5MMMzMMMQMMM"@U MMMMMMMM##(q(#q((((#q((((((v(((v(((#(((q(((((((  	#DJJt$E 45=   45   4      5   5       %9%%%%9%%%9%%%%%%%%%%%%%%%%&:&&&&:&&&:&&&&&&&&&&&&&&&&#7e####7e###7######e###e#######"6U?"""6U"""6""""""U"""U"""""""	# 			(3  <	< 	< 			(sG   X	.X( )X.XXXUX( 	XXX% X( (X?c            	        t        d      } t               }t        j                  dddd      5 }|j                  }ddd       	 t        |      }|j                  | d	
      }|j                  }|j                  }d}||k(  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }
t        j                  d|j                  j                         dz   d|
iz  }t!        t        j"                  |            dx}x}x}	}|j$                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }
t!        t        j"                  |
            dx}x}}|j                  j&                  D ]?  }|\  }}|d   }|t(        k(  }|st        j                  d|fd|t(        f      t        j                  |      dt        j                         v st        j                  t(              rt        j                  t(              nddz  }t        j                  dt(         d|d    d      dz   d|iz  }t!        t        j"                  |            dx}}|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%      d&z   d'|iz  }t!        t        j"                  |            dx}x}}	|d(   d)   }|j,                  }d*} ||      }	d+}|	|k(  }|st        j                  d|fd,|	|f      d)t        j                         v st        j                  |      rt        j                  |      nd)t        j                  |      t        j                  |      t        j                  |	      t        j                  |      d-z  }t        j                  d.|j-                  d*            d/z   d0|iz  }t!        t        j"                  |            dx}x}x}	x}}B 	 t/        j0                  |       y# 1 sw Y   zxY w# t/        j0                         w xY w)1uQ   BB2: 3 axioms → 3 Qdrant upsert calls, each payload has axiom_type='distilled'.r*   r+   r,   Fr-   r.   Nr3   r6   r7   r;   zN%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.upsert
}.call_count
} == %(py7)sr'   rA   rJ   py4rM   z$Expected 3 Qdrant upsert calls, got 
>assert %(py9)spy9z6%(py2)s
{%(py2)s = %(py0)s.qdrant_upserts
} == %(py5)srH   rI   rL   rM   collection_namez%(py1)s == %(py3)sr   rR   zExpected collection_name='', got ''
>assert %(py5)srK   pointsr   r=   r>   r@   z Expected 1 point per upsert callrE   rF   r   payload
axiom_type	distilled)zI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} == %(py9)s)rA   rJ   r   rD   r   z%Expected axiom_type='distilled', got z
>assert %(py11)spy11)r#   r(   rU   rV   rW   r
   rX   r%   
call_countr[   r\   r]   r^   r_   r`   ra   rb   rc   qdrant_upsertscall_args_listr   r>   getrg   rh   )ri   r'   rj   rk   rl   rH   rt   ru   @py_assert6rp   rw   @py_format10rq   rv   upsert_call_kwargsry   ro   rz   r   rr   rs   r   @py_assert8@py_assert7@py_format12s                              r   1test_bb2_qdrant_upserts_with_axiom_type_distilledr      s   a F		B		$	$%'
 	88
%BIf/AByy 	
y## 	
q 	
#q( 	
 	
#q 	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
 		 $ 	
 	
 		 () 	
 	
  32993G3G2HI	
 	
 	
 	
 	
 	
 $$))$))))$))))))v)))v)))$)))))))))) 9933 	K#IAv+, ,0AA  ,0A   I -   v   1B   I 1B    -->,? @012!5     H%Fv;G!G;!#GGG;!GGGGGG3GGG3GGGGGGvGGGvGGG;GGG!GGG%GGGGGGGGQi	*G;; | ;|,  ,;  ,  v     I   I   I  ,  I -  I 1<    8L8Q7TU     	 			(; : 			(s   V4UW 4V>Wc                 8   t        d      } t               }t        d      |j                  _        t        j                  dddd      5 }|j                  }ddd       	 t        |	      }|j                  | d
      }t        |dd      5 }|D cg c]#  }|j                         s|j                         % }}d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z   d|iz  }t)        t        j*                  |            dx}	x}}
|j,                  }d}||k(  }|st        j                  d|fd||f      dt        j                          v st        j"                  |      rt        j$                  |      ndt        j$                  |      t        j$                  |      dz  }t        j&                  d|j,                         dz   d|iz  }t)        t        j*                  |            dx}x}}|j.                  }d}||k(  }|st        j                  d|fd||f      dt        j                          v st        j"                  |      rt        j$                  |      ndt        j$                  |      t        j$                  |      dz  }t        j&                  d|j.                         dz   d|iz  }t)        t        j*                  |            dx}x}}t1        j2                  |       y# 1 sw Y   xY wc c}w # 1 sw Y   ;xY w# t1        j2                         w xY w)uJ   BB3: Qdrant raises on every upsert → KG still written, qdrant_upserts=0.r*   zQdrant connection refusedr+   r,   Fr-   r.   Nr3   r6   r7   r9   r:   r;   r=   r>   r?   r@   z8KG should have 3 entries even after Qdrant failure, got rE   rF   rG   rH   rI   zjsonl_entries should be 3, got 
>assert %(py7)srM   r   r   z5qdrant_upserts should be 0 after Qdrant failure, got )r#   r(   RuntimeErrorr%   side_effectrU   rV   rW   r
   rX   rY   rZ   r>   r[   r\   r]   r^   r_   r`   ra   rb   rc   rd   r   rg   rh   )ri   r'   rj   rk   rl   rH   rm   rn   r?   ro   rp   rq   rr   rs   rt   ru   rv   rw   s                     r   (test_bb3_qdrant_failure_kg_still_writtenr      s   a F		B()DEBII		$	$%'
 	88
%BIf/AB (C'2 	<b*,;B
RXXZ;E;	< 5z 	
Q 	
zQ 	
 	
 	
zQ 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
 		  	
 	
  Gs5zlS	
 	
 	
 	
 	
 ## 	
q 	
#q( 	
 	
#q 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 $ 	
 	
 		 () 	
 	
  .f.B.B-CD	
 	
 	
 	
 	
 $$ 	
 	
$) 	
 	
$ 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 % 	
 	
 		 )* 	
 	
  DFDYDYCZ[	
 	
 	
 	
 	
 			(/  <	< 	< 			(sI   	O#.P O5O0(O0:O5<LP #O-0O55O?:P Pc                 
   t        d      } t        j                  dddd      5 }t        j                  ddd	      }|j                  |d
z          |j                  }ddd       	 t        d      }|j                  | d       t        |dd      5 }|D cg c]#  }|j                         s|j                         % }}d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}
}	t        j(                  |d         }|d   }d}||k(  }|st        j                  d|fd||f      t        j                   |      t        j                   |      dz  }t        j"                  d|d         d z   d!|iz  }t%        t        j&                  |            dx}x}}t+        j,                  |       y# 1 sw Y   pxY wc c}w # 1 sw Y   xY w# t+        j,                         w xY w)"uG   WB1: KG write uses open(..., 'a') — append mode, never 'w' overwrite.   r+   r,   Fr-   r.   pre_existingz	old entry)r   r   
Nr3   r6   r7   r9   r:   r*   r;   r=   r>   r?   r@   z/Expected 3 lines (1 pre-existing + 2 new), got : rE   rF   r   r   z%(py1)s == %(py4)srB   r   z/Pre-existing line was overwritten. First line: 
>assert %(py6)srD   )r#   rU   rV   re   dumpsrX   rW   r
   rY   rZ   r>   r[   r\   r]   r^   r_   r`   ra   rb   rc   rf   rg   rh   )ri   rj   existing_entryrk   rl   rm   rn   r?   ro   rp   rq   rr   rs   firstry   ru   @py_format5s                    r   "test_wb1_kg_write_uses_append_moder      s   a F		$	$%'
 	>k$RS		.4'(88%D(KV&89(C'2 	<b*,;B
RXXZ;E;	< 5z 	
Q 	
zQ 	
 	
 	
zQ 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
 		  	
 	
  >c%j\E7S	
 	
 	
 	
 	
 

58$T{ 	
n 	
{n, 	
 	
{n 	
 	
 		  	
 	
 		 - 	
 	
  >eAh\J	
 	
 	
 	
 	
 			(3  <	< 	< 			(sH   9K'.K+ KK0KKG2K+ KKK(#K+ +Lc                    t        d      } t               }t        j                  dddd      5 }|j                  }ddd       	 t        |      }|j                  | d	
       |j                  }|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }	t        j                  d|j                  j                         dz   d|	iz  }
t!        t        j"                  |
            dx}x}x}}|j                  j$                  D ]  }|\  }}|d   }t'        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t&              rt        j                  t&              ndt        j                  |      t        j                  |      t        j                  |      dz  }	t        j                  dt'        |d          d|d          dz   d|	iz  }
t!        t        j"                  |
            dx}x}x}}  	 t)        j*                  |       y# 1 sw Y   xY w# t)        j*                         w xY w)zGWB2: Each axiom triggers its own upsert call (not a single batch call).   r+   r,   Fr-   r.   Nr3   
epoch_testr7   r;   r}   r'   r~   z8Expected 4 individual upsert calls (one per axiom), got r   r   r   r   )z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py7)sr>   z&Expected 1 point per upsert call, got r   )r#   r(   rU   rV   rW   r
   rX   r%   r   r[   r\   r]   r^   r_   r`   ra   rb   rc   r   r>   rg   rh   )ri   r'   rj   rk   rl   rt   ru   r   rp   rw   r   r   r   r   s                 r   1test_wb2_each_axiom_gets_individual_qdrant_upsertr      s   a F		B		$	$%'
 	88
%BIVl3 yy 	
y## 	
q 	
#q( 	
 	
#q 	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
	  	
 	
 
	 $ 	
 	
 
	 () 	
 	
 99''(*	
 	
 	
 	
 	
 	
 9933 	K#IAvh' 3'( A (A-  (A   v      I    I (   I )   I -.   6(+,-Rx0@/AC     	 			(/ . 			(s   K
I.K 
KK.c                 ^   t        j                  dddd      5 } | j                  }ddd       	 t        d      }|j	                  t        d      d	
      }|j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d| d|j                   d      dz   d|iz  }t        t        j                  |            dx}}t!        j"                  |       y# 1 sw Y   cxY w# t!        j"                         w xY w)zGEDGE1: WriteResult.kg_file_path equals the writer's configured kg_path.r+   r,   Fr-   r.   Nr3   r   r   r7   r;   )z4%(py2)s
{%(py2)s = %(py0)s.kg_file_path
} == %(py4)srH   rk   rA   rJ   r   zExpected kg_file_path='r   r   r   rD   )rU   rV   rW   r
   rX   r#   kg_file_pathr[   r\   r]   r^   r_   r`   ra   rb   rc   rg   rh   )rj   rk   rl   rH   rt   ru   r   rr   s           r   6test_edge1_write_result_kg_file_path_is_writer_kg_pathr     st   		$	$%'
 	88
%D(K.q1LI"" 	
"h. 	
 	
 	
"h 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 # 	
 	
	6	
 	
  '/ 	
 	
 		 '/ 	
 	
  &hZx8K8K7LAN	
 	
 	
 	
 	
 			(  			(s   FEF FF,c            	     x   dD ]  } t        |       }t        j                  dddd      5 }|j                  }ddd       	 t	        d      }|j                  |d	
      }|j                  }|| k(  }|st        j                  d|fd|| f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |       rt        j                  |       nddz  }t        j                  d|  d|  d|j                         dz   d|iz  }	t        t        j                  |	            dx}}t!        j"                  |        y# 1 sw Y   _xY w# t!        j"                         w xY w)zCEDGE2: WriteResult.jsonl_entries == len(axioms) for various counts.)r      
   r+   r,   Fr-   r.   Nr3   r   r7   r;   )z5%(py2)s
{%(py2)s = %(py0)s.jsonl_entries
} == %(py4)srH   r!   r   z
For count=z: expected jsonl_entries=z, got r   rD   )r#   rU   rV   rW   r
   rX   rd   r[   r\   r]   r^   r_   r`   ra   rb   rc   rg   rh   )
r!   ri   rj   rk   rl   rH   rt   ru   r   rr   s
             r   +test_edge2_jsonl_entries_equals_axiom_countr   (  s     !%(((Xeg
 	 xxH	 
	 )hOF\\&<\@F'' '50   '5   v      I    I (   v   ,1   I ,1    UG#<UG D++,.    
 IIh! 	  	  IIhs   FD;F"F	"F9c                    t        d      } t               }t        j                  dddd      5 }|j                  }ddd       	 t        |      }|j                  | d	
      }|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	t        j                  d|j                         dz   d|	iz  }
t        t        j                   |
            dx}x}}t#        j$                  |       y# 1 sw Y   ,xY w# t#        j$                         w xY w)zJEDGE3: WriteResult.qdrant_upserts == len(axioms) when all upserts succeed.r   r+   r,   Fr-   r.   Nr3   r   r7   r;   r   rH   rI   zExpected qdrant_upserts=5, got r   rM   )r#   r(   rU   rV   rW   r
   rX   r   r[   r\   r]   r^   r_   r`   ra   rb   rc   rg   rh   )ri   r'   rj   rk   rl   rH   rt   rq   ru   rv   rw   s              r   7test_edge3_qdrant_upserts_equals_axiom_count_on_successr   =  sX   a F		B		$	$%'
 	88
%BIf|<$$ 	
 	
$) 	
 	
$ 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 % 	
 	
 		 )* 	
 	
  .f.C.C-DE	
 	
 	
 	
 	
 			(  			(s   E&DE3 &E03F
c                 "   t               } t        j                  dddd      5 }|j                  }ddd       	 t	        |       }|j                  g d	      }|j                  }d
}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}|j                  }d
}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}| j                   }|j"                  }d
}
||
k(  }|st        j                  d|fd||
f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      t        j                  |
      dz  }	dd|	iz  }t        t        j                  |            dx}x}x}}
t%        j&                  |       y# 1 sw Y   xY w# t%        j&                         w xY w)uO   EDGE4: Empty axiom list → WriteResult with jsonl_entries=0, qdrant_upserts=0.r+   r,   Fr-   r.   Nr3   r   r7   r   r;   rG   rH   rI   rL   rM   r   r}   r'   r~   zassert %(py9)sr   )r(   rU   rV   rW   r
   rX   rd   r[   r\   r]   r^   r_   r`   rb   rc   r   r%   r   rg   rh   )r'   rj   rk   rl   rH   rt   rq   ru   rv   rw   r   rp   r   s                r   /test_edge4_empty_axiom_list_returns_zero_countsr   R  s   		B		$	$%'
 	88
%BIb<8##(q(#q((((#q((((((v(((v(((#(((q((((((($$))$))))$))))))v)))v)))$))))))))))yy(y##(q(#q((((#q((((((r(((r(((y(((#(((q(((((((
		(  			(s   K*JK7 *K47Lc                 	   ddl m } m} t        ddd      }d}t        j                  dd	d
d      5 }|j
                  }ddd       	 t        d      }|j                  |g|       t        |dd      5 }t        j                  |j                         j                               }ddd       d   }	|	|k(  }
|
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| d|d    d      dz   d|iz  }t)        t        j*                  |            dx}	}
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       dz   d|iz  }t)        t        j*                  |            dx}	}
|d   }| j-                  |d!       |d"   }	|j.                  }|	|k(  }
|
st        j                  d|
fd#|	|f      t        j                  |	      d$t!        j"                         v st        j$                  |      rt        j                  |      nd$t        j                  |      d%z  }d&d'|iz  }t)        t        j*                  |            dx}	x}
}|d(   }	|j0                  }|	|k(  }
|
st        j                  d|
fd)|	|f      t        j                  |	      d$t!        j"                         v st        j$                  |      rt        j                  |      nd$t        j                  |      d%z  }d&d'|iz  }t)        t        j*                  |            dx}	x}
}|d*   }	|j2                  }|	|k(  }
|
st        j                  d|
fd+|	|f      t        j                  |	      d$t!        j"                         v st        j$                  |      rt        j                  |      nd$t        j                  |      d%z  }d&d'|iz  }t)        t        j*                  |            dx}	x}
}t5        j6                  |       y# 1 sw Y   xY w# 1 sw Y   )xY w# t5        j6                         w xY w),zKEDGE5: Each KG JSONL entry contains the correct epoch_id and a date string.r   )datetimetimezoner   zTest contenttest)r   r   r6   r+   r,   Fr-   r.   Nr3   r7   r9   r:   rS   r;   r   r8   rR   zExpected epoch='r   r   r   rK   rT   rN   rP   rQ   zKG entry must have 'date' fieldz%Y-%m-%dr   )z*%(py1)s == %(py5)s
{%(py5)s = %(py3)s.id
}axiom)rB   rC   rK   rL   rM   r   )z/%(py1)s == %(py5)s
{%(py5)s = %(py3)s.content
}r   )z0%(py1)s == %(py5)s
{%(py5)s = %(py3)s.category
})r   r   r   rU   rV   rW   r
   rX   rY   re   rf   readlinerZ   r[   r\   r`   r]   r^   r_   ra   rb   rc   strptimer   r   r   rg   rh   )r   r   r   r8   rj   rk   rl   rm   rQ   ry   ro   rz   rv   date_strrq   rw   s                   r   5test_edge5_kg_entry_has_correct_epoch_and_date_fieldsr   f  s]   +>FCE!H		$	$%'
 	88
%D(KeWx0(C'2 	6bJJr{{}2245E	6 W~ 	
~) 	
 	
~ 	
 	
 		  	
 	
	6	
 	
  "* 	
 	
 		 "* 	
 	
  xjw0@B	
 	
 	
 	
 	
 AvAAAvAAAvAAAAAAAAAAAAA AAAAAAA=(J/T{&ehh&{h&&&&{h&&&{&&&&&&e&&&e&&&h&&&&&&&Y05==0=0000=00000000050005000=0000000Z 2ENN2 N2222 N222 222222E222E222N2222222
		(/ 	6 	6 			(s0   S/S 72S)PS SSS S4c                    t        d      } t        j                  dddd      5 }|j                  }ddd       	 t	        d      }|j                  | d	
      }|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}t!        |dd      5 }
|
D cg c]#  }|j#                         s|j#                         % }}ddd       t%              }d}||k(  }|st        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  }dd|iz  }t        t        j                  |            dx}x}}t'        j(                  |       y# 1 sw Y   &xY wc c}w # 1 sw Y   BxY w# t'        j(                         w xY w)uH   EDGE6: qdrant_client=None → qdrant_upserts=0, KG written successfully.r   r+   r,   Fr-   r.   Nr3   r   r7   r   r;   r   rH   rI   rL   rM   rG   r9   r:   r=   r>   r?   r@   zassert %(py8)srF   )r#   rU   rV   rW   r
   rX   r   r[   r\   r]   r^   r_   r`   rb   rc   rd   rY   rZ   r>   rg   rh   )ri   rj   rk   rl   rH   rt   rq   ru   rv   rw   rm   rn   r?   ro   rp   rr   rs   s                    r   ,test_edge6_no_qdrant_client_kg_still_writtenr     s9   a F		$	$%'
 	88
%D(Kf|<$$))$))))$))))))v)))v)))$))))))))))##(q(#q((((#q((((((v(((v(((#(((q((((((((C'2 	<b*,;B
RXXZ;E;	<5zQzQzQss55zQ
		(!  <	< 	< 			(sH   MF>M5 9M(>M#M#&M((DM5 M #M((M2-M5 5Nc                 n   t        d      } t               }ddidfd}t        j                  dddd	      5 }|j                  }d
d
d
       	 t        ||      }|j                  | d       d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	t        j                  dd          dz   d|	iz  }
t        t        j                  |
            d
x}x}}|j                  j                  D ]  }|\  }}|d   d   d   }g 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z   d|iz  }t        t        j                  |            d
x}} 	 t%        j&                  |       y
# 1 sw Y   xY w# t%        j&                         w xY w)z>EDGE7: When embed_fn is provided, it is called once per axiom.r*   nr   c                &    dxx   dz  cc<   g dS )Nr   r   g?g?g333333?g? )textembed_call_counts    r   _mock_embedz9test_edge7_embed_fn_called_per_axiom.<locals>._mock_embed  s    "##r   r+   r,   Fr-   r.   N)r4   embed_fnr5   r   r7   r;   r   r   z&Expected embed_fn called 3 times, got r   rD   r   vectorr   )z%(py0)s == %(py3)s)rA   rC   z0Expected embed vector [0.1, 0.2, 0.3, 0.4], got r   rK   )r   strreturnzlist[float])r#   r(   rU   rV   rW   r
   rX   r[   r\   r`   ra   rb   rc   r%   r   r]   r^   r_   rg   rh   )ri   r'   r   rj   rk   rl   ry   ru   ro   r   rr   r   r   r   r   rt   rz   rv   r   s                     @r   $test_edge7_embed_fn_called_per_axiomr     s   a F		BQx$ 
	$	$%'
 	88
%{H
 	Vl3$ 	
 	
$) 	
 	
$ 	
 	
 		 % 	
 	
 		 )* 	
 	
  55Ec5J4KL	
 	
 	
 	
 	
 9933 	K#IAvH%a(2F1 611  61  v     I   I 2    C6(K    	 			(- , 			(s   HF)H HH4c                    ddl m} m}m}m} | t        u }|st        j                  d|fd| t        f      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dz  }dd	|iz  }t        t        j                  |            d
}|t        u }|st        j                  d|fd|t        f      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dz  }dd	|iz  }t        t        j                  |            d
}|t        k(  }|st        j                  d|fd|t        f      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dz  }dd	|iz  }t        t        j                  |            d
}|t        k(  }|st        j                  d|fd|t        f      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dz  }dd	|iz  }t        t        j                  |            d
}y
)zjEDGE8: core.epoch __init__ exports EpochKnowledgeWriter, WriteResult,
    KG_FILE_PATH, QDRANT_COLLECTION.r   r	   )is)z%(py0)s is %(py2)sEKWr
   )rA   rJ   zassert %(py4)sr   NWRr   r;   )z%(py0)s == %(py2)sKFPr   QCr   )
core.epochr
   r   r   r   r[   r\   r]   r^   r_   r`   rb   rc   )r   r   r   r   rt   @py_format3r   s          r   =test_edge8_package_init_exports_write_result_and_kg_file_pathr     s     &&&&&3&&&&&&&3&&&3&&&&&&&&&&&&&&&&&&222,3,33,,"""""2"""""""2"""2""""""""""""""""""r   c                 N   t         j                  } d} | |      }|st        j                  dt          d      dz   dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      dz  }t        t        j                  |            dx} x}}d}|t         v }|st        j                  d	|fd
|t         f      t        j                  |      dt	        j
                         v st        j                  t               rt        j                  t               nddz  }t        j                  dt          d      dz   d|iz  }t        t        j                  |            dx}}t         j                  } d} | |      }|st        j                  dt          d      dz   dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      dz  }t        t        j                  |            dx} x}}y)zIEDGE9: KG_FILE_PATH constant points to genesis_evolution_learnings.jsonl.z!genesis_evolution_learnings.jsonlzHKG_FILE_PATH should end with 'genesis_evolution_learnings.jsonl', got: 'r   zL
>assert %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.endswith
}(%(py4)s)
}r   )rA   rJ   r   rD   NKNOWLEDGE_GRAPHrN   rP   rR   z5KG_FILE_PATH should be under KNOWLEDGE_GRAPH/, got: 'r   rK   z/mnt/e/z(KG_FILE_PATH must be on E: drive, got: 'zN
>assert %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.startswith
}(%(py4)s)
})r   endswithr[   ra   r]   r^   r_   r`   rb   rc   r\   
startswith)rt   ru   rp   rr   ry   ro   rz   rv   s           r   7test_edge9_kg_file_path_constant_points_to_correct_filer     sB      !D  !DE E  a	!             !    "E    F       ,            !-    !-    @~QO     "" 9 "9- -   3<.B             #    $-    .      r   __main__u   BB1: 3 axioms → 3 KG entriesz/BB2: 3 Qdrant upserts with axiom_type=distilledu(   BB3: Qdrant failure → KG still writtenzWB1: KG write uses append modez(WB2: individual Qdrant upserts per axiomz1EDGE1: WriteResult.kg_file_path == writer.kg_pathz#EDGE2: jsonl_entries == len(axioms)z/EDGE3: qdrant_upserts == len(axioms) on successu!   EDGE4: empty list → zero countsz'EDGE5: KG entry has epoch + date fieldsu,   EDGE6: no qdrant_client → KG still writtenz EDGE7: embed_fn called per axiomz2EDGE8: __init__ exports WriteResult + KG_FILE_PATHz'EDGE9: KG_FILE_PATH constant is correctz	  [PASS] z	  [FAIL] r   r   /z tests passedz(ALL TESTS PASSED -- Story 9.06 (Track B))r   zRead before buildr   g333333?N)r   intr   r   r   r   r   floatr   zlist | Noner   r   )r*   )r!   r   r   zlist[Axiom])r   r   )>__doc__
__future__r   builtinsr]   _pytest.assertion.rewrite	assertionrewriter[   re   sysrU   rg   dataclassesr   pathlibr   unittest.mockr   r   r   pytestGENESIS_ROOTpathinsert!core.epoch.epoch_knowledge_writerr
   r   r   r   core.epoch.axiom_distillerr   r   r#   r(   r{   r   r   r   r   r   r   r   r   r   r   r   r   r   __name__	tracebacktestspassedr>   totalrW   fnprint	Exceptionexc	print_excexitr   r   r   <module>r     sT  : #    
  	 !  0 0  'sxxHHOOA|$  - & #'	  	
 ! "@"JJ@H$ **(B. F# $ z 
*+MN	:<mn	35]^	)+MN	35fg	<>tu	.0[\	:<st	,.]^	24ij	79ef	+-QR	=?|}	24klE" FJE "b	"DIdV$%aKF	" 
Bvhawm
,-89G 6  	"IdV2cU+,I!!	"s   EFFF