Build edges connecting a decision node to the surrounding context. The decision node gets: - An edge from the most recent goal (if any precedes the sequence) - An edge to the next structural node after the sequence (if any)
(nodes: &[GraphNode], seq: &[usize], decision_id: &str)
| 674 | /// - An edge from the most recent goal (if any precedes the sequence) |
| 675 | /// - An edge to the next structural node after the sequence (if any) |
| 676 | fn build_decision_edges(nodes: &[GraphNode], seq: &[usize], decision_id: &str) -> Vec<GraphEdge> { |
| 677 | let mut edges = Vec::new(); |
| 678 | |
| 679 | let first_idx = match seq.first() { |
| 680 | Some(&i) => i, |
| 681 | None => return edges, |
| 682 | }; |
| 683 | |
| 684 | // Find the most recent goal before this sequence |
| 685 | for i in (0..first_idx).rev() { |
| 686 | if nodes[i].kind == NodeKind::Goal { |
| 687 | edges.push(GraphEdge::new( |
| 688 | nodes[i].id.clone(), |
| 689 | decision_id.to_string(), |
| 690 | EdgeKind::LedTo, |
| 691 | )); |
| 692 | break; |
| 693 | } |
| 694 | } |
| 695 | |
| 696 | // Find the next patch proposal after this sequence to link to |
| 697 | let last_idx = seq.last().copied().unwrap_or(first_idx); |
| 698 | for node in nodes.iter().skip(last_idx + 1) { |
| 699 | if node.kind == NodeKind::PatchProposal { |
| 700 | edges.push(GraphEdge::new( |
| 701 | decision_id.to_string(), |
| 702 | node.id.clone(), |
| 703 | EdgeKind::CommittedVia, |
| 704 | )); |
| 705 | break; |
| 706 | } |
| 707 | } |
| 708 | |
| 709 | edges |
| 710 | } |
| 711 | |
| 712 | /// Generate the next node ID. |
| 713 | fn next_id(counter: &mut u64, prefix: &str) -> String { |
no test coverage detected