From f85ec9d06f30e83d9df2916a38f31caab81309ac Mon Sep 17 00:00:00 2001 From: Ed_ Date: Fri, 27 Feb 2026 20:04:04 -0500 Subject: [PATCH] feat(mma): Add topological sorting to TrackDAG with cycle detection --- dag_engine.py | 26 ++++++++++++++++++++++++++ tests/test_dag_engine.py | 17 +++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/dag_engine.py b/dag_engine.py index e437831..29028c5 100644 --- a/dag_engine.py +++ b/dag_engine.py @@ -50,3 +50,29 @@ class TrackDAG: if is_cyclic(ticket.id): return True return False + + def topological_sort(self) -> List[str]: + """ + Returns a list of ticket IDs in topological order. + Raises ValueError if a cycle is detected. + """ + if self.has_cycle(): + raise ValueError("Dependency cycle detected") + + visited = set() + stack = [] + + def visit(ticket_id): + if ticket_id in visited: + return + visited.add(ticket_id) + ticket = self.ticket_map.get(ticket_id) + if ticket: + for dep_id in ticket.depends_on: + visit(dep_id) + stack.append(ticket_id) + + for ticket in self.tickets: + visit(ticket.id) + + return stack diff --git a/tests/test_dag_engine.py b/tests/test_dag_engine.py index 004f409..49d5eff 100644 --- a/tests/test_dag_engine.py +++ b/tests/test_dag_engine.py @@ -65,3 +65,20 @@ def test_get_ready_tasks_multiple_deps(): t2.status = "todo" assert [t.id for t in dag.get_ready_tasks()] == ["T2"] + +def test_topological_sort(): + t1 = Ticket(id="T1", description="T1", status="todo", assigned_to="worker") + t2 = Ticket(id="T2", description="T2", status="todo", assigned_to="worker", depends_on=["T1"]) + t3 = Ticket(id="T3", description="T3", status="todo", assigned_to="worker", depends_on=["T2"]) + + dag = TrackDAG([t1, t2, t3]) + sort = dag.topological_sort() + assert sort == ["T1", "T2", "T3"] + +def test_topological_sort_cycle(): + t1 = Ticket(id="T1", description="T1", status="todo", assigned_to="worker", depends_on=["T2"]) + t2 = Ticket(id="T2", description="T2", status="todo", assigned_to="worker", depends_on=["T1"]) + + dag = TrackDAG([t1, t2]) + with pytest.raises(ValueError, match="Dependency cycle detected"): + dag.topological_sort()