The Shape Problem
Read14 min · Map → Contract → Route → Verify · Updated 2026-09-16
You end this lesson with: A dependency map of one real multi-step agent task you run today, with every arrow labeled real or assumed.
Chapters
- Sequence is not dependency01
- Where the habit comes from02
- Faded case03
- Open case04
- What this course builds05
- Key takeaways06
Lecture 01. The Shape Problem
A vendor-contract review job kicks off at nine in the morning. Forty contracts landed overnight. The agent opens contract one, extracts the liability clause, extracts the termination clause, extracts the data-handling clause, checks all three against policy, writes a risk note, then opens contract two and does the same thing again. Forty times.
By half past ten it's done. Nothing in that run was slow. Every individual step took a few seconds. But contract seventeen never depended on contract sixteen's output, and contract two never depended on contract one's. The agent processed forty independent documents as if each one had to wait for the last, because that's the order they were written in the task list, and sequence in a task list reads as sequence in execution unless someone actively decides otherwise.
Illustrative composite. The ninety-minute figure and the forty-contract batch are a worked example for this course, not a measurement from a real company. Treat the numbers as a teaching device, not a benchmark.
That is not a slow-model problem and it is not a bad-prompt problem. It is the shape of the work, and the shape is the part almost nobody designs on purpose. Most people write a task as a list, the agent runs the list top to bottom, and the resulting run time is however long the list takes to read aloud, multiplied by however long each step takes to think through. Nobody decided that. It just happened, because a list is the easiest shape to write and the hardest one to notice you've defaulted into.
Sequence is not dependency
Here is the entire idea this course is built on: an edge in a workflow should mean one thing, the next step reads what the last step produced. If it doesn't read it, the edge is imaginary, and every imaginary edge is wall-clock time you're paying for that bought you nothing.
An edge is a claim, not decoration. The moment you can't name what it claims — what the next step actually reads from the last one — delete it.
State it as a rule you can run against your own task list: keep two steps sequential when the second one reads something the first one wrote; otherwise run them in parallel. The "reads" half isn't a guess — check what the second step's own input actually names, then ask whether that input existed before the first step ran or came out of it.
| Condition on the next step's actual input | Edge type | What to do |
|---|---|---|
| Names something the previous step produced | Real | Keep the two steps sequential |
| Names only things that already existed before the previous step ran | Habit | Run the two steps in parallel |
| Names something several earlier steps produced | Real, fan-in | Join at that step; don't chain the earlier ones |
Decide now: contract sixteen finishes. Contract seventeen starts next, right after it, same as every pair before it. Before reading on, decide — does contract seventeen's extraction step read anything contract sixteen's step produced?
Look again at the contract batch. Extracting contract seventeen's clauses doesn't need contract sixteen's clauses. Checking contract two against policy doesn't need contract one's risk note. The only real dependency inside one contract's review is: extract before check (you can't check a clause you haven't pulled out yet), and check before the risk note (you can't summarize a verdict you haven't reached). That's two real edges, and they're the same two edges for every one of the forty contracts:
extract reads: contract text writes: three clauses
check reads: three clauses writes: risk verdict
note reads: risk verdict writes: risk note
Everything else (waiting for contract one to fully finish before starting contract two) is a fake edge, inherited from the order the contracts happened to be listed in.
Redraw it honestly and the shape changes completely:
Chained (what actually ran):
contract-1 → contract-2 → contract-3 → ... → contract-40 → batch-report
Real dependencies (what's actually true):
contract-1 ─┐
contract-2 ─┤
contract-3 ─┼─→ batch-report
... │
contract-40 ─┘
Forty independent branches that all feed one place at the end. That's not a redesign. It's the same work, drawn accurately instead of drawn out of habit. The chain was never a decision. It was the default shape of a task list nobody looked at twice.
The rejected option here — leaving all forty contracts chained — pays the full ninety minutes from the opening scenario for dependencies that were never there. The redrawn shape pays for only the slowest single contract review, not the sum of forty. That gap, not any change in what gets checked or how carefully, is the entire cost of the habit.
Drawn as a diagram instead of ASCII, the corrected shape looks like this:
Every contract branch is independent. The report is the one node that legitimately needs all of them at once — nothing here waits on a neighbor to finish first.
Where the habit comes from
Three habits create fake edges without anyone choosing them:
- Task lists read top to bottom. Writing "extract clauses, check policy, write risk note" for one contract and then writing it again for the next contract, one after another, is the most natural way to describe forty repeated jobs in prose. Prose defaults to sequence even when the underlying work doesn't.
- One agent, one context window. A single agent working through a list has no reason to notice that step 12 and step 13 are unrelated. It just does the next thing in front of it. Nothing in a linear execution model surfaces the question "did I actually need to wait?"
- Sequential is the safe-looking choice. It feels careful. Doing things "one at a time" reads as diligence, even when the one-at-a-time-ness is buying nothing but slowness.
None of these are wrong reasons to write a first draft. They're wrong reasons to leave the draft unexamined. The fix this course teaches isn't "add parallelism everywhere": a chain that's genuinely a chain (extract, then check, then summarize, for one contract) should stay a chain. The fix is: look at every edge and ask whether it's earned.
Faded case
Skip to the open case if this is familiar. A separate team runs a Friday batch: twenty-five vendor invoices, each one extracted for line items, matched against its purchase order, flagged for mismatches, then logged. The runbook lists the twenty-five invoices one after another, and the batch job runs them in exactly that order, invoice one through invoice twenty-five, each one waiting for the last to finish before it starts. Within one invoice, extract has to run before match — match reads the line items extract produced, a real edge. Across invoices, look at what invoice nine's extract step actually takes as input: the ninth invoice's own text, nothing invoice eight wrote. Decide what to do with the invoice-to-invoice edges before reading the check fence.
Open case
Run the same test against the task you map in the exercises below: for two steps that currently run one after another, check what the second one's input actually names before deciding whether the edge between them is real.
What this course builds
Across ten lectures and two projects, you'll take one running example (the contract-review batch above) through the full design process:
- Separate real edges from habit edges (Lecture 02), then write a contract for every node so the graph can route on its output instead of guessing (Lecture 03).
- Classify the result into four repeatable shapes (Lecture 04), and decide when a fan-out actually needs a join at the end, and when it doesn't (Lecture 05).
- Split what a model is allowed to judge from what the graph is allowed to decide (Lecture 06), and add a verifier that catches bad output before it moves downstream (Lecture 07).
- Give the whole thing durable state so a crash mid-batch doesn't mean starting over (Lecture 08), and price the shape you drew before you run it for real (Lecture 09).
- Learn when a graph is the wrong tool entirely, and see where graph engineering sits among the other layers of building with agents (Lecture 10).
Then two projects: build a real fan/join graph on a task of your own, then harden it with a verifier and durable state.
This course builds every one of those ideas around one running example, the contract-review batch above, carried through end to end.
Key takeaways
- An edge is a claim, not decoration. If it doesn't mean "the next step reads this," it's not a dependency. It's an accident of how the task got written down.
- Sequence in a task list is not sequence in the work. Three habits (top-to-bottom prose, single-context execution, and sequential-feels-safe) quietly turn independent work into a chain nobody chose.
- The fix is auditing edges, not adding parallelism everywhere. A real chain should stay a chain. The goal is an honest graph, not a maximally parallel one.
- This is a design discipline, not a framework choice. Nothing in this course depends on a specific orchestration library: the ideas apply whether you wire them by hand or with an off-the-shelf graph engine.
What You Have Now
A dependency map of one real multi-step agent task you run today, with every arrow labeled real or assumed. It's the first entry in the design document this course builds toward — a plain list of steps with each arrow marked, nothing fancier yet. It opens the Map stage of this course's Map → Contract → Route → Verify loop, the stage every later lecture assumes is already honest.
Save it as graph/lecture-01.md; the lab's checker looks for that file at that path.
Exercises
- Draw your real batch. Pick one recurring multi-step task you run today: a review pipeline, a research task, a multi-file refactor. List every step in the order you currently run them, then mark each arrow "real" (the next step reads the last one's output) or "habit" (it just runs next). Count how many arrows survive.
- Find the smallest independent unit. In that same task, find the smallest piece of work that repeats without depending on its siblings: one contract, one file, one search query. That unit is the thing you'll learn to fan out over the rest of this course.
Check your understanding
Reading the free lecture? Create a free account to track progress and unlock the review system.