Full page · 01 · Moat

Controller chains:
the decisions guarding every call.

A call graph shows who calls whom. Controller chains show the decisions guarding every call: the enclosing control structures from the call site inward — conditions, polarity, branches, iteration ranges — plus the callers above whose guards reach down to you.

Core

Call graph with controller awareness. Each chain runs from a call site inward through every enclosing if, for, try, and match, recording the condition, which arm was taken, and the branch or recovery arm around it. Direction down covers the function's own decision path; direction up covers the callers' guards.

Live example

$ controller_chain({ "function": "handle_controller_chain_disk",
    "file": "src/daemon.rs", "include_callers": true })
{
  "chain_budget_bytes": 24576,
  "emitted_chains": 38,
  "freshness": {...},
  "line_ref": "working_tree",
  "marker": "... [truncated, 124256 bytes]",
  "omitted_bytes": 124256,
  "omitted_chains": 22,
  "summary": {"chains": 60, "down_chains": 56, "per_chain_levels": [1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 1, 1, 0, 2, 2, 0, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 5, 3, 2], "total_levels": 75, "up_chains": 4},
  "truncated": true
}
[...]

One real emitted chain level — same object shape — from a second call with source text included:

$ controller_chain({ "function": "sorted_manifest_and_hash",
    "file": "src/db/mod.rs", "include_source": true })
{"branch": "body", "caught_exceptions": [], "condition": null, "end_line": 165, "is_negated": false, "iteration_max": null, "iteration_min": null, "iteration_range": null, "level": 0, "polarity": "positive", "scope_depth": 1, "source_text": "for r in &sorted {\n        hasher.update(r.file_path.as_bytes());\n        hasher.update([0u8]);\n        hasher.update(r.content_hash.as_bytes());\n        hasher.update([0u8]);\n    }", "start_line": 160, "type": "for"}

The full response is truncated at the 24576-byte budget; [...] and the marker field count what was cut — never silently dropped.

Real MCP tool output — verbatim excerpt. Top-level fields and the summary object are byte-identical to the live response; [...] on its own line marks where emitted chains were cut, and the freshness block is collapsed to {...}. The single chain level shown second is a real emitted level, so the level shape (condition, polarity, branch, scope) is real, not described. Captured live against the DesignGraph codebase.

API surface

Tool
controller_chain
Parameters
function (required), file (required), include_callers, include_source, max_bytes
Returns
Chains with per-level condition, polarity, branch, iteration range, and source text; a summary with chain counts and the truncation status

Use cases

Honesty: the response envelope always reports truncation explicitly — omitted chains and bytes are counted, never silently dropped.