Detect informed commit: explore → commit (without verification).
(
nodes: &[GraphNode],
seq: &[usize],
counter: &mut u64,
prefix: &str,
)
| 482 | |
| 483 | /// Detect informed commit: explore → commit (without verification). |
| 484 | fn detect_informed_commit( |
| 485 | nodes: &[GraphNode], |
| 486 | seq: &[usize], |
| 487 | counter: &mut u64, |
| 488 | prefix: &str, |
| 489 | ) -> Option<(GraphNode, Vec<GraphEdge>)> { |
| 490 | let kinds: Vec<NodeKind> = seq.iter().map(|&i| nodes[i].kind).collect(); |
| 491 | |
| 492 | let has_exploration = kinds.contains(&NodeKind::Exploration); |
| 493 | let has_commitment = kinds.contains(&NodeKind::Commitment); |
| 494 | let has_verification = kinds.contains(&NodeKind::Verification); |
| 495 | |
| 496 | if !(has_exploration && has_commitment && !has_verification) { |
| 497 | return None; |
| 498 | } |
| 499 | |
| 500 | let exploration_count = kinds |
| 501 | .iter() |
| 502 | .filter(|k| **k == NodeKind::Exploration) |
| 503 | .count(); |
| 504 | |
| 505 | let committed_file = seq |
| 506 | .iter() |
| 507 | .filter(|&&i| nodes[i].kind == NodeKind::Commitment) |
| 508 | .find_map(|&i| extract_file(&nodes[i])); |
| 509 | |
| 510 | let file_display = committed_file |
| 511 | .as_deref() |
| 512 | .map(short_path) |
| 513 | .unwrap_or_else(|| "file".to_string()); |
| 514 | |
| 515 | let summary = format!( |
| 516 | "Investigated {} file{} → edited {}", |
| 517 | exploration_count, |
| 518 | if exploration_count == 1 { "" } else { "s" }, |
| 519 | file_display |
| 520 | ); |
| 521 | |
| 522 | let consolidated_ids: Vec<String> = seq.iter().map(|&i| nodes[i].id.clone()).collect(); |
| 523 | |
| 524 | let detail = serde_json::json!({ |
| 525 | "pattern": "informed_commit", |
| 526 | "explorations": exploration_count, |
| 527 | "file": committed_file, |
| 528 | }); |
| 529 | |
| 530 | let id = next_id(counter, prefix); |
| 531 | let timestamp = seq.last().map(|&i| nodes[i].timestamp).unwrap_or_default(); |
| 532 | |
| 533 | let mut node = GraphNode::new(&id, NodeKind::Decision, timestamp, summary).with_detail(detail); |
| 534 | node.classified = true; |
| 535 | node.confidence = Some(0.75); |
| 536 | node.consolidated_from = consolidated_ids; |
| 537 | |
| 538 | let decision_edges = build_decision_edges(nodes, seq, &id); |
| 539 | |
| 540 | Some((node, decision_edges)) |
| 541 | } |
no test coverage detected