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
- New codebase on-ramp: no accumulated intent yet — the structural decision-path lens works immediately.
- Bug investigation: start here to see which guard arm actually fired and which recovery arm sits beside it.
- Review: confirm a change handles every arm, not just the one the author tested.
Honesty: the response envelope always reports truncation explicitly — omitted chains and bytes are counted, never silently dropped.