pub struct Graph {
pub edges: HashMap<String, HashSet<String>>,
pub reverse: HashMap<String, HashSet<String>>,
}Expand description
Dependency graph built from task depends_on fields.
Fields§
§edges: HashMap<String, HashSet<String>>task_id -> set of task IDs it depends on
reverse: HashMap<String, HashSet<String>>task_id -> set of task IDs that depend on it (reverse edges)
Implementations§
Source§impl Graph
impl Graph
Sourcepub fn build(tasks: &HashMap<String, Task>) -> Self
pub fn build(tasks: &HashMap<String, Task>) -> Self
Build a dependency graph from a set of tasks.
Sourcepub fn ready<'a>(
&self,
tasks: &'a HashMap<String, Task>,
tag: Option<&str>,
limit: Option<usize>,
epic: Option<&str>,
) -> Vec<&'a Task>
pub fn ready<'a>( &self, tasks: &'a HashMap<String, Task>, tag: Option<&str>, limit: Option<usize>, epic: Option<&str>, ) -> Vec<&'a Task>
Return tasks that are ready: status is Open and all dependencies are Done.
Effective priorities are computed once in O(V+E) rather than per-task inside the sort comparator.
Sourcepub fn effective_priority(
&self,
id: &str,
tasks: &HashMap<String, Task>,
) -> Priority
pub fn effective_priority( &self, id: &str, tasks: &HashMap<String, Task>, ) -> Priority
Compute the effective priority of a single task. This is the minimum (highest urgency) of the task’s own priority and the priorities of all tasks that depend on it, transitively.
For bulk computation prefer Graph::effective_priorities_all which
runs in O(V+E) instead of O(V+E) per call.
Sourcepub fn effective_priorities_all(
&self,
tasks: &HashMap<String, Task>,
) -> HashMap<String, Priority>
pub fn effective_priorities_all( &self, tasks: &HashMap<String, Task>, ) -> HashMap<String, Priority>
Compute effective priorities for ALL tasks in a single O(V+E) pass.
effective(x) = min(own(x), min over direct dependents y of effective(y))
We process nodes in reverse-topological order (dependents before their dependencies) so that by the time we visit a node its dependents are already resolved. Nodes that participate in a cycle are not reached by the topological pass and keep their own priority as a safe fallback.
Sourcepub fn would_cycle(&self, from: &str, to: &str) -> bool
pub fn would_cycle(&self, from: &str, to: &str) -> bool
Check if adding an edge from -> to would create a cycle.
Does BFS from to following edges; if we reach from, it’s a cycle.
Sourcepub fn dep_tree<'a>(
&self,
tasks: &'a HashMap<String, Task>,
id: &str,
) -> Option<DepNode<'a>>
pub fn dep_tree<'a>( &self, tasks: &'a HashMap<String, Task>, id: &str, ) -> Option<DepNode<'a>>
Build a dependency tree for display.
Uses two sets to bound rendering:
visiting(path-local): cycle detection — a node on the current recursion path is emitted as a leaf withcycle: true.seen(render-global): DAG deduplication — a node already fully expanded on any earlier path is emitted as a leaf withseen: true(and no children), preventing exponential blowup on diamond shapes.
Sourcepub fn topo_sort_subset<'a>(
&self,
subset: &HashSet<String>,
tasks: &'a HashMap<String, Task>,
) -> SubsetTopo<'a>
pub fn topo_sort_subset<'a>( &self, subset: &HashSet<String>, tasks: &'a HashMap<String, Task>, ) -> SubsetTopo<'a>
Topological sort over a subset of task IDs.
Only dependency edges between tasks in the subset are considered.
Tie-breaking: priority (P0 first), then creation date (oldest first).
Tasks caught in a dependency cycle cannot be ordered and are returned
separately in cyclic instead of being silently dropped.
Sourcepub fn adjacency_list(&self) -> HashMap<&str, Vec<&str>>
pub fn adjacency_list(&self) -> HashMap<&str, Vec<&str>>
Get adjacency list for JSON output (full, unfiltered).
Sourcepub fn bounded_adjacency_list<'a>(
&'a self,
tasks: &'a HashMap<String, Task>,
include_done: bool,
epic: Option<&str>,
limit: Option<usize>,
) -> HashMap<&'a str, Vec<&'a str>>
pub fn bounded_adjacency_list<'a>( &'a self, tasks: &'a HashMap<String, Task>, include_done: bool, epic: Option<&str>, limit: Option<usize>, ) -> HashMap<&'a str, Vec<&'a str>>
Get a bounded adjacency list suitable for MCP/JSON output.
Excludes:
- Done/cancelled tasks by default (unless
include_doneis true) - Isolated nodes that have no dependencies and no dependents within the included set
Optional filters:
epic: include only children of the given epic ID (plus the epic itself)limit: cap the number of nodes in the output