Detect commit-and-verify: commit → verify (without preceding exploration).
(
nodes: &[GraphNode],
seq: &[usize],
counter: &mut u64,
prefix: &str,
)
| 422 | |
| 423 | /// Detect commit-and-verify: commit → verify (without preceding exploration). |
| 424 | fn detect_commit_and_verify( |
| 425 | nodes: &[GraphNode], |
| 426 | seq: &[usize], |
| 427 | counter: &mut u64, |
| 428 | prefix: &str, |
| 429 | ) -> Option<(GraphNode, Vec<GraphEdge>)> { |
| 430 | let kinds: Vec<NodeKind> = seq.iter().map(|&i| nodes[i].kind).collect(); |
| 431 | |
| 432 | let has_commitment = kinds.contains(&NodeKind::Commitment); |
| 433 | let has_verification = kinds.contains(&NodeKind::Verification); |
| 434 | let has_exploration = kinds.contains(&NodeKind::Exploration); |
| 435 | |
| 436 | if !(has_commitment && has_verification && !has_exploration) { |
| 437 | return None; |
| 438 | } |
| 439 | |
| 440 | let committed_file = seq |
| 441 | .iter() |
| 442 | .filter(|&&i| nodes[i].kind == NodeKind::Commitment) |
| 443 | .find_map(|&i| extract_file(&nodes[i])); |
| 444 | |
| 445 | let verify_cmd = seq |
| 446 | .iter() |
| 447 | .filter(|&&i| nodes[i].kind == NodeKind::Verification) |
| 448 | .find_map(|&i| extract_command(&nodes[i])); |
| 449 | |
| 450 | let file_display = committed_file |
| 451 | .as_deref() |
| 452 | .map(short_path) |
| 453 | .unwrap_or_else(|| "file".to_string()); |
| 454 | |
| 455 | let cmd_display = verify_cmd |
| 456 | .as_deref() |
| 457 | .map(|c| truncate(c, 40)) |
| 458 | .unwrap_or_else(|| "tests".to_string()); |
| 459 | |
| 460 | let summary = format!("Edited {} → verified with {}", file_display, cmd_display); |
| 461 | |
| 462 | let consolidated_ids: Vec<String> = seq.iter().map(|&i| nodes[i].id.clone()).collect(); |
| 463 | |
| 464 | let detail = serde_json::json!({ |
| 465 | "pattern": "commit_and_verify", |
| 466 | "file": committed_file, |
| 467 | "verify_command": verify_cmd, |
| 468 | }); |
| 469 | |
| 470 | let id = next_id(counter, prefix); |
| 471 | let timestamp = seq.last().map(|&i| nodes[i].timestamp).unwrap_or_default(); |
| 472 | |
| 473 | let mut node = GraphNode::new(&id, NodeKind::Decision, timestamp, summary).with_detail(detail); |
| 474 | node.classified = true; |
| 475 | node.confidence = Some(0.80); |
| 476 | node.consolidated_from = consolidated_ids; |
| 477 | |
| 478 | let decision_edges = build_decision_edges(nodes, seq, &id); |
| 479 | |
| 480 | Some((node, decision_edges)) |
| 481 | } |
no test coverage detected