
    i%                        d Z ddlmZ ddlZddlZddlZddlZddlmZ ddl	m
Z
 ddlmZ ddlmZ  ej                  e      Ze G d d	             Z G d
 d      Zy)u  
core/merge/semantic_merge_interceptor.py

SemanticMergeInterceptor — orchestrates conflict detection and Opus 4.6
resolution for concurrent StateDelta patches.

Flow
----
1. ConflictDetector.detect(deltas) → ConflictReport
2a. No conflicts → ConflictDetector.fast_merge(deltas) → MergeResult(used_opus=False)
2b. Conflicts detected → MergePromptBuilder.build(…) → Opus 4.6 → parsed JSON
       Opus response: {"resolved_patch": [...], "resolution_rationale": "..."}
       On parse failure → fast_merge(non_conflicting_deltas) (partial fallback)
3. Append merge event to data/observability/events.jsonl

Opus is ONLY called when ConflictDetector reports at least one conflict.
    )annotationsN)	dataclass)Optional)ConflictDetector)MergePromptBuilderc                  L    e Zd ZU dZded<   ded<   ded<   dZded	<   d
Zded<   y)MergeResultz3Outcome of a SemanticMergeInterceptor.merge() call.boolsuccesslistmerged_patch	used_opusNzOptional[str]resolution_rationaleg        float
latency_ms)__name__
__module____qualname____doc____annotations__r   r        >/mnt/e/genesis-system/core/merge/semantic_merge_interceptor.pyr	   r	   '   s*    =MO*.-.Jr   r	   c                  b    e Zd ZdZ	 	 d	 ddZ	 d		 	 	 	 	 	 	 d
dZddZ	 	 	 	 	 	 	 	 	 	 	 	 ddZy)SemanticMergeInterceptora  
    Orchestrates conflict detection + Opus conflict resolution for StateDelta
    patches submitted concurrently by swarm workers.

    Parameters
    ----------
    opus_client:
        Optional client used to call Opus 4.6.  Must expose one of:
        - ``generate_content_async(prompt) -> response`` (preferred async)
        - ``generate_content(prompt) -> response`` (sync fallback)
        Response objects must have a ``.text`` attribute *or* be directly
        str-coercible.  Inject ``None`` to run in test-only mode where Opus is
        never reachable (conflicts will fall back to partial merge).
    events_path:
        Path to the JSONL file where merge events are appended.
        Defaults to ``"data/observability/events.jsonl"``.
    Nc                \    t               | _        t               | _        || _        || _        y )N)r   detectorr   prompt_builderopus_clientevents_path)selfr   r    s      r   __init__z!SemanticMergeInterceptor.__init__J   s)    
 )*02&&r   c           	       K   t        j                         }| j                  j                  |      }|j                  sc| j                  j                  |      }t        j                         |z
  dz  }| j                  t        |      ddd|       t        d|d|      S t        |j                        }	 | j                  j                  ||||      }	| j                  |	       d{   }
t        j                  |
      }|d   }t        |t               s!t#        d	t%        |      j&                         |j)                  d
d      }t        j                         |z
  dz  }| j                  t        |      |dd|       t        d|d||      S 7 # t*        $ r}t,        j/                  dt%        |      j&                  |t        |j0                               | j                  j                  |j0                        }t        j                         |z
  dz  }| j                  t        |      |dd|       t        d|d|      cY d}~S d}~ww xY ww)a@  
        Merge *deltas* into a single resolved patch.

        Parameters
        ----------
        deltas:
            List of StateDelta objects (or dicts with a ``patch`` key).
        current_state:
            The master state dict at the time of the merge request.
        version:
            Current state version number (forwarded to MergePromptBuilder).

        Returns
        -------
        MergeResult
            ``success`` is always True (partial merge is used on Opus failure).
            ``used_opus`` reflects whether Opus was actually invoked.
        i  r   TF)delta_countconflict_countresolvedr   r   )r   r   r   r   Nresolved_patchz#resolved_patch must be a list, got r    )r   r   r   r   r   u[   Opus merge failed (%s: %s) — falling back to partial merge of %d non-conflicting delta(s))time	monotonicr   detecthas_conflicts
fast_merge_record_eventlenr	   conflicting_pathsr   build
_call_opusjsonloads
isinstancer   
ValueErrortyper   get	Exceptionloggerwarningnon_conflicting_deltas)r!   deltascurrent_stateversionstartreportmergedlatencyr%   promptopus_response_textparsedr'   	rationaleexcs                  r   mergezSemanticMergeInterceptor.mergeX   sT    0   %%f-##]]--f5F~~'%/47GK "   #"	  V5565	((..wF (,v'>!>ZZ 23F#$45Nnd3 9$~:N:W:W9XY  (.zz2H"'MI~~'%/47GK-"   +%." % "?4  	NN.S	""F112 ]]--f.K.KLF~~'%/47GK-"   #"	 %	sJ   B4I72F )F*B)F IF 	IB*I	I
IIIc                ,  K   | j                   t        d      t        | j                   d      r$| j                   j                  |       d{   }n| j                   j	                  |      }t        |d      r|j
                  S t        |      S 7 Cw)a  
        Dispatch *prompt* to the injected Opus client.

        Supports both async (``generate_content_async``) and sync
        (``generate_content``) interfaces to stay compatible with different
        SDK versions and test mocks.

        Raises
        ------
        RuntimeError
            If no ``opus_client`` was provided at construction time.
        Exception
            Any exception propagated from the underlying client call.
        NuN   SemanticMergeInterceptor: no opus_client provided — cannot resolve conflictsgenerate_content_asynctext)r   RuntimeErrorhasattrrK   generate_contentrL   str)r!   rD   responses      r   r2   z#SemanticMergeInterceptor._call_opus   s      #`  4##%=>!--DDVLLH ''88@H8V$== 8} Ms   ABBABc           	     ,   d||||t        |d      d}	 | j                  }t        j                  j	                  |      s t        j                  j                  d|      }t        j                  t        j                  j                  |      d       t        |dd	      5 }|j                  t        j                  |      d
z          ddd       y# 1 sw Y   yxY w# t        $ r+}	t        j                  d| j                  |	       Y d}	~	yd}	~	ww xY w)z
        Append a single merge-event record to ``self.events_path`` as JSONL.

        The write is best-effort: any I/O error is logged as a warning but
        never propagated (event logging must never break the merge pipeline).
        semantic_merge   )eventr$   r%   r&   r   r   z/mnt/e/genesis-systemT)exist_okazutf-8)encoding
Nz9SemanticMergeInterceptor: failed to write event to %s: %s)roundr    ospathisabsjoinmakedirsdirnameopenwriter3   dumpsr9   r:   r;   )
r!   r$   r%   r&   r   r   rU   r    fhrH   s
             r   r.   z&SemanticMergeInterceptor._record_event   s     &&, "
A.
	**K77==- ggll+[ KK4tDk39 3RE*T123 3 3 	NNK   	s6   BC "(C
C CC C 	D(!DD)Nzdata/observability/events.jsonl)r    rP   )   )r=   r   r>   dictr?   intreturnr	   )rD   rP   rh   rP   )r$   rg   r%   rg   r&   r
   r   r
   r   r   rh   None)r   r   r   r   r"   rI   r2   r.   r   r   r   r   r   7   s    ( <' '$ 	ff f 	f
 
fX<%% % 	%
 % % 
%r   r   )r   
__future__r   r3   loggingr[   r)   dataclassesr   typingr   core.merge.conflict_detectorr   core.merge.merge_prompt_builderr   	getLoggerr   r:   r	   r   r   r   r   <module>rq      s^   $ #   	  !  9 >			8	$   P Pr   