rivox 1.0.0

Universal polyglot build coordination layer for Python, Rust, and Node monorepos
Documentation
use super::GraphNode;
use super::builder::UnifiedGraph;
use anyhow::{Result, bail};
use petgraph::algo::toposort;
use petgraph::visit::Topo;
use std::collections::HashMap;

pub struct Scheduler;

impl Scheduler {
    /// Plans sequential topological execution of DAG nodes.
    pub fn plan_execution(unified_graph: &UnifiedGraph) -> Result<Vec<GraphNode>> {
        match toposort(&unified_graph.graph, None) {
            Ok(node_indices) => {
                let scheduled_nodes = node_indices
                    .into_iter()
                    .map(|idx| unified_graph.graph[idx].clone())
                    .collect();
                Ok(scheduled_nodes)
            }
            Err(cycle) => {
                bail!(
                    "Cyclic dependency detected in unified build graph around node index {:?}",
                    cycle.node_id()
                );
            }
        }
    }

    /// Plans async wavefront parallel execution levels (RFC-003).
    /// Returns a vector of wavefronts, where each wavefront contains independent nodes that can be built in parallel.
    pub fn plan_wavefronts(unified_graph: &UnifiedGraph) -> Result<Vec<Vec<GraphNode>>> {
        let mut depths: HashMap<petgraph::graph::NodeIndex, usize> = HashMap::new();
        let mut topo = Topo::new(&unified_graph.graph);

        while let Some(node_idx) = topo.next(&unified_graph.graph) {
            let max_pred_depth = unified_graph
                .graph
                .neighbors_directed(node_idx, petgraph::Direction::Incoming)
                .map(|pred| depths.get(&pred).copied().unwrap_or(0))
                .max();

            let current_depth = match max_pred_depth {
                Some(depth) => depth + 1,
                None => 0,
            };

            depths.insert(node_idx, current_depth);
        }

        if depths.len() != unified_graph.graph.node_count() {
            bail!("Cyclic dependency detected during wavefront analysis");
        }

        let max_depth = depths.values().copied().max().unwrap_or(0);
        let mut wavefronts = vec![Vec::new(); max_depth + 1];

        for (node_idx, depth) in depths {
            let node = unified_graph.graph[node_idx].clone();
            wavefronts[depth].push(node);
        }

        Ok(wavefronts)
    }
}