
    y#iU              	         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mZ ddlmZmZ ddlZdZee
j$                  vre
j$                  j'                  de       ddlmZmZ ddlmZmZmZ 	 	 	 d-	 	 	 	 	 	 	 d.d	Zd/d0d
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 Z*d Z+e,dk(  rddl-Z-ddl.Z. G d d      Z/defdefdefd e fd!e!fd"e"fd#e#fd$e$fgZ0dZ1e0D ]%  \  Z2Z3 e/       Z4	  e3e4        e5d%e2        e1d&z  Z1'  e5d)e1 d* e9e0       d+       e1 e9e0      k(  r	 e5d,       y e
jt                  d&       yy# e6$ r)Z7 e5d'e2 d(e7         e.jp                          Y dZ7[7dZ7[7ww xY w)1u  
tests/track_b/test_story_8_08.py

Story 8.08: Tier1AutonomousUpdater — Epistemic Self-Updates

Black Box Tests (BB1–BB4):
    BB1  Tier 1 update → KG entity file created in kg_base_path (tmp_path)
    BB2  No .py files modified by Tier 1 update (check all written files)
    BB3  Audit entry written to tier1_updates.jsonl (tmp_path)
    BB4  apply_tier1 returns Tier1Result with correct counts

White Box Tests (WB1–WB4):
    WB1  Qdrant upsert uses "genesis_scars" collection name (mock verified)
    WB2  Rules file updates are append-only (existing content unchanged, new at end)
    WB3  KG entity file is valid JSONL (each line parseable as JSON)
    WB4  Prompt updates only create .md or .txt files (never .py)

ALL tests use mocks for Qdrant. ALL file I/O uses tmp_path.
    )annotationsN)Path)	MagicMockcallz/mnt/e/genesis-systemTier1AutonomousUpdaterTier1Result)ArchitectureAnalysis
BottleneckFixProposalc           
         t        |      D cg c]  }t        d| |dz   d| gd| g      ! }}t        |      D cg c]  }t        |dd|        }}t        ||| 	      S c c}w c c}w )
z9Return a populated ArchitectureAnalysis for use in tests.ztest bottleneck    saga_sc_description	frequencyaffected_saga_idsscar_ids	epistemicz!improve prompt quality iteration target_filechange_type	rationalebottlenecksrecommended_fixesscope)ranger   r   r
   )r   num_bottlenecks
fix_targetir   fixess         6/mnt/e/genesis-system/tests/track_b/test_story_8_08.py_make_analysisr%   9   s     '  	*1#.!e!&qc{mA3i[		
K  '  	"#9!=	
E    #s   $A)A.c           
         t        |t        | dz        t        | dz        t        | dz        t        | dz              S )z>Factory: Tier1AutonomousUpdater with all paths under tmp_path.kg_entitiespromptsGLOBAL_GENESIS_RULES.mdtier1_updates.jsonl)qdrant_clientkg_base_pathprompts_dir
rules_fileaudit_log_path)r   str)tmp_pathr+   s     r$   _make_updaterr2   W   sH    !#M129,-x";;<8&;;<     c                b   t        |       }t        d      }|j                  |d       | dz  }|dz  }|j                  } |       }|st	        j
                  d      dz   d	t        j                         v st	        j                  |      rt	        j                  |      nd	t	        j                  |      t	        j                  |      d
z  }t        t	        j                  |            dx}}|j                  } |       }|st	        j
                  d|       dz   dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      d
z  }t        t	        j                  |            dx}}y)zy
    BB1: After apply_tier1(), a KG entity JSONL file exists at
    {kg_base_path}/epoch_{epoch_id}_learnings.jsonl.
    r   r   test_epoch_001epoch_idr'   z$epoch_test_epoch_001_learnings.jsonlz!KG base directory was not createdC
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}kg_dirpy0py2py4Nz#Expected KG entity file not found: expected_file)r2   r%   apply_tier1exists
@pytest_ar_format_assertmsg@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanation)r1   updateranalysisr:   r?   @py_assert1@py_assert3@py_format5s           r$   test_bb1_kg_entity_file_createdrO   g   sL   
 H%GK0H+;<%FCCM==?=????????????6???6???=?????????? ! !   .m_=                  "     r3   c           	        t        |       }t        t        dddgdg      gt        ddd	      t        d
dd	      gd      }|j	                  |d       t        | j                  d            }|D cg c]%  }|j                         s|j                  dk(  s$|' }}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 cg c]  }t!        |       c}       dz   d|iz  }	t#        t        j$                  |	            dx}}yc c}w c c}w )z
    BB2: None of the files written by apply_tier1() have a .py extension.

    We walk ALL files under tmp_path after the call and assert that no .py
    file was created or modified.
    zprompt instruction unclear   s1sc1r   zcore/evolution/some_module.pyr   zshould not create .py filesr   config/prompts/system_prompt.mdprompt_updatezsafe updater   
no_py_testr7   *.py==z%(py0)s == %(py3)spy_filesr<   py3z)Tier 1 must NOT create .py files. Found: 
>assert %(py5)spy5N)r2   r
   r   r   r@   listrglobis_filesuffixrB   _call_reprcomparerD   rE   rF   rG   rC   r0   rH   rI   )
r1   rJ   rK   	all_filesfr\   @py_assert2rL   @py_format4@py_format6s
             r$   test_bb2_no_py_files_modifiedrk   z   so    H%G#8#'&	
 ;'7
 =+'
 +H0 <8 X^^C()I$Ja		E8IJHJ 8r>  8r                  4X4NSV4N3OP     K 5Os   5E8E8E82E=
c                   t        |       }t        d      }|j                  |d       | dz  }|j                  } |       }|st	        j
                  d      dz   dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      d	z  }t        t	        j                  |            d
x}}|j                  d      j                         D cg c]  }|j                         s| }}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}}
t#        j$                  |d         }h d}|t'        |j)                               z
  }| }|s~t	        j
                  d|       dz   ddt        j                         v st	        j                  |      rt	        j                  |      ndiz  }t        t	        j                  |            d
}|d   }d}||k(  }	|	slt	        j                   d|	fd||f      t	        j                  |      t	        j                  |      dz  }dd |iz  }t        t	        j                  |            d
x}x}	}|d!   }t+        |t,              }|sd"d#t        j                         v st	        j                  t*              rt	        j                  t*              nd#t	        j                  |      d$t        j                         v st	        j                  t,              rt	        j                  t,              nd$t	        j                  |      d%z  }t        t	        j                  |            d
x}}|d&   }t+        |t,              }|sd"d#t        j                         v st	        j                  t*              rt	        j                  t*              nd#t	        j                  |      d$t        j                         v st	        j                  t,              rt	        j                  t,              nd$t	        j                  |      d%z  }t        t	        j                  |            d
x}}|d'   }t+        |t,              }|sd"d#t        j                         v st	        j                  t*              rt	        j                  t*              nd#t	        j                  |      d$t        j                         v st	        j                  t,              rt	        j                  t,              nd$t	        j                  |      d%z  }t        t	        j                  |            d
x}}|d(   }t+        |t,              }|sd"d#t        j                         v st	        j                  t*              rt	        j                  t*              nd#t	        j                  |      d$t        j                         v st	        j                  t,              rt	        j                  t,              nd$t	        j                  |      d%z  }t        t	        j                  |            d
x}}y
c c}w ))z
    BB3: apply_tier1() appends one JSON line to {audit_log_path}.

    The entry must contain: timestamp, epoch_id, kg_entities_added,
    scars_updated, prompts_updated, rules_updated.
    r   r5   audit_test_epochr7   r*   zAudit file was not createdr9   
audit_filer;   Nutf-8encodingr   rY   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenlinesr<   py1r^   py6zExpected 1 audit line, got 
>assert %(py8)spy8r   >   r8   	timestamprules_updatedscars_updatedprompts_updatedkg_entities_addedzAudit entry missing fields: z
>assert not %(py0)sr<   missingr8   z%(py1)s == %(py4)srv   r>   assert %(py6)srw   r~   z5assert %(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
}
isinstanceintr<   r=   r^   r`   r|   r}   r{   )r2   r%   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   	read_text
splitlinesstriprs   re   jsonloadssetkeysr   r   )r1   rJ   rK   rn   rL   rM   rN   lrt   rh   @py_assert5@py_assert4@py_format7@py_format9entryrequired_keysr   @py_format2@py_assert0rj   s                       r$   test_bb3_audit_entry_writtenr      sN    H%GK0H+=>11J<<<< <<<<<<<:<<<:<<<<<<<<<<<<",,g,>IIKY1qwwyQYEYu:FF:?FFF:FFFFFF3FFF3FFFFFFuFFFuFFF:FFFFFF9#e*FFFFFFFFJJuQx EM
 c%**,//G;@;@@6wi@@@@@@@w@@@w@@@@@@2 22 22222 2222222 22222222/06:0#66666666:666:6660666666#666#6666666666O,2:,c22222222:222:222,222222c222c2222222222-.4:.44444444:444:444.4444444444444444444O,2:,c22222222:222:222,222222c222c2222222222! Zs   ]?$]?c                T   t        |       }t        ddd      }|j                  |d      }t        |t              }|s-t        j                  dt        |             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}|j                  }d}||kD  }|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      dz   d|iz  }	t        t        j                  |	            dx}x}}|j                   }d}||kD  }|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      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      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}}|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"                  }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}}y)!aF  
    BB4: apply_tier1 returns a Tier1Result with correct non-negative integer counts.

    We check that:
    - kg_entities_added > 0 (bottlenecks produce entities)
    - prompts_updated > 0 (epistemic fix with .md target)
    - rules_updated == 1 (epistemic scope with bottlenecks)
    - result is a Tier1Result instance
    r      rT   )r   r    r!   counts_testr7   z#Expected Tier1Result instance, got z7
>assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}r   resultr	   )r<   rv   r=   r>   Nr   >)z8%(py2)s
{%(py2)s = %(py0)s.kg_entities_added
} > %(py5)sr<   r=   r`   z7Expected at least one KG entity added for 2 bottlenecks
>assert %(py7)spy7)z6%(py2)s
{%(py2)s = %(py0)s.prompts_updated
} > %(py5)sz9Expected at least one prompt update for .md fix proposalsr   rY   z5%(py2)s
{%(py2)s = %(py0)s.rules_updated
} == %(py5)sz7Expected exactly 1 rule added for epistemic bottlenecks)>=)z5%(py2)s
{%(py2)s = %(py0)s.scars_updated
} >= %(py5)sassert %(py7)s)z9%(py2)s
{%(py2)s = %(py0)s.kg_entities_added
} >= %(py5)s)z7%(py2)s
{%(py2)s = %(py0)s.prompts_updated
} >= %(py5)s)z5%(py2)s
{%(py2)s = %(py0)s.rules_updated
} >= %(py5)s)r2   r%   r@   r   r	   rB   rC   typerD   rE   rF   rG   rH   rI   r~   re   r}   r{   r|   )
r1   rJ   rK   r   rM   rN   rL   r   rj   @py_format8s
             r$   +test_bb4_apply_tier1_returns_correct_countsr      s0    H%G4H   M BFfk* *   .d6l^<                         *    *    +      ## a #a'  #a              $    '(    	B     !! A !A%  !A              "    %&    	D      1 1$  1                   $%    	B     $1$1$$$$1$$$$$$6$$$6$$$$$$1$$$$$$$##(q(#q((((#q((((((6(((6(((#(((q(((((((!!&Q&!Q&&&&!Q&&&&&&6&&&6&&&!&&&Q&&&&&&&$1$1$$$$1$$$$$$6$$$6$$$$$$1$$$$$$$r3   c                *   t               }t        | |      }t        dd      }|j                  |d       |j                  }|j
                  }|st        j                  d      dz   d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      t        j                  |      d
z  }t        t        j                  |            dx}}|j                  j                  }|j                  r|j                  j!                  d      }n|j"                  r|j"                  d   nd}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z   d|
iz  }t        t        j                  |            dx}}	y)z
    WB1: _update_scars() calls qdrant_client.upsert(collection_name="genesis_scars", ...).

    We verify the collection name is exactly "genesis_scars" (not "scars" or anything else).
    r+   r   r   r   r    qdrant_testr7   z'qdrant_client.upsert() was never calledzH
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.upsert
}.called
}mock_qdrantr;   Ncollection_namer   genesis_scarsrY   r[   r]   z/Expected collection_name='genesis_scars', got ''r_   r`   )r   r2   r%   r@   upsertcalledrB   rC   rD   rE   rF   rG   rH   rI   	call_argskwargsgetargsre   )r1   r   rJ   rK   rL   rM   rN   call_kwargsr   rh   ri   rj   s               r$   4test_wb1_qdrant_upsert_uses_genesis_scars_collectionr      s    +KHK@GKCH=9 O$$O$OO&OOOOOOO;OOO;OOOOOO$OOOOOO $$..K%,,001BC1<1A1A+**1-t- ?o-  ?o              .    :/9J!L    r3   c                   | dz  }d}|j                  |d       t        |       }t        dd      }|j                  |d	       |j	                  d      }|j
                  } ||      }|st        j                  d
      dz   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t        j                  |      dz  }t        t        j                  |            dx}}|t        |      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}}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}}
y) ua  
    WB2: _append_rules() APPENDS new content — existing content is preserved unchanged.

    Steps:
    1. Write known sentinel text to rules_file.
    2. Run apply_tier1() with epistemic analysis.
    3. Assert sentinel text is still present at the START of the file.
    4. Assert new content exists AFTER the sentinel text (not replacing it).
    r)   zF## ORIGINAL RULE
This content must not be modified by Tier 1 updates.
ro   rp   r   r   r   append_testr7   uW   Original rules file content was modified — Tier 1 must never overwrite existing ruleszN
>assert %(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s.startswith
}(%(py3)s)
}contentsentinelr   Nr   r   z/%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} > %(py6)srs   new_contentru   z)No new content was appended to rules filerx   ry   zAUTO-APPENDED RULEinz%(py1)s in %(py3)srv   r^   z8Expected 'AUTO-APPENDED RULE' marker in appended contentr_   r`   )
write_textr2   r%   r@   r   
startswithrB   rC   rD   rE   rF   rG   rH   rI   rs   re   )r1   r.   r   rJ   rK   r   rL   r   rj   r   rh   r   r   r   r   ri   s                   r$   test_wb2_rules_file_append_onlyr     s    55JYH(W5H%GKCH=9""G"4G  h' '   	b                   '    '    (     
 #h-.)K{LaLaLLLaLLLLLL3LLL3LLLLLL{LLL{LLLLLLaLLL!LLLLLLLL ;.  ;           $/    $/    	C    r3   c           
        t        |       }t        t        ddddgdg      t        ddd	gd
g      gt        ddd      gd      }|j	                  |d       | dz  dz  }|j
                  } |       }|st        j                  d      dz   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}|j                  d      j                         D cg c]  }|j!                         s| }}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 ]  \  }}	 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  }t        j                  d%|d&z    d.|       d/z   d0|iz  }t        t        j                  |            dx}}	|d)   }d1}||v }	|	st        j$                  d*|	fd2||f      t        j                  |      t        j                  |      d3z  }t        j                  d%|d&z    d4|d)          d5z   d6|iz  }t        t        j                  |            dx}x}	}d7}||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    d8|       d/z   d0|iz  }t        t        j                  |            dx}}	|d7   }d}||k(  }	|	slt        j$                  d9|	fd:||f      t        j                  |      t        j                  |      d3z  }d;d6|iz  }t        t        j                  |            dx}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=|       d/z   d0|iz  }t        t        j                  |            dx}}	 yc c}w # t(        j,                  $ r,}t/        j0                  d%|d&z    d'| d(|       Y d}~d}~ww xY w)>a'  
    WB3: Every line in the epoch_{epoch_id}_learnings.jsonl file is parseable as JSON.

    Additional checks:
    - Each entry has a "type" field ("bottleneck" or "fix_proposal")
    - Each entry has an "epoch_id" field matching the provided epoch
    - Each entry has a "timestamp" field
    zmemory leak in context window   rR   s2rS   r   z prompt truncation on long inputsr   s3sc2zconfig/prompts/context.mdrU   zreduce context window usager   r   r   jsonl_valid_testr7   r'   z&epoch_jsonl_valid_test_learnings.jsonlzKG entity file was not createdr9   kg_filer;   Nro   rp   r   r   r   rs   rt   ru   zKG entity file is emptyrx   ry   zLine r   z is not valid JSON: z

Content: r   r   r   r   r   z missing 'type' field: r_   r`   )
bottleneckfix_proposal)z%(py1)s in %(py4)sr   z has unexpected type: z
>assert %(py6)srw   r8   z missing 'epoch_id': rY   r   r   rz   z missing 'timestamp': )r2   r
   r   r   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   r   r   r   rs   re   	enumerater   r   JSONDecodeErrorpytestfail)r1   rJ   rK   r   rL   rM   rN   r   rt   rh   r   r   r   r   r"   liner   excr   ri   rj   s                        r$   &test_wb3_kg_entity_file_is_valid_jsonlr   1  s    H%G#;#',	 >#'&	
 7+7
 -H2 +=>&)QQG>>=>==========7===7===>=========))7);FFHV1AGGIQVEVu:44:>444:44444434443444444u444u444:44444444444444U# R4	UJJt$E MvMMMvMMMvMMMMMMMMMMMMM%Aw.EeW MMMMMMMV} 	
 > 	
} >> 	
 	
} > 	
 	
 		  	
 	
 		 !? 	
 	
  AE70v@	
 	
 	
 	
 	
 OzU"OOOzUOOOzOOOOOOUOOOUOOOOeAE72Gw$OOOOOOOZ 6$66 $66666 $6666 666$66666666Q{e#QQQ{eQQQ{QQQQQQeQQQeQQQQuQUG3I%%QQQQQQQQR W ## 	UKK%Aw&:3%{4(STT	Us$   XXX""Y!5!YY!c                   t        |       }t        t        dddgdg      gt        ddd	      t        d
dd	      t        ddd	      t        ddd	      gd      }|j	                  |d       | dz  }|j
                  } |       }|st        j                  d      dz   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}t        |j                               }|D ch c]  }|j                    }	}|D ch c]  }|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  }t        j                  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}}t        | j'                  d&            }|D cg c]%  }|j)                         s|j"                  d'k(  s$|' }}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 cg c]  }t+        |       c}       d"z   d#|iz  }t        t        j                  |            dx}}d-}||
v}|st        j$                  d.|fd/||
f      t        j                  |      d0t        j                         v st        j                  |
      rt        j                  |
      nd0d z  }t        j                  d1      d"z   d#|iz  }t        t        j                  |            dx}}|D ]  }|j)                         s|j"                  }d2}||v }|st        j$                  d|fd3||f      d4t        j                         v st        j                  |      rt        j                  |      nd4t        j                  |      t        j                  |      d5z  }t        j                  d6|j                          d7z   d8|iz  }t        t        j                  |            dx}x}} yc c}w c c}w c c}w c c}w )9u   
    WB4: _update_prompts() creates only .md or .txt files — never .py or any other extension.

    We provide fixes with various target extensions and assert only the safe ones
    produce output files in prompts_dir.
    zprompt unclearr   rR   rS   r   zconfig/prompts/safe_template.mdrU   zsafe mdr   zconfig/prompts/safe_notes.txtzsafe txtzcore/evolution/dangerous.pyrefactorzshould not be createdzdata/output/result.jsondataznot a prompt formatr   r   prompt_extension_testr7   r(   z!Prompts directory was not createdr9   r-   r;   Nzsafe_template.mdr   r   created_namesr   z6Expected safe_template.md to be created in prompts_dirr_   r`   zsafe_notes.txtz4Expected safe_notes.txt to be created in prompts_dirrW   rX   rY   r[   	forbiddenr]   zFound forbidden .py files: z.json)not in)z%(py1)s not in %(py3)screated_suffixesz*Prompts dir should not contain .json files)z.mdz.txt)z.%(py2)s
{%(py2)s = %(py0)s.suffix
} in %(py5)srg   r   z*Unexpected file extension in prompts_dir: r   r   )r2   r
   r   r   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   ra   iterdirnamerd   re   rb   rc   r0   )r1   rJ   rK   r-   rL   rM   rN   created_filesrg   r   r   r   rh   ri   rj   rf   r   r   r   s                      r$   3test_wb4_prompt_updates_only_create_md_or_txt_filesr   k  s    H%G#,#'&	
 =+#
 ;+$
 9&1
 5"/!
, ? HD +BCY&KDDDD!DDDDDDD;DDD;DDDDDDDDDDDD,,./M%23QVV3M3*78Q88  .            "/    "/    	A      },  }           -     -    	?    
 X^^C()I%KqU9JKIK 9?  9                  &y&A!s1v&A%BC    
  7**  7*          +    +    	5    
  99;88  8.  8  v     I   I   I  /    =QVVHE     1 48 L&As$   W(WW'W7WW 
c                 ~   ddl } | j                  } |t              }|sddt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            dx}}| j                  t              D ch c]  }|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}}yc c}w )z7Tier1Result is a proper dataclass with required fields.r   NzNassert %(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s.is_dataclass
}(%(py3)s)
}dataclassesr	   r   r~   r   r   field_namesr   assert %(py5)sr`   r|   r}   r{   )r   is_dataclassr	   rD   rE   rB   rF   rG   rH   rI   fieldsr   re   )	r   rL   r   rj   rg   r   r   rh   ri   s	            r$   test_tier1result_is_dataclassr     s   ##0#K00000000;000;000#000000K000K0000000000#.#5#5k#BCa166CKC-+----+---------+---+-------)?k))))?k)))?))))))k)))k)))))))++++++++++++++++++++++++)?k))))?k)))?))))))k)))k)))))))	 Ds   N:c                2   t        | 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  }t	        j                  d|j                         dz   d|iz  }t        t	        j                  |            dx}x}}y)zDWhen qdrant_client is None, _update_scars returns 0 without raising.Nr   r   r5   no_qdrant_testr7   r   rY   z5%(py2)s
{%(py2)s = %(py0)s.scars_updated
} == %(py5)sr   r   z4Expected scars_updated=0 when no Qdrant client, got r   r   )r2   r%   r@   r|   rB   re   rD   rE   rF   rG   rC   rH   rI   	r1   rJ   rK   r   rL   r   rM   rj   r   s	            r$   2test_no_qdrant_client_skips_scar_update_gracefullyr     s    HD9GK0H  4D EF  1 1$  1                   $%    ?v?S?S>TU     r3   c                   t        |       }t        g g 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}}|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}}y)u<   Empty ArchitectureAnalysis → all Tier1Result fields are 0.r   r   
empty_testr7   r   rY   )z9%(py2)s
{%(py2)s = %(py0)s.kg_entities_added
} == %(py5)sr   r   r   r   Nr   )z7%(py2)s
{%(py2)s = %(py0)s.prompts_updated
} == %(py5)sr   )r2   r
   r@   r~   rB   re   rD   rE   rF   rG   rH   rI   r|   r}   r{   )	r1   rJ   empty_analysisr   rL   r   rM   rj   r   s	            r$   (test_empty_analysis_produces_zero_countsr     s   H%G)bBVabN  , GF##(q(#q((((#q((((((6(((6(((#(((q((((((($1$1$$$$1$$$$$$6$$$6$$$$$$1$$$$$$$!!&Q&!Q&&&&!Q&&&&&&6&&&6&&&!&&&Q&&&&&&&$1$1$$$$1$$$$$$6$$$6$$$$$$1$$$$$$$r3   c                \   t        |       }t        d      }|j                  |d       |j                  |d       | dz  }|j                  d      j	                         D cg c]  }|j                         s| }}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}}|D cg c]  }t!        j"                  |      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  }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}}yc c}w c c}w )uA   Each call to apply_tier1() appends a NEW line — not overwrites.r   r5   run_1r7   run_2r*   ro   rp   r   rY   rr   rs   rt   ru   z(Expected 2 audit lines for 2 calls, got rx   ry   Nr8   r   r   epochsr   r   r`   )r2   r%   r@   r   r   r   rs   rB   re   rD   rE   rF   rG   rC   rH   rI   r   r   )r1   rJ   rK   rn   r   rt   rh   r   r   r   r   r   r   ri   rj   s                  r$   /test_multiple_calls_append_multiple_audit_linesr     s   H%GK0H737311J",,g,>IIKY1qwwyQYEYu:SS:?SSS:SSSSSS3SSS3SSSSSSuSSSuSSS:SSSSSSFs5zlSSSSSSSS167AdjjmJ'7F77f7f7ff7f7f7ff Z 8s   %L$;L$8L)c                   t        |       }t        d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  }t	        j                  d      dz   d|iz  }t        t	        j                  |            dx}x}}y)zIOntological scope analysis should NOT append rules (that's for PR scope).ontologicalr   r   ontological_testr7   r   rY   r   r   r   z@Tier 1 must not append rules for ontological (code-change) scoper   r   N)r2   r%   r@   r{   rB   re   rD   rE   rF   rG   rC   rH   rI   r   s	            r$   )test_ontological_scope_skips_rules_updater     s    H%GM1EH  4F GF 1 1$  1                   $%    	K     r3   c                    ddl 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
}y
)zJcore.evolution.__init__.py exports Tier1AutonomousUpdater and Tier1Result.r   r   )is)z%(py0)s is %(py2)sT1Ur   )r<   r=   zassert %(py4)sr>   NT1Rr	   )core.evolutionr   r	   rB   re   rD   rE   rF   rG   rH   rI   )r   r   rL   @py_format3rN   s        r$   'test_package_init_exports_tier1_classesr     s    
 (((((3(((((((3(((3((((((((((((((((((+3+33++r3   c                   t        |       }t        t        dddgdg      gt        ddd	      gd
      }|j	                  |d       | dz  dz  }|j                         ra|j                  d      j                         D cg c]  }|j                         s| }}|D ]  }t        j                  |      }|j                  d      dk(  s.|j                  dd      }|j                  }	d}
 |	|
      }| }|st        j                  d|       dz   dt        j                          v st        j"                  |      rt        j$                  |      ndt        j$                  |	      t        j$                  |
      t        j$                  |      dz  }t'        t        j(                  |            dx}	x}
x}} yyc c}w )zEFix proposals targeting .py files must not appear in KG entity files.zprompt issuer   rR   rS   r   zcore/evolution/example.pyr   zcode fixr   r   r   py_exclusion_testr7   r'   z'epoch_py_exclusion_test_learnings.jsonlro   rp   r   r   r    rX   z0KG entity must not reference .py fix proposals: zP
>assert not %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.endswith
}(%(py4)s)
}target)r<   r=   r>   rw   N)r2   r
   r   r   r@   rA   r   r   r   r   r   r   endswithrB   rC   rD   rE   rF   rG   rH   rI   )r1   rJ   rK   r   r   rt   r   r   r  rL   rM   r   @py_assert7r   s                 r$   /test_py_fix_proposals_excluded_from_kg_entitiesr    s   H%G#*#'&	
 7&$
 !H& +>?&)RRG~~#--w-?JJLZqPQPWPWPYZZ 	DJJt$Eyy N2="5!?? 5 ?51 11 1    GugN 6   "  	 "  	 +  	 ,1  	 2      		 Zs   GG__main__c                  "    e Zd Zd ZddZddZy)_Tmpc                H    t        t        j                               | _        y N)r   tempfilemkdtemp_dir)selfs    r$   __init__z_Tmp.__init__:  s    X--/0DIr3   c                     | j                   |z  S r
  )r  )r  r   s     r$   __truediv__z_Tmp.__truediv__=  s    99t##r3   c                8    | j                   j                  |      S r
  )r  rb   )r  patterns     r$   rb   z
_Tmp.rglob@  s    99??7++r3   N)r   r0   returnr   )r  r0   )__name__
__module____qualname__r  r  rb    r3   r$   r  r  9  s    	1	$	,r3   r  zBB1: KG entity file createdzBB2: No .py files modifiedzBB3: Audit entry writtenzBB4: Returns correct countsz)WB1: Qdrant uses genesis_scars collectionzWB2: Rules file append-onlyzWB3: KG JSONL is validzWB4: Prompt only .md/.txtz	  [PASS] r   z	  [FAIL] z: 
/z tests passedu   ALL TESTS PASSED — Story 8.08)r   r   rT   )r   r0   r    r   r!   r0   r  r
   r
  )r1   r   r  r   );__doc__
__future__r   builtinsrD   _pytest.assertion.rewrite	assertionrewriterB   r   syspathlibr   unittest.mockr   r   r   GENESIS_ROOTpathinsert'core.evolution.tier1_autonomous_updaterr   r	   core.evolution.meta_architectr
   r   r   r%   r2   rO   rk   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  	tracebackr  testspassedr   fntmpprint	Exceptionr   	print_excrs   exitr  r3   r$   <module>r2     s  ( #    
  )  'sxxHHOOA|$  7  	< &)X3D#%V8D7RtLh	*

%"	!P z, , 
'(GH	%'DE	#%AB	&(ST	46jk	&(GH	!#IJ	$&YZ	E F "bf	"sGIdV$%aKF" 
BvhaE
|=
12U/0Q @  	"IdV2cU+,I!!	"s   2E		E7E22E7