
    .i$                        d Z ddlmZ ddlZddlmZmZ ddlmZ  ej                  e
      Ze G d d             Z G d d	      Zy)
u`  
core/merge/conflict_detector.py

ConflictDetector — analyzes multiple StateDelta patches for logical contradictions.
Used by SemanticMergeInterceptor to decide if Opus arbitration is needed.

Conflict types detected:
    1. path_collision      — two deltas write the same JSON path with different values
    2. op_contradiction    — one delta adds at path X, another removes at path X
    3. semantic_contradiction — two deltas replace the same field with different values

# VERIFICATION_STAMP
# Story: 7.01
# Verified By: parallel-builder
# Verified At: 2026-02-25
# Tests: 10/10
# Coverage: 100%
    )annotationsN)	dataclassfield)Anyc                  p    e Zd ZU dZded<    ee      Zded<    ee      Zded<    ee      Z	ded	<   y
)ConflictReportzBResult of conflict detection across multiple StateDelta proposals.boolhas_conflicts)default_factory	list[str]conflicting_pathsconflict_typeslistnon_conflicting_deltasN)
__name__
__module____qualname____doc____annotations__r   r   r   r   r        5/mnt/e/genesis-system/core/merge/conflict_detector.pyr   r   "   s:    L#(#>y> %d ;NI;#(#>D>r   r   c                  \    e Zd ZdZddZddZed	d       Ze	 	 	 	 	 	 	 	 	 	 	 	 d
d       Zy)ConflictDetectorag  
    Analyzes multiple StateDelta patches for logical contradictions.

    A StateDelta is expected to have a ``patch`` attribute that is either a
    tuple or list of RFC 6902 operation dicts.  Plain dicts with a ``patch``
    key are also accepted (for testing convenience).

    Algorithm
    ---------
    1. Build a path-ops map: for every delta, collect every (path, op, value)
       triple and record which delta index it came from.
    2. For each path that appears in more than one delta, run three checks:
       - Type 1 (path_collision): same path, op is add/replace, values differ.
       - Type 2 (op_contradiction): mix of add and remove ops at same path.
       - Type 3 (semantic_contradiction): same path, op is replace, values differ.
    3. Deltas whose indices never appear in the conflict set are returned as
       ``non_conflicting_deltas``.
    c                   |st        dg       S t        |      dk(  rt        dt        |            S i }t        |      D ]w  \  }}| j	                  |      }|D ]\  }|j                  dd      }|j                  dd      }|j                  dd      }	|j                  |g       j                  |||	f       ^ y g }
g }t               }|j                         D ])  \  }}t        |      d	k  r| j                  |||
||       + t        |      D cg c]  \  }}||vs| }}}t        |
      }t        ||
||
      }t        j                  dt        |      ||
|       |S c c}}w )a0  
        Analyze *deltas* for logical conflicts.

        Args:
            deltas: List of StateDelta objects (or dicts with a ``patch`` key).

        Returns:
            ConflictReport describing all detected conflicts and which deltas
            are safe to merge without Opus arbitration.
        F)r
   r      path opvalueN   )r
   r   r   r   uK   ConflictDetector.detect: %d deltas → has_conflicts=%s, paths=%s, types=%s)r   lenr   	enumerate_extract_patchget
setdefaultappendsetitems_check_pathr	   loggerdebug)selfdeltaspath_opsidxdeltapatchop_dictr   op_typer    r   r   conflicting_indicesopsidnon_conflictingr
   reports                      r   detectzConflictDetector.detectJ   s    !bQQv;!!#'+F|  ;=#F+ 	LJC''.E  L#KK3&{{44$[[$7##D"-44c7E5JK	L	L (*$&(+!) 	ID#3x!|!#	 $F+
!Qq8K/KA
 
 ./'/)#2	
 	YK	
 %
s   E% E%c                \    g }|D ]$  }| j                  |      }|j                  |       & |S )u  
        Merge non-conflicting patches into a single combined operation list.

        No Opus arbitration call needed — patches are simply concatenated in
        submission order.

        Args:
            non_conflicting_deltas: List of StateDelta / dict objects whose
                                    patches are known not to conflict.

        Returns:
            Flat list of RFC 6902 operation dicts from all supplied deltas.
        )r$   extend)r-   r   mergedr1   r2   s        r   
fast_mergezConflictDetector.fast_merge   s;      + 	!E''.EMM% 	! r   c                    t        | d      r| j                  }n%t        | t              r| j	                  dg       }ng }t        |t
              rt        |      S t        |t              r|S g S )z
        Return the patch as a plain list regardless of whether *delta* is a
        StateDelta (with a ``patch`` tuple attribute) or a plain dict.
        r2   )hasattrr2   
isinstancedictr%   tupler   )r1   r2   s     r   r$   zConflictDetector._extract_patch   s`     5'"KKEt$IIgr*EE eU#;eT"L	r   c                   d}|D cg c]  \  }}}|dv r|||f }	}}}t        |	      dk\  rr|	D 
ch c]  \  }
}
}t        |       }}
}t        |      dkD  rF|s|j                  |        d}d|vr|j                  d       |	D ]  \  }}
}
|j                  |        |D 
ch c]  \  }
}}
|
 }}
}d|v rOd|v rK|s|j                  |        d}d	|vr|j                  d	       |D ]  \  }}}
|d
v s|j                  |        |D cg c]  \  }}}|dk(  s||f }}}}t        |      dk\  rp|D 
ch c]  \  }
}t        |       }}
}t        |      dkD  rD|s|j                  |        d|vr|j                  d       |D ]  \  }}
|j                  |        yyyc c}}}w c c}}
w c c}}
w c c}}}w c c}}
w )z
        Run all three conflict checks for a single *path* that appears in
        more than one delta.  Mutates the supplied output collections in place.
        F)addreplacer!   r   Tpath_collisionrF   removeop_contradiction)rF   rI   rG   semantic_contradictionN)r"   reprr'   rF   )r   r6   r   r   r5   path_already_recordedr0   r4   val	write_ops_unique_reprsop_types_presentreplace_opsunique_replace_reprss                  r   r*   zConflictDetector._check_path   s.    !&
 &)
 
!Wc,, '3
	 

 y>Q7@A)!QDIALA< 1$,%,,T2,0)#>9"))*:;!* 1ICA'++C01 :==7AG==$$5E)E(!((.(,%!7%%&89#& 1Wa//'++C01 14
 
,3w)7KS#J
 
 {q <G#H&!SDI#H #H'(1,,%,,T2+>A"))*BC) 1FC'++C01 - !A
 B >
 $Is"   F'F.&F4F:F:;GN)r.   r   returnr   )r   r   rU   
list[dict])r1   r   rU   rV   )r   strr6   zlist[tuple[int, str, Any]]r   r   r   r   r5   zset[int]rU   None)	r   r   r   r   r;   r?   staticmethodr$   r*   r   r   r   r   r   2   ss    .EN0  & 7171'71 %71 "	71
 &71 
71 71r   r   )r   
__future__r   loggingdataclassesr   r   typingr   	getLoggerr   r+   r   r   r   r   r   <module>r_      sO   & #  ( 			8	$ ? ? ?C1 C1r   