Summary
Add strongly-connected component (SCC) awareness to SessionQueue so tasks within dependency cycles can be scheduled as co-released batches once their external dependencies are satisfied.
Motivation
Real-world dependency graphs often contain intentional cycles. In code dependency graphs (e.g., mutually recursive modules), infrastructure dependency graphs (circular service dependencies), and task decomposition outputs from LLMs, cycles are common and legitimate.
Currently, SessionQueue.topologicalSort() throws CyclicDependencyError when cycles exist. The only options are to fail or to pre-process the graph externally. AAMF solves this by computing SCCs via Tarjan's algorithm and treating intra-SCC dependencies as pre-satisfied — all members of an SCC become ready once their external dependencies are met.
This is a small, self-contained addition that makes the existing SessionQueue usable for a much wider class of dependency graphs.
Proposed API
SessionQueue Additions
class SessionQueue {
// ... existing methods ...
/**
* Register strongly-connected components.
*
* SCC-internal dependencies are treated as pre-satisfied by getReady() —
* all members of an SCC become ready once their external dependencies
* are complete. This allows scheduling tasks with mutual/circular
* dependencies without requiring the graph to be a DAG.
*
* @param sccs - Arrays of session IDs forming cycles. Only SCCs with
* 2+ members need to be registered (singletons are trivial).
*/
setSCCs(sccs: string[][]): void;
/**
* Get the SCC containing the given session, or undefined if the session
* is not part of any registered SCC.
*/
getSCC(sessionId: string): string[] | undefined;
}
Tarjan's SCC Finder (Utility)
Export a generic SCC computation utility:
/**
* Find all strongly-connected components in a directed graph using
* Tarjan's algorithm. Returns only non-trivial SCCs (size >= 2).
*
* @param nodes - All node IDs in the graph.
* @param edges - Map from node ID to its dependency (successor) IDs.
* @returns Arrays of node IDs forming non-trivial SCCs.
*/
export function findSCCs(nodes: string[], edges: Map<string, string[]>): string[][];
Impact on Existing Methods
getReady() — When checking if a session's dependencies are satisfied, intra-SCC deps are treated as pre-satisfied. All SCC members become ready simultaneously once external deps are met.
topologicalSort() — Instead of throwing on cycles, collapse each SCC into a single node for ordering purposes. Members within an SCC are returned in registration order.
restoreState() — No changes needed; completed/blocked tracking is per-session, not per-SCC.
detectBatchCollisions() / selectNonOverlappingBatch() — SCC members should preferably be scheduled in the same batch to reduce cross-batch dependency waiting.
Implementation Notes
setSCCs builds an internal Map<string, Set<string>> mapping each member to its SCC peer set — O(total members) construction, O(1) per lookup in getReady()
- The
findSCCs utility is a standalone function (not a SessionQueue method) so it can be used independently for any graph analysis
- SCC registration is optional — if
setSCCs is never called, behavior is unchanged (strict DAG enforcement)
- Consider adding a
computeSCCs() convenience method on SessionQueue that calls findSCCs over the session dependency graph and auto-registers the results
Summary
Add strongly-connected component (SCC) awareness to
SessionQueueso tasks within dependency cycles can be scheduled as co-released batches once their external dependencies are satisfied.Motivation
Real-world dependency graphs often contain intentional cycles. In code dependency graphs (e.g., mutually recursive modules), infrastructure dependency graphs (circular service dependencies), and task decomposition outputs from LLMs, cycles are common and legitimate.
Currently,
SessionQueue.topologicalSort()throwsCyclicDependencyErrorwhen cycles exist. The only options are to fail or to pre-process the graph externally. AAMF solves this by computing SCCs via Tarjan's algorithm and treating intra-SCC dependencies as pre-satisfied — all members of an SCC become ready once their external dependencies are met.This is a small, self-contained addition that makes the existing
SessionQueueusable for a much wider class of dependency graphs.Proposed API
SessionQueue Additions
Tarjan's SCC Finder (Utility)
Export a generic SCC computation utility:
Impact on Existing Methods
getReady()— When checking if a session's dependencies are satisfied, intra-SCC deps are treated as pre-satisfied. All SCC members become ready simultaneously once external deps are met.topologicalSort()— Instead of throwing on cycles, collapse each SCC into a single node for ordering purposes. Members within an SCC are returned in registration order.restoreState()— No changes needed; completed/blocked tracking is per-session, not per-SCC.detectBatchCollisions()/selectNonOverlappingBatch()— SCC members should preferably be scheduled in the same batch to reduce cross-batch dependency waiting.Implementation Notes
setSCCsbuilds an internalMap<string, Set<string>>mapping each member to its SCC peer set — O(total members) construction, O(1) per lookup ingetReady()findSCCsutility is a standalone function (not aSessionQueuemethod) so it can be used independently for any graph analysissetSCCsis never called, behavior is unchanged (strict DAG enforcement)computeSCCs()convenience method onSessionQueuethat callsfindSCCsover the session dependency graph and auto-registers the results