Attempt to merge a conflict group using token-level semantics. # Algorithm 1. Extract the two competing vertices (only 2-way supported). 2. Retrieve content bytes for both from the [`ChangeStore`]. 3. Find the common ancestor vertex — the dead vertex that both competing changes deleted. 4. Retrieve content bytes for the ancestor. 5. Tokenize all three byte sequences. 6. Run a three-way diff at t
(&self, group: &ConflictGroup)
| 87 | /// |
| 88 | /// Returns [`PristineError`] on database access failure. |
| 89 | pub fn try_merge(&self, group: &ConflictGroup) -> Result<MergeOutcome, PristineError> { |
| 90 | // Only two-way conflicts are candidates (the most common case). |
| 91 | if group.vertex_count() != 2 { |
| 92 | log::debug!( |
| 93 | "SemanticMergeEngine::try_merge: skipping {}-way conflict (only 2-way supported)", |
| 94 | group.vertex_count(), |
| 95 | ); |
| 96 | return Ok(MergeOutcome::NoCrdtData); |
| 97 | } |
| 98 | |
| 99 | let v_left = &group.vertices[0]; |
| 100 | let v_right = &group.vertices[1]; |
| 101 | |
| 102 | // Step 1-2: Get content bytes for both competing vertices. |
| 103 | let left_content = match self.get_vertex_content(v_left) { |
| 104 | Ok(c) => c, |
| 105 | Err(e) => { |
| 106 | log::debug!( |
| 107 | "SemanticMergeEngine::try_merge: cannot read left vertex {}: {}", |
| 108 | v_left, |
| 109 | e, |
| 110 | ); |
| 111 | return Ok(MergeOutcome::NoCrdtData); |
| 112 | } |
| 113 | }; |
| 114 | |
| 115 | let right_content = match self.get_vertex_content(v_right) { |
| 116 | Ok(c) => c, |
| 117 | Err(e) => { |
| 118 | log::debug!( |
| 119 | "SemanticMergeEngine::try_merge: cannot read right vertex {}: {}", |
| 120 | v_right, |
| 121 | e, |
| 122 | ); |
| 123 | return Ok(MergeOutcome::NoCrdtData); |
| 124 | } |
| 125 | }; |
| 126 | |
| 127 | // Step 3: Find the common ancestor vertex (the dead vertex both sides |
| 128 | // replaced). Try the explicit `ancestor` field first, then fall back |
| 129 | // to graph-based discovery using the `parent` field. |
| 130 | let base_content = if let Some(ref ancestor) = group.ancestor { |
| 131 | match self.get_vertex_content(ancestor) { |
| 132 | Ok(c) => c, |
| 133 | Err(e) => { |
| 134 | log::debug!( |
| 135 | "SemanticMergeEngine::try_merge: cannot read ancestor {}: {}", |
| 136 | ancestor, |
| 137 | e, |
| 138 | ); |
| 139 | return Ok(MergeOutcome::NoCrdtData); |
| 140 | } |
| 141 | } |
| 142 | } else if let Some(ref parent) = group.parent { |
| 143 | match self.find_ancestor_content(parent, v_left.change, v_right.change) { |
| 144 | Ok(Some(content)) => content, |
| 145 | Ok(None) => { |
| 146 | log::debug!( |