MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / detect_backtracking

Function detect_backtracking

atomic-agent/src/provenance/consolidate.rs:192–255  ·  view source on GitHub ↗

Detect backtracking: the agent reads/edits the same file multiple times. Pattern: any file appears in both an exploration AND a commitment more than once in the sequence, suggesting the agent revised its approach.

(
    nodes: &[GraphNode],
    seq: &[usize],
    counter: &mut u64,
    prefix: &str,
)

Source from the content-addressed store, hash-verified

190/// Pattern: any file appears in both an exploration AND a commitment more
191/// than once in the sequence, suggesting the agent revised its approach.
192fn detect_backtracking(
193 nodes: &[GraphNode],
194 seq: &[usize],
195 counter: &mut u64,
196 prefix: &str,
197) -> Option<(GraphNode, Vec<GraphEdge>)> {
198 let mut file_edit_counts: std::collections::HashMap<String, u32> =
199 std::collections::HashMap::new();
200
201 for &idx in seq {
202 let node = &nodes[idx];
203 if node.kind == NodeKind::Commitment {
204 if let Some(file) = extract_file(node) {
205 *file_edit_counts.entry(file).or_default() += 1;
206 }
207 }
208 }
209
210 // Need at least one file edited more than once
211 let repeated: Vec<(&String, &u32)> = file_edit_counts
212 .iter()
213 .filter(|(_, count)| **count > 1)
214 .collect();
215
216 if repeated.is_empty() {
217 return None;
218 }
219
220 let max_file = repeated
221 .iter()
222 .max_by_key(|(_, c)| *c)
223 .map(|(f, _)| f.to_string())
224 .unwrap_or_default();
225 let max_count = file_edit_counts.get(&max_file).copied().unwrap_or(0);
226
227 let summary = format!(
228 "Iterated on {} ({} attempts)",
229 short_path(&max_file),
230 max_count
231 );
232
233 let consolidated_ids: Vec<String> = seq.iter().map(|&i| nodes[i].id.clone()).collect();
234
235 let detail = serde_json::json!({
236 "pattern": "backtracking",
237 "iterations": max_count,
238 "file": max_file,
239 "files_revisited": repeated.iter().map(|(f, c)| {
240 serde_json::json!({"file": f, "edits": c})
241 }).collect::<Vec<_>>(),
242 });
243
244 let id = next_id(counter, prefix);
245 let timestamp = seq.last().map(|&i| nodes[i].timestamp).unwrap_or_default();
246
247 let mut node = GraphNode::new(&id, NodeKind::Decision, timestamp, summary).with_detail(detail);
248 node.classified = true;
249 node.confidence = Some(0.85);

Callers 1

consolidateFunction · 0.85

Calls 9

extract_fileFunction · 0.85
build_decision_edgesFunction · 0.85
lastMethod · 0.80
with_detailMethod · 0.80
next_idFunction · 0.70
getMethod · 0.65
iterMethod · 0.45
is_emptyMethod · 0.45
cloneMethod · 0.45

Tested by

no test coverage detected