We Approved a 5-Node Plan. The Trace Showed 40 Agent Calls.
Day 7: The Decomposition Nobody Signed Off On
Here's a number that should bother you: an engineer on my team approved a 5-node plan. The trace for that run shows 40 agent invocations. Not a bug, not a runaway loop — just a subagent doing, quietly and without asking, exactly what the orchestrator did at the top. Every cost estimate you've made, every plan you've signed off on, assumes decomposition happens once, up front, before anything executes. It doesn't. It happens again inside the subagents, and that gap is why your bill and your failure modes stop matching your diagram.
The trace that didn't match the plan
Take a recent PhoenixDX run. The plan the engineer signed off on was a clean 5-node DAG: spec, scaffold, implement auth middleware, tests, review. Nothing exotic. It went to the orchestrator, and the execution log came back with over 40 agent invocations. Here's the part that matters, pulled straight from the trace around the 'implement auth middleware' node:
[orchestrator] plan: 5 nodes (spec, scaffold, implement_auth_middleware, tests, review)
[dispatch] implement_auth_middleware -> subagent#7
[subagent#7] context_pressure: task_tokens=18400 > budget=8000
[subagent#7] re-decompose: implement_auth_middleware ->
[jwt_validation, session_store, rate_limit_hook,
error_handler, middleware_wiring, config_loader]
[subagent#7] dispatch child -> subagent#7.1 (jwt_validation)
[subagent#7] dispatch child -> subagent#7.2 (session_store)
[subagent#7] dispatch child -> subagent#7.3 (rate_limit_hook)
[subagent#7] dispatch child -> subagent#7.4 (error_handler)
[subagent#7] dispatch child -> subagent#7.5 (middleware_wiring)
[subagent#7] dispatch child -> subagent#7.6 (config_loader)
[subagent#7.2] context_pressure: further split -> [schema_check, migration_draft]
[orchestrator] node implement_auth_middleware: complete (output received)One node on the approved plan. Six child agents underneath it, and one of those splits again. The orchestrator's log has a single line for the whole thing — 'complete, output received.' The fork never shows up on the plan side. As far as the orchestrator is concerned, nothing happened.
The assumption everyone makes
I made this exact assumption, before I sat down with raw traces instead of summaries. Decomposition is the orchestrator's job, and it's a planning-phase job: you write the prompt, the orchestrator thinks, out comes a DAG, you review it, it dispatches nodes, subagents execute. One split, upstream, and everything downstream is just execution. That model is what your cost estimates run on, what your approval workflows run on, what every 'let me look at the plan before we run it' ritual is built on. And it falls apart in exactly the case you care about most — the case where a node turns out to be bigger than it looked when you approved it.
What actually happens inside a subagent under context pressure
A subagent gets handed one node: 'implement auth middleware.' It starts working the task in its own context window. Partway through, it hits a wall — the task plus the code it's read plus the tool output it's accumulated no longer fits in one context pass. There's no protocol that says 'escalate back to the orchestrator.' There's a protocol that says 'keep going.' So it does the only thing it knows how to do: split its own assigned task into sub-tasks and spawn agent or tool calls to work through them. It doesn't fail, and it doesn't ask permission. It's the exact same reasoning capability the orchestrator used to build the top-level plan, running one level down, with zero line of communication back up to the plan that dispatched it.
- ▹The orchestrator planned on the assumption that a node equals one unit of work for one subagent pass.
- ▹Mid-execution, the subagent discovers the node doesn't fit — and re-plans locally, using the same LLM call that handles everything else.
- ▹That local re-plan never reaches the orchestrator's plan representation. It only exists inside the subagent's own trace.
- ▹It can recurse more than one level deep — session_store forked again into schema_check and migration_draft.
Why this stays invisible unless you go looking
The orchestrator's plan representation only has room for the nodes it authored. It dispatches 'implement_auth_middleware' to a subagent and waits for a return value. Whatever happens inside — how many times the subagent calls itself, how many tokens it burns re-planning — collapses into one edge in the orchestrator's view: dispatched, complete. Nothing in the architecture is asking the question 'did the plan I approved match what actually ran,' so nothing reconciles your DAG-shaped plan against your tree-shaped actual cost. You have to go to the raw span log — not the plan object, not the summary — to see that one node quietly became seven agent calls.
The cost isn't just tokens — it's a failure mode
Yes, unplanned recursion burns tokens you didn't budget for. That's the boring half of the problem. Here's the half that should actually worry you: when a subagent re-splits its task, it derives the sub-tasks from whatever context it's currently holding — not from the constraints the orchestrator attached to the parent node. Say 'implement auth middleware' carried a constraint like 'reuse the existing session store, do not introduce a new one,' or 'rate limiting must go through the shared Redis client.' That constraint lived on the parent node, in the plan. It doesn't automatically travel to six freshly spawned children three levels removed from the object that held it. The constraint that justified the split in the first place is exactly the thing most likely to vanish in the re-split. And when it breaks, it doesn't break where you'd look — it shows up in session_store's migration_draft child, three hops from the node you actually reviewed.
What to instrument tomorrow
- ▹Log subagent-internal call counts against the planned node count. A ratio like 'planned:1, actual:7' on one node is the signal that decomposition happened twice.
- ▹Treat every subagent as a potential re-planner, not a leaf executor. Give it the same constraints and budget context you'd give the orchestrator — the invariants, not a stripped-down one-liner — because it may end up doing the orchestrator's job without telling anyone.
- ▹Propagate constraints as structured data attached to the task, not as prose the first-level subagent is trusted to remember and pass down.
- ▹Add a trace view that renders the actual execution tree next to the approved DAG. If you can't put the two side by side, you can't catch the drift.
The reframe for Day 8
If subagents are going to re-decompose under pressure no matter what you designed, 'how do I split this task well' is only half the question. The half most teams skip: what decomposition am I willing to let happen without seeing it? That's tomorrow — designing for the re-planning you can't observe, instead of pretending it won't happen.
Extend your knowledge
- ▹Pull the raw trace/span log from your own orchestrator framework (LangGraph, your custom harness, whatever you run) for one real task and count actual agent invocations against planned DAG nodes — do this before reading Day 8.
- ▹If you use Claude Agent SDK or similar, check whether your subagent invocations carry the parent task's constraints as structured context or only as a prose instruction — that's the exact seam where drops happen.
- ▹Read Anthropic's engineering writeup on building their multi-agent research system for how they talk about subagent tool-call budgets and context handoff — it's the clearest public discussion of this exact seam.
- ▹Set up a side-by-side view (even a simple diff of node-count vs. call-count per run) as a standing check before Day 8, which builds directly on this instrumentation.
Discussion
Chat with Chi Cong (AI) about this article. Your conversation is private to you — you can publish a summary for others when you're done.