Dependency frontiers
A build job can start only after every prerequisite has finished. Count incoming edges and keep a frontier of jobs with no unresolved prerequisites. Processing a job removes its outgoing dependencies, which can make more jobs ready. If the frontier empties before all jobs are processed, a cycle remains.
The same traversal supports several different questions. Selecting the smallest ready identifier gives a reproducible order. Two ready jobs reveal a choice, so the complete order isn't unique. Finish times use the slowest predecessor, while chain counts add contributions from tied predecessors. These values must be updated before a successor leaves the frontier. Start with a feasibility audit, then distinguish ordering rules from the values you propagate through the graph.
dependencies = [[0,2], [1,2], [2,3]]
initial ready = [0,1]
smallest valid order = [0,1,2,3]
durations = [3,7,2,4]
finish times = [3,7,9,13]
Job 2 waits until time 7; job 3 finishes at time 13.