---
sources:
  - ../../src/analyses/depth.rs
---

# Topological depth

## The concept

**Topological depth** assigns each node its distance from the nearest root (a node with in-degree 0). Roots are at depth 0. Nodes reachable only through one hop are at depth 1, and so on. When multiple paths lead to a node, the longest path determines its depth (giving the "deepest" layer assignment).

```
depth 0:  index.md
depth 1:  setup.md, overview.md
depth 2:  details/install.md
```

For graphs with cycles, drft uses SCC contraction: all nodes in a cycle are assigned the same depth (the depth of their contracted super-node in the condensation DAG) and marked `in_cycle: true`.

## Why it matters for knowledge systems

In systems with intentional layering — like research → observations → design → acceptance criteria — depth reveals whether documents follow the intended hierarchy:

- **Correct layering.** Depth 0 documents are entry points. Depth 1 documents are one step removed. Each layer cites only the layer below it.
- **Layer violations.** A document at depth 0 linking directly to something at depth 3 "skips" intermediate layers, suggesting a structural shortcut.
- **Upward links.** A document at depth 2 linking to something at depth 0 reverses the flow, pointing "up" the hierarchy.
- **Cycle entanglement.** Nodes flagged `in_cycle` don't have a clean depth — they form a mutual dependency cluster.

## What drft surfaces

### As an analysis (`drft report`)

```bash
drft report depth
```

```
=== depth ===
depth 0: index.md
depth 1: setup.md, overview.md
depth 2: details/install.md
depth 1 (cyclic): a.md, b.md
```

JSON output:

```json
{
  "depth": {
    "max_depth": 2,
    "nodes": [
      { "node": "index.md", "depth": 0, "in_cycle": false },
      { "node": "overview.md", "depth": 1, "in_cycle": false },
      { "node": "setup.md", "depth": 1, "in_cycle": false },
      { "node": "a.md", "depth": 1, "in_cycle": true },
      { "node": "b.md", "depth": 1, "in_cycle": true },
      { "node": "details/install.md", "depth": 2, "in_cycle": false }
    ]
  }
}
```

### As a rule (`drft check`)

The `layer-violation` rule flags two kinds of issues:

- **Skip-layer link:** An edge from depth D to depth D+K where K > 1.
- **Upward link:** An edge from depth D to depth D' where D' < D.

Edges involving cyclic nodes are skipped (their depth is approximate).

```
warn[layer-violation]: a.md → c.md (skip-layer link (depth 0 → depth 2))
```

Enable it in `drft.toml`:

```toml
[rules]
layer-violation = "warn"
```

## Algorithm

1. Run the SCC analysis to identify cycles.
2. Contract each non-trivial SCC into a single super-node, producing a DAG.
3. BFS from all roots (super-nodes with in-degree 0), assigning each the maximum depth across all incoming paths.
4. Expand back: all members of a super-node get its depth and `in_cycle: true`.

Complexity is O(V + E) for the SCC analysis plus O(V + E) for the BFS.
