
    i                    8   U d Z ddlmZ ddlZddlmc mZ ddl	Z	ddl
Z
ddlZddlZddlZddlmZ ddlmZ ddlmZ ddlmZ ddlmZmZmZ ddlZd	Zeej6                  vrej6                  j9                  de       dd
lmZmZ ddl m!Z!m"Z" ddl#m$Z$ ddl%m&Z&m'Z' ddl(m)Z)m*Z* ddl+m,Z, 	 	 d2	 	 	 	 	 	 	 	 	 d3dZ-d4dZ.d5d6dZ/d7d8dZ0d Z1d9d:dZ2ddddidZ3de4d<   d Z5d Z6d Z7d  Z8d! Z9d" Z:d# Z;d$ Z<d% Z=d& Z>d' Z?d( Z@d) ZAd* ZBd+ ZCd, ZDd- ZEd. ZFd/ ZGd0 ZHd1 ZIy);u   
tests/merge/test_semantic_merge.py

Module 7 Integration Tests — Semantic Merge Pipeline
Story B-7.07: Test Suite — Module 7 Semantic Merge

Tests the full flow:
    ConflictDetector → SemanticMergeInterceptor → PatchReconciler → MergeTelemetry

ALL tests use mocks — NO real Opus/API calls, NO real Redis connections.

Test Plan (14+ tests):
    BB1: Non-conflicting merge → fast path (used_opus=False)
    BB2: Conflicting merge → Opus called, unified patch returned
    BB3: Axiom violation ("API_KEY" in state) → PatchReconciler valid=False
    BB4: Axiom violation ("sqlite3" in state) → PatchReconciler valid=False
    BB5: MergeTelemetry records stats: 10 merges → correct rates
    BB6: Full pipeline: detect → merge → reconcile → record (end-to-end)
    BB7: Empty deltas → success with empty patch

    WB1: ConflictDetector.detect called BEFORE any Opus invocation
    WB2: fast_merge path: opus_client never called (verify mock)
    WB3: MergePromptBuilder same input → same output (deterministic)
    WB4: PatchReconciler all 3 steps run (schema + apply + axiom)
    WB5: MergeRecord fields populated correctly after merge
    WB6: Opus fallback: invalid JSON → partial merge of non-conflicting
    WB7: ConflictReport.non_conflicting_deltas used in fallback path
    )annotationsN)asdict)datetime)Path)Any)	AsyncMock	MagicMockpatchz/mnt/e/genesis-system)ConflictDetectorConflictReport)SemanticMergeInterceptorMergeResult)MergePromptBuilder)PatchReconcilerReconcileResult)MergeTelemetryMergeRecord)
StateDeltac                P    t        | ||t        |      t        dddddd            S )z?Return a StateDelta with the given patch ops as a frozen tuple.i        
   r   )agent_id
session_idversion_at_readr
   submitted_at)r   tupler   )r   opsr   versions       8/mnt/e/genesis-system/tests/merge/test_semantic_merge.py_make_deltar!   E   s3     CjdAr2q!4     dictc                    | |dS )zEReturn a plain dict delta (tests that both StateDelta and dict work).r   r
    )r   r   s     r    _make_dict_deltar'   U   s     3//r"   c                    t        j                  | |d      }t               }||_        t               }||j                  _        t        |d      r|`|S )z
    Synchronous mock Opus client.
    generate_content() returns a MagicMock with .text = valid JSON.
    No generate_content_async attribute (forces sync path in interceptor).
    )resolved_patchresolution_rationalegenerate_content_async)jsondumpsr	   textgenerate_contentreturn_valuehasattrr+   )r)   	rationaleresponse_bodymock_responseclients        r    _make_sync_opus_clientr6   Z   sY     JJ( )  M KM&M[F+8F(v/0)Mr"   c                z    t               }| |_        t               }||j                  _        t	        |d      r|`|S )zFMock Opus client that returns malformed JSON (triggers fallback path).r+   )r	   r.   r/   r0   r1   r+   )bad_textr4   r5   s      r    _make_bad_opus_clientr9   o   s<    KM!M[F+8F(v/0)Mr"   c                    t        j                         }	 |j                  |       |j                          S # |j                          w xY w)zDRun an async coroutine synchronously (no pytest-asyncio dependency).)asyncionew_event_looprun_until_completeclose)coroloops     r    _runrA   z   s6    !!#D&&t,



s	   7 A	c                (    |xs d}t        | |      S )z:Factory: SemanticMergeInterceptor with a temp events file.z/tmp/test_module7_events.jsonl)opus_clientevents_path)r   )rC   tmp_patheventss      r    _make_interceptorrG      s    99F#PPr"   active   modegenesis)statusr   config
BASE_STATEc                    t        dddddg      } t        dddddg      }t               }t        |d	      r|`t	        |
      }t        |j                  | |gt        d            }|j                  }d}||u }|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}||u }|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 
ch c]  }
|
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}}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}}|j(                  j+                          yc c}
w )"u   
    BB1: Two deltas touching different paths → no conflict, Opus NOT called.

    Verifies:
    - result.success is True
    - result.used_opus is False
    - Both ops appear in merged_patch
    - Opus client generate_content is never called
    agent-Aaddz/alpha   oppathvalueagent-Bz/betar   r+   rC   rI   r   Tisz/%(py2)s
{%(py2)s = %(py0)s.success
} is %(py5)sresultpy0py2py5z"Non-conflicting merge must succeed
>assert %(py7)spy7NFz1%(py2)s
{%(py2)s = %(py0)s.used_opus
} is %(py5)sz%Opus must NOT be invoked on fast pathrU   inz%(py1)s in %(py3)spaths_in_resultpy1py3z alpha op must be in merged patch
>assert %(py5)sra   zbeta op must be in merged patch)r!   r	   r1   r+   rG   rA   mergerN   success
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanation	used_opusmerged_patchr/   assert_not_called)delta_adelta_brC   interceptorr]   @py_assert1@py_assert4@py_assert3@py_format6@py_format8rT   rh   @py_assert0@py_assert2@py_format4s                  r    (test_bb1_non_conflicting_merge_fast_pathr      si    )UHq&Q%RSG)UGa&P%QRG+K{45.#<K+##Wg$6
A#NOF>>GTG>T!GGG>TGGGGGG6GGG6GGG>GGGTGGG#GGGGGGGGMuMu$MMMuMMMMMM6MMM6MMMMMMuMMM&MMMMMMMM,2,?,?@br&z@O@J8&JJJ8JJJ8JJJJJJJJJJJJJ(JJJJJJJH7o%HHH7oHHH7HHHHHHoHHHoHHHH'HHHHHHH  224 As   2Oc                    t        dddddg      } t        dddddg      }ddddg}t        |d	      }t        |
      }t        |j	                  | |gt
        d            }|j                  }d}||u }|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}||u }|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"                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                   d      dz   d|iz  }t        t        j                  |            dx}}|j$                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}|j&                  j)                          y) u,  
    BB2: Two deltas conflict on the same path → Opus is invoked.

    Verifies:
    - result.success is True
    - result.used_opus is True
    - result.merged_patch matches the Opus resolved_patch
    - result.resolution_rationale is populated
    - Opus generate_content called exactly once
    rP   replace/statusrH   rS   rW   inactivezA wins by priorityr)   r2   rX   rI   rY   TrZ   r\   r]   r^   assert %(py7)src   Nrd   z+Opus must be called when conflicts detectedrb   ==z4%(py2)s
{%(py2)s = %(py0)s.merged_patch
} == %(py4)sresolvedr_   r`   py4z"Resolved patch must come from Opus
>assert %(py6)spy6)z<%(py2)s
{%(py2)s = %(py0)s.resolution_rationale
} == %(py5)s)r!   r6   rG   rA   rm   rN   rn   ro   rp   rq   rr   rs   rt   rv   rw   rx   ru   ry   r*   r/   assert_called_once)r{   r|   r   rC   r}   r]   r~   r   r   r   r   @py_format5@py_format7s                r    &test_bb2_conflicting_merge_opus_calledr      sy    )Y	T\&]%^_G)Y	T^&_%`aG )hGHH(L`aK#<K+##Wg$6
A#NOF>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!RtRt#RRRtRRRRRR6RRR6RRRRRRtRRR%RRRRRRRRP(*PPP(PPPPPP6PPP6PPPPPPPPP(PPP(PPPP,PPPPPPP&&>*>>&*>>>>>&*>>>>>>>6>>>6>>>&>>>*>>>>>>>>  335r"   c                 R   t               } ddi}ddddg}| j                  ||      }|j                  }d}||u }|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}||u }|st        j                  d|fd||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}d |j                  D        }t        |      }|st        j                  d|j                         dz   dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }	t        t        j                  |	            dx}}y)u   
    BB3: Patch that produces state containing "API_KEY" → PatchReconciler.valid=False.

    The PatchReconciler is the safeguard that prevents forbidden patterns from
    entering the master state, even if Opus produces such a patch.
    rJ   rK   rQ   z/credentialszMY_API_KEY=secretrS   FrZ   z-%(py2)s
{%(py2)s = %(py0)s.valid
} is %(py5)sr]   r^   z%API_KEY in new state must be rejectedrb   rc   Nz1%(py2)s
{%(py2)s = %(py0)s.new_state
} is %(py5)sr   c              3  $   K   | ]  }d |v  
 yw)API_KEYNr&   .0errs     r    	<genexpr>zLtest_bb3_axiom_violation_api_key_patch_reconciler_rejects.<locals>.<genexpr>        9CyC9   z%Expected 'API_KEY' axiom error, got: .
>assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyr   r   validate_and_applyvalidro   rp   rq   rr   rs   rt   ru   rv   rw   	new_stateerrorsr   

reconcilerstater
   r]   r~   r   r   r   r   r   s
             r    9test_bb3_axiom_violation_api_key_patch_reconciler_rejectsr      s    !"JYE><OPQE**5%8F<<I5I<5 III<5IIIIII6III6III<III5III"IIIIIIII#t#t####t######6###6######t#######96==9 399 9   0?             :    :     r"   c                 R   t               } ddi}ddddg}| j                  ||      }|j                  }d}||u }|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}||u }|st        j                  d|fd||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}d |j                  D        }t        |      }|st        j                  d|j                         dz   dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }	t        t        j                  |	            dx}}y)u   
    BB4: Patch that produces state containing "sqlite3" → PatchReconciler.valid=False.

    The SQLite ban (Rule 7 of GLOBAL_GENESIS_RULES.md) is enforced at the
    merge layer — no sqlite3 reference can enter the master state.
    dbpostgresr   /dbzsqlite3://local.dbrS   FrZ   r   r]   r^   z%sqlite3 in new state must be rejectedrb   rc   Nr   r   c              3  $   K   | ]  }d |v  
 ywsqlite3Nr&   r   s     r    r   zLtest_bb4_axiom_violation_sqlite3_patch_reconciler_rejects.<locals>.<genexpr>   r   r   z%Expected 'sqlite3' axiom error, got: r   r   r   r   r   s
             r    9test_bb4_axiom_violation_sqlite3_patch_reconciler_rejectsr      s    !"J:Eu7KLME**5%8F<<I5I<5 III<5IIIIII6III6III<III5III"IIIIIIII#t#t####t######6###6######t#######96==9 399 9   0?             :    :     r"   c                 
   i i fd} fd}fd}fd}t               }| |j                  _        ||j                  _        ||j                  _        ||j
                  _        t        j                  dd      5 }|j                  }ddd       	 t        |	      }t        d
      D ]B  }|dk  }	|dk  }
t        d|dd|	rdnd|
t        d
|z         d      }|j                  |       D |j                         }|d   }d
}||k(  }|st        j                   d|fd||f      t        j"                  |      t        j"                  |      dz  }t        j$                  d|d          dz   d|iz  }t'        t        j(                  |            dx}x}}|d   }d}||z
  }t+        |      }d}||k  }|st        j                   d|fd||f      d t-        j.                         v st        j0                  t*              rt        j"                  t*              nd t        j"                  |      t        j"                  |      t        j"                  |      t        j"                  |      d!z  }t        j$                  d"|d          d#z   d$|iz  }t'        t        j(                  |            dx}x}x}x}x}}|d%   }d&}||z
  }t+        |      }d}||k  }|st        j                   d|fd||f      d t-        j.                         v st        j0                  t*              rt        j"                  t*              nd t        j"                  |      t        j"                  |      t        j"                  |      t        j"                  |      d!z  }t        j$                  d'|d%          d#z   d$|iz  }t'        t        j(                  |            dx}x}x}x}x}}|d(   }d)}||z
  }t+        |      }d}||k  }|st        j                   d|fd||f      d t-        j.                         v st        j0                  t*              rt        j"                  t*              nd t        j"                  |      t        j"                  |      t        j"                  |      t        j"                  |      d!z  }t        j$                  d*|d(          d#z   d$|iz  }t'        t        j(                  |            dx}x}x}x}x}}t3        j4                  |       y# 1 sw Y   xY w# t3        j4                         w xY w)+z
    BB5: Record 10 merges through MergeTelemetry; verify stats reflect correct rates.

    Uses a mock Redis client so INCR/GET/LRANGE are tracked in-memory via
    a simple dict-backed mock (no real Redis connection).
    c                6    j                  | d      dz   | <   y )Nr   rR   get)keyredis_stores    r    	mock_incrzAtest_bb5_merge_telemetry_records_correct_stats.<locals>.mock_incr   s    &??32Q6Cr"   c                Z    j                  | d      }t        |      j                         S )Nr   )r   strencode)r   valr   s     r    mock_getz@test_bb5_merge_telemetry_records_correct_stats.<locals>.mock_get   s$    ooc1%3x  r"   c                V    j                  | g       j                  d |D               y )Nc              3  2   K   | ]  }t        |        y w)N)r   )r   vs     r    r   zUtest_bb5_merge_telemetry_records_correct_stats.<locals>.mock_rpush.<locals>.<genexpr>  s     .F!s1v.Fs   )
setdefaultextend)r   valuesredis_listss     r    
mock_rpushzBtest_bb5_merge_telemetry_records_correct_stats.<locals>.mock_rpush  s$    sB'...Fv.FFr"   c                L    j                  | g       }|dk(  r||d  S |||dz    S )NrR   r   )r   startendlstr   s       r    mock_lrangezCtest_bb5_merge_telemetry_records_correct_stats.<locals>.mock_lrange  s7    ooc2&"9uv;5q!!r"   .jsonlFsuffixdeleteNredis_clientrD   r         zsess-03dr   rR   r   Tr   delta_countconflict_countrx   merge_latency_msrn   total_mergesr   z%(py1)s == %(py4)srj   r   zExpected 10 merges, got r   r   conflict_rate_pctg      D@{Gz?<z<%(py7)s
{%(py7)s = %(py0)s((%(py2)s - %(py4)s))
} < %(py10)sabsr_   r`   r   rc   py10z Expected 40% conflict rate, got z
>assert %(py12)spy12opus_rate_pctg      >@zExpected 30% opus rate, got avg_latency_msg      -@z!Expected 14.5ms avg latency, got )r	   incrside_effectr   rpushlrangetempfileNamedTemporaryFilenamer   ranger   floatrecord	get_statsro   rp   rt   ru   rv   rw   r   rq   rr   rs   osunlink)r   r   r   r   
mock_redistmprE   	telemetryihas_conflictrx   r   statsr   r   r   r   r   r~   @py_assert5@py_assert6@py_assert9@py_assert8@py_format11@py_format13r   r   s                            @@r    .test_bb5_merge_telemetry_records_correct_statsr     s    #%K#%K7!G" J"+JOO!)JNN#-J $/J!		$	$HU	C s88!"
Q	 r 	%Aq5LAI "1S'?$0qa#!&rAvF V$	% ##%^$^^$*^^^$^^^$^^^^^^.Fu^G\F],^^^^^^^^,- 	
 	
-4 	
s45 	
 	
5< 	
 	
5 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 . 	
 	
 		 15 	
 	
 		 6 	
 	
 		 9= 	
 	
  /u5H/I.JK	
 	
 	
 	
 	
 	
 ) 	
D 	
)D0 	
s01 	
D 	
1D8 	
 	
1D 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 * 	
 	
 		 -1 	
 	
 		 2 	
 	
 		 59 	
 	
  +5+A*BC	
 	
 	
 	
 	
 	
 )* 	
T 	
*T1 	
s12 	
T 	
2T9 	
 	
2T 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 + 	
 	
 		 .2 	
 	
 		 3 	
 	
 		 6: 	
 	
  06F0G/HI	
 	
 	
 	
 	
 	
 			(I H 			(s    T$Q8T1 $T.1Uc                    t               } t        d      }t               }t        j                  dd      5 }|j
                  }ddd       	 t        d      }ddd	}t        d
ddddg      }t        dddddg      }| j                  ||g      }	|	j                  }
d}|
|u }|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}}t'        |j)                  ||g|d            }|j*                  }
d}|
|u }|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}|
|u }|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/                  ||j0                        }|j2                  }
d}|
|u }|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}}|j4                  }
d}|
|u}|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}}|j4                  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}}|j4                  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}}t7        d*d+dd|j8                  d,      }|j;                  |       |j=                         }|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}}t?        |d.      5 }|D cg c]#  }|jA                         s|jA                         % }}ddd       tC              }d}||k(  }|st        j                  d$|fd/||f      d0t        j                         v st        j                  tB              rt        j                  tB              nd0d1t        j                         v st        j                  |      rt        j                  |      nd1t        j                  |      t        j                  |      d2z  }d3d4|iz  }t#        t        j$                  |            dx}x}}tE        jF                  |d         }|d5   }d*}||k(  }|slt        j                  d$|fd%||f      t        j                  |      t        j                  |      d&z  }d'd(|iz  }t#        t        j$                  |            dx}x}}|d6   }d}||u }|slt        j                  d|fd7||f      t        j                  |      t        j                  |      d&z  }d'd(|iz  }t#        t        j$                  |            dx}x}}tI        jJ                  |       y# 1 sw Y   xY wc c}w # 1 sw Y   YxY w# tI        jJ                         w xY w)8u  
    BB6: End-to-end pipeline integration test.

    Flow: detect(deltas) → fast_merge() → reconcile(patch) → record(MergeRecord)

    Uses non-conflicting deltas so no Opus is needed. Verifies each component
    contributes correctly to the final outcome.
    NrX   r   Fr   r   readyr   )rL   countrP   r   r   runningrS   rW   z/countrR   rZ   z5%(py2)s
{%(py2)s = %(py0)s.has_conflicts
} is %(py5)sreportr^   z#Different paths should not conflictrb   rc   rY   Tr\   merge_resultr   rd   r   reconcile_resultis notz5%(py2)s
{%(py2)s = %(py0)s.new_state
} is not %(py5)srL   r   r   r   assert %(py6)sr   r  zsess-full-pipeliner   r   r   rz0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenlinesr_   rj   rk   r   assert %(py8)spy8r   rn   z%(py1)s is %(py4)s)&r   rG   r   r   r   r   r   r!   detecthas_conflictsro   rp   rq   rr   rs   rt   ru   rv   rw   rA   rm   rn   rx   r   ry   r   r   r   
latency_msr   r   openstripr  r,   loadsr   r   )detectorr}   r   r   telemetry_pathr   r   r{   r|   r  r~   r   r   r   r   r  r  r   r   r   r   r   r   fhlr  r   @py_format9saveds                                r    4test_bb6_full_pipeline_detect_merge_reconcile_recordr&  9  s'     !H#5K "J		$	$HU	C "s"/"".Q	"Q/iIXa*b)cdiHWX*Y)Z[ '7!34##SuS#u,SSS#uSSSSSSvSSSvSSS#SSSuSSS.SSSSSSSS K--w.@%QR-ST##+t+#t++++#t++++++|+++|+++#+++t+++++++%%..%....%......|...|...%.......... &88@Y@YZ%%--%----%------------%----------))55)5555)555555555555)5555555555))(3@y@3y@@@@3y@@@3@@@y@@@@@@@))'27a72a77772a7772777a7777777 +)44
 	  ##%^$))$))))$)))$)))))))))) .#& 	9"(*81aggiQWWY8E8	95zQzQzQss55zQ

58$\":&::"&:::::"&::::":::&::::::::Y'4'4''''4''''''4''''''' 			.!e" "V 9	9 	9 			.!sI   dYd8 %d+*d& d&d+H/d8 d#&d++d50d8 8ec                 L   t               } t        | j                  g t        d            }|j                  }d}||u }|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}||u }|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  }t        j                  d|j                         dz   d	|iz  }t        t        j                  |            d
x}x}}y
)u   
    BB7: Passing an empty delta list → success=True, empty merged_patch, used_opus=False.

    This is a valid edge case — no work needed means no conflicts.
    rR   rY   TrZ   r\   r]   r^   r   rc   NFrd   r   )z4%(py2)s
{%(py2)s = %(py0)s.merged_patch
} == %(py5)szExpected empty patch, got: rb   )rG   rA   rm   rN   rn   ro   rp   rq   rr   rs   rt   rv   rw   rx   ry   ru   )r}   r]   r~   r   r   r   r   s          r    1test_bb7_empty_deltas_returns_success_empty_patchr(  |  s    $%K+##B
A#>?F>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!$u$u$$$$u$$$$$$6$$$6$$$$$$u$$$$$$$Y"Y"$YYY"YYYYYY6YYY6YYYYYY"YYY(CFDWDWCX&YYYYYYYYr"   c                 z   t        dddddg      } t        dddddg      }ddddg}t        |      }t        |	      }g |j                  j                  fd
}||j                  _        |j
                  fd}||_        t        |j                  | |gt        d             t              }d}||k\  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                        rt        j                        ndt        j                  |      t        j                  |      dz  }
t        j                   d       dz   d|
iz  }t#        t        j$                  |            dx}x}	}d   }d}||k(  }|st        j                  d|fd||f      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}}j'                  d      }j'                  d       }||k  }|st        j                  d'|fd(||f      d)t        j                         v st        j                  |      rt        j                  |      nd)d*t        j                         v st        j                  |      rt        j                  |      nd*d+z  }t        j                   d,| d-| d.      d/z   d0|iz  }t#        t        j$                  |            d}y)1z
    WB1: ConflictDetector.detect() is the FIRST operation in the pipeline.

    Even when conflicts exist and Opus must be called, detect() runs before
    Opus is ever invoked. Verified via call-order tracking.
    rP   r   z/verv1rS   rW   v2)r)   rX   c                6    j                  d        |       S )Nr  append)deltas
call_orderoriginal_detects    r    tracked_detectzEtest_wb1_conflict_detector_called_before_opus.<locals>.tracked_detect  s    (#v&&r"   c                6    j                  d        |       S )Nopusr-  )promptr0  original_generates    r    tracked_generatezGtest_wb1_conflict_detector_called_before_opus.<locals>.tracked_generate  s    &! ((r"   rI   rY   r   )>=)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} >= %(py6)sr  r0  r  z Expected at least 2 calls, got: z
>assert %(py8)sr  Nr   r  r   r   r   z*detect() must be called FIRST, got order: r   r   r4  re   rg   ri   z(Opus must be called when conflicts existrl   ra   r   )z%(py0)s < %(py2)s
detect_idxopus_idxr_   r`   zdetect() (idx=z) must precede Opus (idx=)
>assert %(py4)sr   )r!   r6   rG   r   r  r/   rA   rm   rN   r  ro   rp   rq   rr   rs   rt   ru   rv   rw   index)r{   r|   r   rC   r}   r2  r7  r   r   r   r   r$  r   r   r   r   r   r9  r:  r~   @py_format3r0  r1  r6  s                        @@@r    -test_wb1_conflict_detector_called_before_opusr@    s0    )YQU&V%WXG)YQU&V%WXG &4@AH(AK#<KJ "**11O' #1K $44) $4K 		GW-z1		EFz?PaP?aPPP?aPPPPPP3PPP3PPPPPPzPPPzPPP?PPPaPPP#CJ<!PPPPPPPPa= H =H$  =H        %    5ZLA     K6ZKKK6ZKKK6KKKKKKZKKKZKKKK!KKKKKKK!!(+J'H   :                !    !    $=hZqI    r"   c                    t               } t        | d      r| `t        |       }t	        dddddg      }t	        ddd	d
dg      }t	        dddddg      }t        |j                  |||gt                    }|j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                   |
            dx}x}}| j"                  j%                          | j"                  }|j&                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      t        j                  |      dz  }
t        j(                  d| j"                  j&                   d      dz   d|
iz  }t        t        j                   |            dx}x}x}}y)z
    WB2: When no conflicts exist, the fast_merge path has exactly zero Opus API calls.

    The Opus client mock tracks all calls. After a non-conflicting merge,
    generate_content must have been called 0 times.
    r+   rX   ArQ   /xr   rS   Bz/y   Cz/z   FrZ   rd   r]   r^   r   rc   Nr   r   )zX%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.generate_content
}.call_count
} == %(py7)srC   )r_   r`   r   rc   zOpus called z times on fast pathz
>assert %(py9)spy9)r	   r1   r+   rG   r!   rA   rm   rN   rx   ro   rp   rq   rr   rs   rt   rv   rw   r/   rz   
call_countru   )rC   r}   r{   r|   delta_cr]   r~   r   r   r   r   r   r   @py_format10s                 r    (test_wb2_fast_merge_path_zero_opus_callsrL    s    +K{45.#<K #udR HIJG#udR HIJG#udR HIJG+##Wgw$?LMF$u$u$$$$u$$$$$$6$$$6$$$$$$u$$$$$$$  224'' '22 a 2a7  2a              (    3    78    {33>>??RS     r"   c                    t               } t               }t        dddddg      }t        dddddg      }|j                  ||g      }|j                  }d}||u }|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}ddd}
d}| j                  ||g||
|      }| j                  ||g||
|      }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d      dz   d|iz  }t        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}}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)$u   
    WB3: MergePromptBuilder.build() produces identical output for identical inputs.

    The builder must be deterministic — no timestamps, random IDs, or ordering
    variance — so repeated calls produce reproducible prompts for testing.
    rP   r   z/modefastrS   rW   slowTrZ   r
  r  r^   r   rc   Nmedium*   )rJ   r     r   )z%(py0)s == %(py2)sprompt_1prompt_2r;  zIMergePromptBuilder must produce deterministic output for identical inputsr=  r   zGenesis Semantic Reducerre   rg   ri   assert %(py5)sra   zversion r)   )r   r   r!   r  r  ro   rp   rq   rr   rs   rt   rv   rw   buildru   )builderr   r{   r|   r  r~   r   r   r   r   r   r   rS  rT  r?  r   r   r   r   s                      r    .test_wb3_merge_prompt_builder_is_deterministicrX    s    !"G!H)YRX&Y%Z[G)YRX&Y%Z[G __gw/0F'4'4''''4''''''6'''6''''''4'''''''+EG }}gw/HH}}gw/HHx  8x                          	T    
 &1%1111%111%1111111111111111gY+8++++8+++++++++8+++8+++++++ 9    9   9                 9    9   9                7h7h7hh'x''''x'''''''''x'''x'''''''r"   c                 B	   t               } ddd}ddddg}| j                  ||      }| j                  |      }g }||k(  }|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }t        j                  d|       dz   d|iz  }t        t        j                  |            dx}}ddd}	| j                  |	|      \  }
}d}|
|u}|st        j                  d|fd|
|f      dt        j                         v st        j                  |
      rt        j                  |
      ndt        j                  |      dz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}}g }||k(  }|st        j                  d|fd	||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|j                  }d}||u }|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}}d |j                  D        }t        |      }|sdd t        j                         v st        j                  t              rt        j                  t              nd t        j                  |      t        j                  |      d!z  }t        t        j                  |            dx}}|d"   }d}||k(  }|st        j                  d|fd#||f      t        j                  |      t        j                  |      d$z  }t        j                  d%      d&z   d'|iz  }t        t        j                  |            dx}x}}y)(u'  
    WB4: PatchReconciler runs all 3 validation steps — schema, apply, axiom.

    Tested by supplying a schema-valid patch that produces a state with an
    axiom violation. All three steps must have run: schema (pass), apply
    (pass and produce new_state), axiom (fail and add error).
    r   r   )r   r   r   r   sqlite3_file_dbrS   r   )z%(py0)s == %(py3)sschema_errors)r_   rk   z Expected no schema errors, got: rl   ra   Nr  )z%(py0)s is not %(py3)snew_state_from_applyz+Dry-run apply must succeed for valid schemaapply_errorsrU  FrZ   r   r]   r^   zAxiom step must reject sqlite3rb   rc   c              3  $   K   | ]  }d |v  
 ywr   r&   r   s     r    r   z@test_wb4_patch_reconciler_all_three_steps_run.<locals>.<genexpr>  r   r   z,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}r   r   r   r   r   z"Original state must not be mutatedr   r   )r   r   _check_schemaro   rp   rq   rr   rs   rt   ru   rv   rw   _dry_run_applyr   r   r   )r   r   r
   r]   r[  r   r~   r   r   working_state_copyr\  r]  r   r   r   r   r   r   s                     r    -test_wb4_patch_reconciler_all_three_steps_runrb    s    !"J
 !,Eu7HIJE**5%8F ,,U3MR=BRRR=BRRRRRR=RRR=RRRBRRR"B=/ RRRRRRR !+q9)3)B)BCUW\)]&,'+Zt+ZZZtZZZZZZZZZZZZtZZZ-ZZZZZZZ<2<2<<2 <<B5B<5 BBB<5BBBBBB6BBB6BBB<BBB5BBB"BBBBBBBB96==9939999999993999399999999999999 ;J*J;*$JJJ;*JJJ;JJJ*JJJ&JJJJJJJJr"   c            	        t        j                  dd      5 } | j                  }ddd       	 t        d      }t	        dddd	d
d	      }|j                  |       t        |d      5 }|D cg c]#  }|j                         s|j                         % }}ddd       t              }d}||k(  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                   |            dx}x}	}t#        j$                  |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   }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   }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   }d	}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }
t        t        j                   |
            dx}x}}|d   }d
}||z
  }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                  |      t        j                  |      d$z  }d%d&|iz  }t        t        j                   |            dx}x}x}x}x}}|d'   }d	}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }
t        t        j                   |
            dx}x}}t)        |      }|j+                         D ]  \  }}||   }||k(  }|st        j                  d|fd(||f      t        j                  |      d)t        j                         v st        j                  |      rt        j                  |      nd)d*z  }t        j,                  d+| d,||    d-|       d.z   d/|iz  }t        t        j                   |            dx}} 	 t/        j0                  |       y# 1 sw Y   1xY wc c}w # 1 sw Y   xY w# t/        j0                         w xY w)0z
    WB5: MergeRecord fields are populated correctly after recording a merge.

    Verifies that MergeRecord is a proper dataclass with all required fields
    and that the fields survive serialisation via dataclasses.asdict().
    r   Fr   Nr   zverify-sess-001r   rR   Tg     @E@r   r  r   r  r  r  r  r  r  r   r   r   r   r  r   r   r   rx   rZ   r  r   gMbP?r   r   r   r   assert %(py12)sr   rn   )z%(py1)s == %(py3)srV   ri   zField 'z' mismatch: z != rl   ra   )r   r   r   r   r   r   r  r  r  ro   rp   rq   rr   rs   rt   rv   rw   r,   r  r   r   itemsru   r   r   )r   rD   r   r   r"  r#  r  r   r   r   r   r$  r%  r   r   r   r~   r   r  r  r  r  record_dictr   rV   r   r   s                              r    0test_wb5_merge_record_fields_populated_correctlyrg     sf    
	$	$HU	C shh!"+N	(!
 	  +s# 	9r(*81aggiQWWY8E8	9 5zQzQzQss55zQ

58$\"7&77"&77777"&7777"777&77777777]#(q(#q((((#q(((#(((q(((((((%&+!+&!++++&!+++&+++!+++++++[!)T)!T))))!T)))!)))T)))))))+,<t<,t3<s34<u<4u<<<<4u<<<<<<s<<<s<<<,<<<t<<<4<<<u<<<<<<<<Y'4'4''''4''''''4''''''' Vn%++- 	[JC:Z:&ZZZ:ZZZ:ZZZZZZZZZZZZZ'#l5:,dSXRY(ZZZZZZZ	[ 			+I $ 9	9 	9& 			+sG   Y;Y3 )Y&.Y!Y!Y&V%Y3 Y!Y&&Y0+Y3 3Z
c                    t        dddddg      } t        dddddg      }t        dd	d
ddg      }t        d      }t        |      }t        |j	                  | ||gt
        d            }|j                  }d}||u }|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}||u }|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 ch c]  }|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}}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c c}w )'z
    WB6: When Opus returns invalid JSON, the interceptor falls back to
    fast_merge of non-conflicting deltas (partial merge).

    The conflicting deltas are excluded; only safe deltas survive.
    rB  r   rC  A_valrS   rD  B_valrF  rQ   z/clean_fieldc   zTHIS IS NOT JSON AT ALL }{rX   rI   rY   TrZ   r\   r]   r^   zFallback must still succeedrb   rc   NFrd   z)Opus credit must NOT be given on fallbackrU   re   rg   rh   ri   z9Non-conflicting delta must survive partial merge fallbackrl   ra   not inz%(py1)s not in %(py3)sz:Conflicting path must not appear in fallback partial merge)r!   r9   rG   rA   rm   rN   rn   ro   rp   rq   rr   rs   rt   ru   rv   rw   rx   ry   )delta_conflict_adelta_conflict_bdelta_cleanbad_opusr}   r]   r~   r   r   r   r   rT   rh   r   r   r   s                   r    :test_wb6_opus_invalid_json_triggers_partial_merge_fallbackrs  N  s    #3	4RY)Z([\"3	4RY)Z([\c5.SU$V#WXK %%ABH#9K+##	+[9 $  F >>@T@>T!@@@>T@@@@@@6@@@6@@@>@@@T@@@#@@@@@@@@QuQu$QQQuQQQQQQ6QQQ6QQQQQQuQQQ&QQQQQQQQ -3,?,?@br&z@O@ >_,  >_          -    -    	D    
  4&  4          '    '    	E     As   7N<c                 X   t               } t        dddddg      }t        dddddg      }t        dd	d
ddg      }|||g}| j                  |      }|j                  }d}||u }|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                  }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                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}x}}|j                  d   }||u }|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               }t!        |"      }t#        |j%                  |t&        d#$            }|j(                  }d}||u }|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 ch c]  }|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}}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c c}w )/aL  
    WB7: On Opus failure, ConflictReport.non_conflicting_deltas is the source
    for the fallback partial merge.

    This test introspects the ConflictDetector output to confirm that
    non_conflicting_deltas contains exactly the safe delta(s) that should
    survive, and then confirms the interceptor uses them correctly.
    W1r   z/sharedr*  rS   W2r+  W3rQ   z/independentsafeTrZ   r
  r  r^   r   rc   NrR   r   )z\%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.non_conflicting_deltas
})
} == %(py8)sr  )r_   rj   rk   ra   r  zassert %(py10)sr   r   )z%(py1)s is %(py3)s
delta_saferi   z5Only the safe delta must be in non_conflicting_deltasrl   ra   rX   rI   rY   r\   r]   rU   re   rg   pathsz,Safe delta ops must appear in fallback mergerl  rn  z1Conflicting ops must NOT appear in fallback merge)r   r!   r  r  ro   rp   rq   rr   rs   rt   rv   rw   non_conflicting_deltasr  ru   r9   rG   rA   rm   rN   rn   ry   )r   delta_conflict_1delta_conflict_2ry  
all_deltasr  r~   r   r   r   r   r   @py_assert7r   r$  r  r   r   rr  r}   r]   rT   rz  s                          r    @test_wb7_conflict_report_non_conflicting_deltas_used_in_fallbackr  t  s     !H"4IX\*])^_"4IX\*])^_T5.SY$Z#[\J"$4jAJ__Z(F '4'4''''4''''''6'''6''''''4''''''',,23,-22-2222-22222232223222222v222v222,222-2222222222((+ +z9  +z    ,      0:    0:    	@    
 %&H#9K+##J
A#FGF >>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!"("5"56BRZ6E6R>U"RRR>URRR>RRRRRRURRRURRRR$RRRRRRRV9E!VVV9EVVV9VVVVVVEVVVEVVVV#VVVVVVV 7s   "V'c                    t               } t        | d      r| `t        |       }t	        dddddg      }t        |j                  |gt        d	            }|j                  }d
}||u }|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}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                   |            dx}x}}| j$                  j'                          |j(                  D 	ch c]  }	|	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}}yc c}	w )z
    Integration: A single delta submitted alone cannot conflict with itself.
    Fast path is taken, Opus is never called.
    r+   rX   solorQ   z/soloonlyrS   rR   rY   TrZ   r\   r]   r^   r   rc   NFrd   rU   re   rg   rz  ri   rU  ra   )r	   r1   r+   rG   r!   rA   rm   rN   rn   ro   rp   rq   rr   rs   rt   rv   rw   rx   r/   rz   ry   )rC   r}   deltar]   r~   r   r   r   r   rT   rz  r   r   r   s                 r    !test_single_delta_never_conflictsr    s   
 +K{45.#<Kw!P QRE+##UGZ#CDF>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!$u$u$$$$u$$$$$$6$$$6$$$$$$u$$$$$$$  224"("5"56BRZ6E67e7e7ee 7s   Kc                 t   dddddgd} dddd	dgd}t               }t        |j                  | |gt                    }|j                  }d
}||u }|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}||u }|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 	ch c]  }	|	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 )z
    Integration: Plain dict deltas (not StateDelta objects) are accepted by
    ConflictDetector and SemanticMergeInterceptor (duck typing support).
    zdict-ArQ   z	/dict_keyrR   rS   r%   zdict-Bz
/other_keyr   TrZ   r\   r]   r^   r   rc   NFrd   rU   re   rg   rz  ri   rU  ra   )rG   rA   rm   rN   rn   ro   rp   rq   rr   rs   rt   rv   rw   rx   ry   )dict_delta_adict_delta_br}   r]   r~   r   r   r   r   rT   rz  r   r   r   s                 r    /test_dict_deltas_accepted_alongside_state_deltar    s    !)5+`a4b3cdL (5,ab4c3deL#%K+##\<$@*MNF>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!$u$u$$$$u$$$$$$6$$$6$$$$$$u$$$$$$$"("5"56BRZ6E6;%;%;%% <5    <5   <      5   5        7s   L5c                    t        j                  dd      5 } | j                  }ddd       	 t        d      }t	        d      D ]1  }|j                  t        d| dd	d
t        d|z         d
             3 |j                         }|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   }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   }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   }
d}|
|z
  }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                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}
x}x}x}x}}t%        j&                  |       y# 1 sw Y   xY w# t%        j&                         w xY w)z
    Integration: MergeTelemetry without Redis uses in-memory latency list.
    Conflict and opus counts are not tracked (stay at 0), but total and latency work.
    r   Fr   Nr   rI   z	no-redis-r   rR   TrE  r   r   r   r   r   r  r   r   g        r   r   g      6@r   r   r   r   r   rd  r   )r   r   r   r   r   r   r   r   r   ro   rp   rt   rv   rw   r   rq   rr   rs   r   r   )r   rE   r   r   r   r   r   r   r   r   r~   r   r   r  r  r  r  s                    r    &test_merge_telemetry_no_redis_fallbackr    sZ   
 
	$	$HU	C s88"(K	q 	A[&qc? !&rAv 	 ##% ^$))$))))$)))$))))))))))()0S0)S0000)S000)000S0000000_%,,%,,,,%,,,%,,,,,,,,,,)*9T9*T19s129T92T99992T999999s999s999*999T9992999T99999999 			(7 6 			(s   L)K%L6 )L36Mc                 *   t               } t        dddddg      }t        ddddg      }| j                  ||g      }|j                  }d	}||u }|st	        j
                  d
|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}d}	|j                  }|	|v }
|
st	        j
                  d|
fd|	|f      t	        j                  |	      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}	x}
}d}	|j                  }|	|v }
|
st	        j
                  d|
fd|	|f      t	        j                  |	      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}	x}
}y)z^
    Integration: ConflictDetector catches op_contradiction (add vs remove on same path).
    rB  rQ   z/fieldnewrS   rD  remove)rT   rU   TrZ   r
  r  r^   r   rc   Nop_contradictionre   )z6%(py1)s in %(py5)s
{%(py5)s = %(py3)s.conflict_types
})rj   rk   ra   )z9%(py1)s in %(py5)s
{%(py5)s = %(py3)s.conflicting_paths
})r   r!   r  r  ro   rp   rq   rr   rs   rt   rv   rw   conflict_typesconflicting_paths)r   	delta_adddelta_remover  r~   r   r   r   r   r   r   s              r    2test_conflict_detector_identifies_op_contradictionr    s     !HC5"Q!RSIsHh%G$HIL__i67F'4'4''''4''''''6'''6''''''4'''''''6!6!66!66666!6666666666666666!66666666/v///8/////8////8//////v///v///////////r"   c                    t               } ddd}| j                  |g       }|j                  }d}||u }|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dd}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      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}}y)uY   
    Integration: Empty patch list is valid — new_state equals the original state.
    rR   r   )abTrZ   r   r]   r^   r   rc   Nr   )z1%(py2)s
{%(py2)s = %(py0)s.new_state
} == %(py5)s)z.%(py2)s
{%(py2)s = %(py0)s.errors
} == %(py5)s)r   r   r   ro   rp   rq   rr   rs   rt   rv   rw   r   r   )r   r   r]   r~   r   r   r   r   s           r    'test_patch_reconciler_valid_empty_patchr    s|    !"J!E**5"5F<<4<4<466<4/QQ//////////////6///6//////////////==B=B=B66=Br"   c                 J   t        dddddg      } t        dddddg      }ddddg}t        |d	      }t        |
      }ddd}t        |j	                  | |g|d            }|j
                  }d}||u }	|	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}||u }	|	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                  }||k(  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            dx}}	t!               }|j#                  ||j                        }|j$                  }d}||u }	|	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}||u}	|	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"   }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"   }d}	||	k(  }|slt        j                  d|fd#||	f      t        j                  |      t        j                  |	      d$z  }dd|iz  }t        t        j                  |            dx}x}}	y)%u   
    Integration: Conflicting merge → Opus resolves → PatchReconciler validates.

    This is the most complete end-to-end test covering the conflict path.
    rB  r   r   r	  rS   rD  stoppedzA is canonicalr   rX   idler   )rL   r   rY   TrZ   r\   r  r^   r   rc   Nrd   r   r   resolved_opsr   r  r   r   r  r  r  rL   r   r   )r!   r6   rG   rA   rm   rn   ro   rp   rq   rr   rs   rt   rv   rw   rx   ry   r   r   r   r   )r{   r|   r  rC   r}   r   r  r~   r   r   r   r   r   r   r   r  r   r   s                     r    *test_full_pipeline_with_opus_and_reconciler    s    #y)i XYZG#y)i XYZG %i)LML(P`aK#<K "-E))7G*<eR)PQL'4'4''''4''''''<'''<''''''4'''''''!!)T)!T))))!T))))))<)))<)))!)))T)))))))$$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 !"J!44UL<U<UV!!)T)!T))))!T))))))))))))!)))T)))))))%%1T1%T1111%T111111111111%111T1111111%%h/<9</9<<<</9<<</<<<9<<<<<<<?$f$?f$$$$?f$$$?$$$f$$$$$$$r"   c                     t               } t               }t        dddddg      }t        dddddg      }|j                  ||g      }| j	                  ||g|t
        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}}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)zW
    Integration: MergePromptBuilder includes the conflicting paths in the prompt.
    rB  r   z/config/moderN  rS   rD  rO  rR   rY   re   rg   r5  ri   z#Conflict path must appear in promptrl   ra   NzCONFLICT REPORTrU  zWORKER PROPOSALSzRespond ONLY with valid JSON)r   r   r!   r  rV  rN   ro   rp   rt   rq   rr   rs   ru   rv   rw   )
rW  r   r{   r|   r  r5  r   r   r   r   s
             r    1test_merge_prompt_builder_contains_conflict_pathsr  (  s    !"G!H#y.SY Z[\G#y.SY Z[\G__gw/0F]]GW-vz1]MFJ>V#JJJ>VJJJ>JJJJJJVJJJVJJJJ%JJJJJJJ&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''')3)V3333)V333)333333V333V3333333r"   )zsess-007rR   )
r   r   r   
list[dict]r   r   r   intreturnr   )r   r   r   r  r  r#   )ztest rationale)r)   listr2   r   r  r	   )zNOT_VALID_JSON {{{)r8   r   r  r	   )NN)rE   z
str | Noner  r   )J__doc__
__future__r   builtinsrq   _pytest.assertion.rewrite	assertionrewritero   r;   r,   r   sysr   dataclassesr   r   pathlibr   typingr   unittest.mockr   r	   r
   pytestGENESIS_ROOTrU   insertcore.merge.conflict_detectorr   r   %core.merge.semantic_merge_interceptorr   r   core.merge.merge_prompt_builderr   core.merge.patch_reconcilerr   r   core.merge.merge_telemetryr   r   core.coherence.state_deltar   r!   r'   r6   r9   rA   rG   rN   __annotations__r   r   r   r   r  r&  r(  r@  rL  rX  rb  rg  rs  r  r  r  r  r  r  r  r  r&   r"   r    <module>r     sV  : #     	 
      5 5  'sxxHHOOA|$ J W > H B 1 !		  	
  0
*Q '1@ST
D T5:66((EP@"FZ&)X8"(J!KH+\#L"WT*!& F0 
%D4r"   