Graph node (value + grad + backward fn) gave every Value its own _backward closure, capable of pushing gradient into its immediate parents, given its OWN gradient is already known. But for anything beyond a single operation, that raises an ordering question: in an expression like c = a*b + a, the intermediate node a*b needs ITS gradient computed before it can push gradient further back into a and b, and c needs to run first of all (it's the very output the whole backward pass starts from). Call _backward in the wrong order, on a node whose OWN .grad hasn't been fully accumulated yet, and you get a silently wrong answer, not a crash, just numbers that look plausible but aren't the real gradient.
Topological sort is the tool that guarantees the right order: an ordering of every node in the graph where every node appears strictly after everything it depends on, which, read in REVERSE, is exactly the order a correct backward pass needs to call every node's _backward.
Theory performs a post-order depth-first traversal from the output node: recurse into every parent FIRST, then append the current node, after every parent has already been appended. This guarantees every node appears after all its ancestors in the returned list, with the starting node last.
Implement build_topo_order(root) against that reasoning. The signature and docstring are already in the editor.
Graph node's own accumulation tests exercise) appears exactly once in the result.root must be the LAST element of the returned list.Open one at a time. Each gives away a little more than the last.
Write a recursive helper: if a node hasn't been visited yet, mark it visited, recurse into every one of its _prev parents, THEN append the node itself, in that order.
Call the helper once, starting from root, and return whatever list it built up via its appends.
Click "Run Tests" to test your implementation