
    ,"i@E              	         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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mZmZ ddlmZmZmZmZ d,dZd-d	Z 	 	 	 	 	 	 	 	 d.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/e0dk(  rddl1Z1 G d d      Z2de"fde#fde$fde%fd e&fd!e'fd"e(fd#e)fgZ3dZ4e3D ]%  \  Z5Z6 e2       Z7	  e6e7        e8d$e5        e4d%z  Z4'  e8d(e4 d) e<e3       d*       e4 e<e3      k(  r	 e8d+       y e
jz                  d%       yy# e9$ r)Z: e8d&e5 d'e:         e1jv                          Y dZ:[:dZ:[:ww xY w)/uP  
tests/track_b/test_story_8_03.py

Story 8.03 (Track B): MetaArchitect — Scar-Driven Structural Analysis

Black Box Tests (BB1–BB4):
    BB1  10 failed sagas in last 7 days → at least 1 bottleneck identified
    BB2  scope="epistemic" returned for prompt-fixable issues
    BB3  Analysis written to meta_architect_log.jsonl (tmp_path)
    BB4  Empty scars + empty sagas → ArchitectureAnalysis with empty bottlenecks, scope="epistemic"

White Box Tests (WB1–WB4):
    WB1  Qdrant query groups similar scars (cluster, not per-scar)
    WB2  lookback_days parameter drives Postgres interval correctly
    WB3  _determine_scope returns "ontological" when any bottleneck affects .py files
    WB4  Log entry is valid JSON with required fields

ALL tests use mocks — no real Qdrant or Postgres connections.
tmp_path is used for all file I/O.
    )annotationsN)Path)	MagicMockpatchcallz/mnt/e/genesis-system)MetaArchitectArchitectureAnalysis
BottleneckFixProposalc           	         t               }| D cg c]-  }|d   d|j                  dd      i|j                  dg       d/ }}||j                  _        |S c c}w )z
    Build a mock Qdrant client whose scroll() returns ``scars``.

    Each scar dict should have "id", "payload" (with "description"), and
    optionally "vector".  The scroll() return value is a list of point-like
    dicts with the same shape.
    iddescription vector)r   payloadr   )r   getscrollreturn_value)scarsmockspointss       6/mnt/e/genesis-system/tests/track_b/test_story_8_03.py_make_mock_qdrantr   >   sn     ;D  	 D'%quu]B'?@eeHb)	
F   &DKKKs   2Ac           	         t               }t               }| D cg c]*  }|d   |j                  dd      |j                  dd      f, }}||j                  _        ||j                  _        |S c c}w )z
    Build a mock psycopg2-like connection whose cursor().fetchall() returns
    rows in the format (id, description, error_trace).
    r   r   r   error_trace)r   r   fetchallr   cursor)sagas	mock_connmock_cursorr   rowss        r   _make_mock_pgr#   T   sn    
 I+KSXYaQtWaeeM2.mR0HIYDY(,K%$/I! Zs   /A.c                T    t        |       }t        |      }|dz  }t        |||      S )z>Factory: MetaArchitect with mocked clients and a tmp log path.meta_architect_log.jsonlqdrant_clientpg_connectionlog_path)r   r#   r   )r   r   tmp_pathqdrantpglogs         r   _make_architectr.   a   s2     u%F	u	B
/
/CvR#NN    c                   t        d      D cg c]  }d|dddd }}t        d      D cg c]  }d|ddd	 }}t        |||       }|j                  d
      }t        |t              }|sd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                  }t        |      }	d}
|	|
k\  }|s6t        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                  |	      t        j                  |
      dz  }t        j                  dt        |j                               dz   d|iz  }t        t        j                  |            dx}x}	x}}
yc c}w c c}w )uO   BB1: 10 PARTIAL_FAIL sagas in last 7 days → at least 1 bottleneck identified.
   zsaga-02dztimeout connecting to redisr   r   r   r      zscar-r   r      lookback_days5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstanceanalysisr	   py0py1py2py4N   >=)zQ%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.bottlenecks
})
} >= %(py8)slen)r=   r>   py3py5py8u!   Expected ≥1 bottleneck but got z
>assert %(py10)spy10)ranger.   analyzer:   r	   @py_builtinslocals
@pytest_ar_should_repr_global_name	_safereprAssertionError_format_explanationbottlenecksrD   _call_reprcompare_format_assertmsg)r*   ir   r   	architectr;   @py_assert3@py_format5@py_assert2@py_assert4@py_assert7@py_assert6@py_format9@py_format11s                 r   9test_bb1_ten_failed_sagas_produce_at_least_one_bottleneckr_   r   sJ    r qg/L]_`E  q qg/LME 
  uh7I  q 1Hh 455555555:555:555555h555h555555 4555 45555555555## 3#$  $)   $                        $    %    )*    ,C0D0D,E+FG     
s
   KK$c                <   ddddddg}ddddg}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      dz   d|iz  }	t        t        j                  |	            dx}x}}y)uF   BB2: Bottleneck description containing 'prompt' → scope='epistemic'.scar-01zprompt instruction ambiguousr5   scar-02saga-01r   r3   r6   r7   	epistemic==z-%(py2)s
{%(py2)s = %(py0)s.scope
} == %(py5)sr;   r=   r?   rF   z$Expected scope='epistemic' but got ''
>assert %(py7)spy7N)r.   rJ   scoperM   rS   rK   rL   rN   rO   rT   rP   rQ   )
r*   r   r   rV   r;   @py_assert1rZ   rW   @py_format6@py_format8s
             r   2test_bb2_epistemic_scope_for_prompt_fixable_issuesrp      s    )GH)GHE
 )GXZ[E  uh7I  q 1H>> [ >[(  >[                  )    /x~~.>a@     r/   c                <   dddg}ddddg}t        |||       }| dz  }||_        |j                  d	
       |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      dz   d|iz  }t        t	        j                  |            dx}
x}}|	D ]8  }t#        j$                  |      }t'        |t(              }|sd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}; yc c}w ) zIBB3: analyze() writes at least one JSON line to meta_architect_log.jsonl.ra   znetwork timeoutr5   rc   znetwork timeout failurer   r3   r%   r6   r7   zLog file was not created.C
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}r)   r=   r?   r@   Nutf-8encodingrA   rB   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} >= %(py6)srD   linesr=   r>   rE   py6zLog file has no entries.
>assert %(py8)srG   r9   r:   parseddictr<   )r.   r)   rJ   existsrM   rT   rK   rL   rN   rO   rP   rQ   	read_text
splitlinesstriprD   rS   jsonloadsr:   r|   )r*   r   r   rV   r)   rm   rW   rX   linerw   rY   @py_assert5rZ   @py_format7r]   r{   s                   r   &test_bb3_analysis_written_to_jsonl_logr      s3   .?@AE.GXZ[\Euh7I44H!IA&??9?999999999989998999?999999999&00'0BMMO`dSWS]S]S_T`E`u:66:?666:66666636663666666u666u666:66666666666666  (D!&$''''''''z'''z''''''&'''&''''''$'''$''''''''''(	 as   N-Nc                0   t        g g |       }|j                  d      }t        |t              }|sd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                  }g }||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      dz   d|iz  }t        t        j                  |            dx}x}}y)u[   BB4: Empty scars + empty sagas → ArchitectureAnalysis(bottlenecks=[], scope='epistemic').r6   r7   r9   r:   r;   r	   r<   Nre   z3%(py2)s
{%(py2)s = %(py0)s.bottlenecks
} == %(py5)srh   z!Expected empty bottlenecks, got: rj   rk   rd   rg   z"Expected scope='epistemic', got: 'ri   )r.   rJ   r:   r	   rK   rL   rM   rN   rO   rP   rQ   rR   rS   rT   rl   )	r*   rV   r;   rW   rX   rm   rZ   rn   ro   s	            r   5test_bb4_empty_scars_and_sagas_returns_empty_analysisr      sA   B1I  q 1Hh 455555555:555:555555h555h555555 4555 45555555555 2 2%  2                   $&    ,H,@,@+AB     >> [ >[(  >[                  )    -X^^,<A>     r/   c                V   dddddddddg}t        |g |       }|j                  |      }|D cg c]  }t        |       }}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}}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}}yc c}w )u3  
    WB1: _cluster_scars groups semantically similar scars into a single cluster
    rather than creating one cluster per scar.

    We use identical descriptions (no real vectors) to force text-based clustering.
    3 scars with the same description → 1 cluster of size 3 (not 3 clusters of size 1).
    ra   zredis connection refusedr5   rb   scar-03r4   re   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)smaxcluster_sizesrx   z:Expected at least 1 cluster of size 3, got cluster sizes: rz   rG   NrA   rD   clusterszExpected 1 cluster but got : )r.   _cluster_scarsrD   r   rM   rS   rK   rL   rN   rO   rT   rP   rQ   )r*   r   rV   r   cr   rY   r   rZ   r   r]   s              r   3test_wb1_similar_scars_are_grouped_into_one_clusterr      se    )CD)CD)CDE  r84I''.H &..SV.M.}  "                               "#    E]OT     x= A =A   =A                                &c(m_B}oF     	 /s   J&c                   ddddg}t        |      }t        t        g       || dz        }|j                  d       |j                  j
                  }|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                   d   d   }d}	|	|v }
|
st        j"                  d|
fd|	|f      t        j                  |	      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d|      dz   d|iz  }t        t        j                  |            dx}	}
y)zX
    WB2: _query_sagas uses the lookback_days parameter in the SQL INTERVAL clause.
    rc   testr   r3   	log.jsonlr&      r7   z!cursor.execute() was never calledzI
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.execute
}.called
}r!   rs   Nr   z14 daysinz%(py1)s in %(py3)sexecuted_sqlr>   rE   z#Expected '14 days' in SQL but got: 
>assert %(py5)srF   )r#   r   r   rJ   r   r   executecalledrM   rT   rK   rL   rN   rO   rP   rQ   	call_argsrS   )r*   r   r    rV   r!   rm   rW   rX   r   @py_assert0rY   @py_format4rn   s                r   /test_wb2_lookback_days_drives_postgres_intervalr      s    fRHIEe$I'+K'I B' ""//KJ%%J%JJ'JJJJJJJ;JJJ;JJJJJJ%JJJJJJ&&003A6L 9$  9          %    %    .l-=>    r/   c                   t        g g |       }t        dddgdg      g}|j                  |      }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}}t        dddgdg      g}|j                  |      }	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
    WB3: _determine_scope returns 'ontological' when a bottleneck description
    references a .py file or code-level artefact.
    z)failure in router.py causes dispatch loopr4   rc   ra   )r   	frequencyaffected_saga_idsscar_idsontologicalre   )z%(py0)s == %(py3)srl   )r=   rE   z<Expected 'ontological' for .py-referencing bottleneck, got 'ri   r   rF   Nz1prompt instruction unclear causing wrong response   zsaga-02rb   rd   scope_epz9Expected 'epistemic' for prompt-fixable bottleneck, got ')r.   r
   _determine_scoperM   rS   rK   rL   rN   rO   rT   rP   rQ   )
r*   rV   bottlenecks_ontologicalrl   rY   rm   r   rn   bottlenecks_epistemicr   s
             r   Ctest_wb3_determine_scope_returns_ontological_for_py_file_bottleneckr      s   
  B1I 	C(k[		
 &&'>?E! 5M!  5M              "    GugQO     	K(k[		
 ))*?@H" 8{"  8{              #    DH:QO    r/   c                   dddg}ddddg}| dz  }t        t        |      t        |      |	      }|j                  d
       |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| }	}|	s{t        j                  d      dz   ddt        j                         v st        j                  |	      rt        j                  |	      ndiz  }
t        t        j                  |
            h d}|	D ]  }t!        j"                  |      }|t%        |j'                               z
  }| }|st        j                  d| d|       dz   ddt        j                         v st        j                  |      rt        j                  |      ndiz  }t        t        j                  |            d}g }|d   }t)        |t*              }|}|r|d   }|}|s<d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  }|j-                  |       |r+d!d"t        j                        iz  }|j-                  |       t        j.                  |d#      i z  }d$d%|iz  }t        t        j                  |            dx}x}x}x}}|d&   }t)        |t0              }|sd'dt        j                         v st        j                  t(              rt        j                  t(              ndt        j                  |      d(t        j                         v st        j                  t0              rt        j                  t0              nd(t        j                  |      d)z  }t        t        j                  |            dx}}|d*   }d+}||v }|slt        j2                  d,|fd-||f      t        j                  |      t        j                  |      d.z  }d/d0|iz  }t        t        j                  |            dx}x}}|d1   }t)        |t0              }|sd'dt        j                         v st        j                  t(              rt        j                  t(              ndt        j                  |      d(t        j                         v st        j                  t0              rt        j                  t0              nd(t        j                  |      d)z  }t        t        j                  |            dx}}|d2   }t)        |t0              }|sd'dt        j                         v st        j                  t(              rt        j                  t(              ndt        j                  |      d(t        j                         v st        j                  t0              rt        j                  t0              nd(t        j                  |      d)z  }t        t        j                  |            dx}}|d3   }t)        |t4              }|sd'dt        j                         v st        j                  t(              rt        j                  t(              ndt        j                  |      d4t        j                         v st        j                  t4              rt        j                  t4              nd4t        j                  |      d)z  }t        t        j                  |            dx}}|d5   }t)        |t4              }|sd'dt        j                         v st        j                  t(              rt        j                  t(              ndt        j                  |      d4t        j                         v st        j                  t4              rt        j                  t4              nd4t        j                  |      d)z  }t        t        j                  |            dx}} yc c}w )6z
    WB4: Each line in the log is valid JSON containing:
        timestamp, lookback_days, scope, bottleneck_count, fix_count,
        bottlenecks (list), recommended_fixes (list)
    ra   ztimeout in memory lookupr5   rc   zmemory lookup timeoutr   r3   r%   r&      r7   zLog file was not written.rr   r)   rs   Nrt   ru   zNo log lines were written.z
>assert %(py0)sr=   rw   >   rl   	fix_count	timestamprR   r8   bottleneck_countrecommended_fixeszLog entry missing fields: z	. Entry: z
>assert not %(py0)smissingr   z.%(py7)s
{%(py7)s = %(py2)s(%(py4)s, %(py5)s)
}r:   str)r?   r@   rF   rk   z%(py10)srH   r   zassert %(py13)spy13r8   z5assert %(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
}intr=   r?   rE   rF   rl   )rd   r   r   )z%(py1)s in %(py4)s)r>   r@   zassert %(py6)sry   r   r   rR   listr   )r   r   r#   rJ   r}   rM   rT   rK   rL   rN   rO   rP   rQ   r~   r   r   r   r   setkeysr:   r   append_format_boolopr   rS   r   )r*   r   r   r)   rV   rm   rW   rX   lrw   @py_format1required_fieldsr   entryr   @py_format2r\   r   @py_assert9ro   r^   @py_format12@py_format14rZ   rn   rY   r   s                              r   5test_wb4_log_entry_is_valid_json_with_required_fieldsr     sa    .HIJE.EVXYZE44H'.#E*I
 A&??9?999999999989998999?999999999 **G*<GGIW1QWWYQWEW.........5...5.....O  <

4 !C

$55{R{RR8	5'RRRRRRR7RRR7RRRRRR 	J%,Iz,c2I2I2u[7II7IIIIIIIzIIIzIII,IIIIIIcIIIcIII2IIII2III7IIIIIIIIIIIIII06z0#66666666z666z6660666666#666#6666666666W~=!==~!=====~!====~===!======== 239z3S99999999z999z9993999999S999S9999999999,2z,c22222222z222z222,222222c222c2222222222.5z.55555555z555z555.5555555555555555555 34;z4d;;;;;;;;z;;;z;;;4;;;;;;d;;;d;;;;;;;;;;< Xs   #e
9e
c                 t   t         t        u } | st        j                  d| fdt         t        f      dt	        j
                         v st        j                  t               rt        j                  t               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        t        u } | st        j                  d| fdt        t        f      d	t	        j
                         v st        j                  t              rt        j                  t              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        t        u } | st        j                  d| fdt        t        f      dt	        j
                         v st        j                  t              rt        j                  t              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        t        u } | st        j                  d| fdt        t        f      dt	        j
                         v st        j                  t              rt        j                  t              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)z]core.evolution.__init__ exports MetaArchitect, ArchitectureAnalysis, Bottleneck, FixProposal.)is)z%(py0)s is %(py2)sMetaArchitectFromInitr   )r=   r?   zassert %(py4)sr@   NArchitectureAnalysisFromInitr	   BottleneckFromInitr
   FixProposalFromInitr   )r   r   rM   rS   rK   rL   rN   rO   rP   rQ   r   r	   r   r
   r   r   )rm   @py_format3rX   s      r   'test_pkg_exports_meta_architect_classesr   L  s    M1111 M111111 111 111111M111M1111111'+?????'+???????'???'??????+????+????????++++++++++++++++++++++++++++++----+---------------+---+-------r/   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}}| 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}}| 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}}yc c}w c c}w c c}w )z2All four dataclasses expose their required fields.r   NzNassert %(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s.is_dataclass
}(%(py3)s)
}dataclassesr	   r   rR   r   r   	aa_fieldsr   zassert %(py5)srF   r   rl   r
   r   b_fieldsr   r   r   r   target_file	fp_fieldschange_type	rationale)r   is_dataclassr	   rK   rL   rM   rN   rO   rP   rQ   fieldsnamerS   r
   r   )r   rm   rZ   rn   fr   r   rY   r   r   r   s              r   test_dataclass_fields_existr   Y  s    ##9#$899999999;999;999#999999$8999$89999999999!,!3!34H!IJAJIJ%=I%%%%=I%%%=%%%%%%I%%%I%%%%%%%+)++++)+++++++++)+++)+++++++7i7i7ii ##/#J////////;///;///#//////J///J////////// + 2 2: >?1?H?$=H$$$$=H$$$=$$$$$$H$$$H$$$$$$$";("""";(""";""""""("""("""""""*(****(*********(***(*******!:!!!!:!!!:!!!!!!!!!!!!!!!! ##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!,!3!3K!@AAAIA%=I%%%%=I%%%=%%%%%%I%%%I%%%%%%%%=I%%%%=I%%%=%%%%%%I%%%I%%%%%%%#;)####;)###;######)###)#######% K @ Bs   ggg"c                    t               } | j                  }g }||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                  }g }||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)z+ArchitectureAnalysis has sensible defaults.re   r   aarh   assert %(py7)srk   N)z9%(py2)s
{%(py2)s = %(py0)s.recommended_fixes
} == %(py5)srd   rg   )r	   rR   rM   rS   rK   rL   rN   rO   rP   rQ   r   rl   )r   rm   rZ   rW   rn   ro   s         r   #test_architecture_analysis_defaultsr   t  sV   		B>>R>R>R22>R%2%2%%%%2%%%%%%2%%%2%%%%%%2%%%%%%%88"{"8{""""8{""""""2"""2"""8"""{"""""""r/   c                ^   g d}dd|ddd|ddd|dg}t        g g |       }|j                  |      }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}}|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  }dd|iz  }t        t        j                  |            dx}
x}x}}y)uP   Scars with identical vectors cluster into one group (cosine sim = 1.0 ≥ 0.85).      ?        r   ra   z	oom errorr   r   r   rb   r   rA   re   r   rD   r   rx   zassert %(py8)srG   Nr   r4   )z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py7)s)r=   r?   r@   rk   zassert %(py9)spy9)r.   r   rD   rM   rS   rK   rL   rN   rO   rP   rQ   )r*   vecr   rV   r   rY   r   rZ   r   r]   rm   rW   r\   ro   @py_format10s                  r   <test_cosine_clustering_identical_vectors_produce_one_clusterr     s]   
CDDDE  B1I''.Hx=A=A=A33xx=A{ 3{ q q    q      3   3   {      q       r/   c                   ddg ddddg dddd	g d
dg}t        g g |       }|j                  |      }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}}y)zAOrthogonal vectors (cosine sim = 0.0) each get their own cluster.ra   zerr Ar   r   rb   zerr B)r   r   r   r   zerr C)r   r   r   r4   re   r   rD   r   rx   z0Expected 3 clusters for orthogonal vectors, got rz   rG   N)r.   r   rD   rM   rS   rK   rL   rN   rO   rT   rP   rQ   )	r*   r   rV   r   rY   r   rZ   r   r]   s	            r   Ctest_cosine_clustering_orthogonal_vectors_produce_separate_clustersr     sH    OLOLOLE  B1I''.Hx= A =A   =A                                ;3x=/J     r/   c                   | dz  }t        |      }|j                  d      }|j                  }g }||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                  } |       }|sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	t        t        j                  |	            dx}}y)zJMetaArchitect with no injected clients returns empty analysis, writes log.r   )r)   r6   r7   re   r   r;   rh   r   rk   Nrd   rg   zAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}r)   rs   )r   rJ   rR   rM   rS   rK   rL   rN   rO   rP   rQ   rl   r}   )
r*   r)   rV   r;   rm   rZ   rW   rn   ro   rX   s
             r   &test_no_clients_returns_empty_analysisr     sb   +%Hx0I  q 1H%2%2%%%%2%%%%%%8%%%8%%%%%%2%%%%%%%>>([(>[((((>[((((((8(((8(((>((([(((((((???88?r/   __main__c                      e Zd ZdZd ZddZy)_TmpDirz.Minimal tmp_path stand-in for standalone runs.c                >    dd l }dd l}|j                         | _        y )Nr   )tempfileosmkdtemp_dir)selfr   r   s      r   __init__z_TmpDir.__init__  s     ((*DIr/   c                2    t        | j                        |z  S )N)r   r   )r   r   s     r   __truediv__z_TmpDir.__truediv__  s    		?T))r/   N)r   r   returnr   )__name__
__module____qualname____doc__r   r    r/   r   r   r     s    <	+	*r/   r   u!   BB1: 10 sagas → ≥1 bottlenecku%   BB2: prompt scars → scope=epistemiczBB3: log written to JSONLu$   BB4: empty inputs → empty analysisu    WB1: similar scars → 1 clusterzWB2: lookback_days in SQLu#   WB3: .py bottleneck → ontologicalzWB4: log fields validz	  [PASS] rA   z	  [FAIL] r   
/z tests passedu   ALL TESTS PASSED — Story 8.03)r   
list[dict]r   r   )r   r  r   r   )r   r  r   r  r*   r   r   r   )>r   
__future__r   builtinsrK   _pytest.assertion.rewrite	assertionrewriterM   r   syspathlibr   unittest.mockr   r   r   pytestGENESIS_ROOTpathinsertcore.evolution.meta_architectr   r	   r
   r   core.evolutionr   r   r   r   r   r#   r.   r_   rp   r   r   r   r   r   r   r   r   r   r   r   r   r   	tracebackr   testspassedr   fntmpprint	Exceptionexc	print_excrD   exitr   r/   r   <module>r     s  * #    
  0 0  'sxxHHOOA|$  ,
	O	O	O 	O 		O"*$(*&62!H+<f.$6#! * z* * 
-.gh	02de	$&LM	/1fg	+-`a	$&UV	.0st	 "WX	E F "bi	"sGIdV$%aKF" 
BvhaE
|=
12U/0M <  	"IdV2cU+,I!!	"s   3E

E8E33E8