Files
taskgraph_ts/docs/architecture/decisions/003-topo-order-throws-on-cycle.md
glm-5.1 bde1cc4e70 Decompose monolithic architecture.md into modular docs/architecture/ documents
The 751-line architecture.md violated the SDD process modular documentation
target (~500 lines). It also had duplicate TaskGraph class definitions (one
monolith, one decomposed) that directly contradicted each other, and embedded
consumer-specific tool dispatch mappings that belong in downstream projects.

Changes:
- Split into 8 focused documents + 7 ADR records + redirect page
- Removed the monolithic TaskGraph class (kept only decomposed version)
- Moved CLI→plugin dispatch mapping out (belongs in plugin architecture)
- Extracted implementation code (frontmatter splitter, findCycles, DAG
  propagation) into WHAT/WHY descriptions per architect role spec
- Added proper ADR format for all resolved design decisions
- Fixed review issues: C_fail mapping, DuplicateNodeError/DuplicateEdgeError
  types, ValidationError/GraphValidationError definitions, mutation error
  handling contract, enum naming convention, validation timing clarification
2026-04-26 06:38:52 +00:00

1.2 KiB

ADR-003: topologicalOrder throws CircularDependencyError on cyclic graphs

Status: Accepted

Context

When a graph has cycles, topological sort cannot produce a complete ordering. Options: return null, return a partial ordering, or throw an error with cycle information.

Decision

Throw CircularDependencyError with cycles populated from findCycles(). Do not return a partial ordering or null.

Consequences

Positive

  • Prevents silent ignoring of cycles — consumers get explicit error information
  • CircularDependencyError.cycles provides the actual cycle paths for error reporting
  • Simpler return type — string[] instead of string[] | null or string[][]
  • Both consumers treat cycles as bugs: alkhub data comes from validated DB schema; OpenCode plugin data comes from frontmatter that should be validated before graph construction

Negative

  • Callers who want "best effort" ordering on cyclic graphs must catch the error and call findCycles() separately
  • Cannot get partial results — if you want "topo sort of the acyclic portions," that requires filtering first

Mitigation

findCycles() and hasCycles() are available for consumers that want to handle cycles gracefully before calling topologicalOrder().