Being a Bottleneck
In my last post I talked about automation and how I’ve been reconciling with how work gets done as a developer. The takeaway was that automation is helpful as long as the work is visible and chunked in a way that makes it easily digestible. With the way AI agents work, it becomes eerily similar to the brooms carrying buckets of water: task-oriented, efficient, and eager. Suddenly you’re faced with a huge amount of work in progress (WIP) slowly building up for you to verify. Again referencing The Goal, we find that mountains of work build up in front of bottlenecks. Yes, unfortunately, you are the bottleneck when it comes to AI and that is okay. In fact, it’s really important. Why?
Well, let’s do a thought experiment in which we remove ourselves entirely from the development process. Imagine a scenario with no guards at all: no tests, no documentation, no task breakdown. Just an AI agent and a dream. You type in the application you want and poof, there it is. It may work, it may not. We ask the AI to test it, the agent verifies it worked or that it failed, and we cycle through revisions. Eventually, we can imagine it will be “right.” Depending on complexity, though, those cycles may be long and slow or riddled with bugs. Over time we’ll want to add features, the hallmark of all large applications. So we add testing and linting to our pipeline. Maybe that eases the churn, but we are still out of the loop. We ask our AI system to maintain the tests, handle linting, and even manage deployment. Taking it a step further, it can QA and do nearly everything for us.
As soon as you sit down to use it, though, you will inevitably find something wrong. Not because of the AI, necessarily, but because you didn’t describe something correctly, or changed your mind once confronted with it. Eric Ries in The Lean Startup talks about getting fast feedback from customers; in this case, you are the customer of the AI. You should have been in the loop earlier. Your early intervention would have prevented hitting LLM context limits, reduced the overall cost of building, and, most importantly, caught the misunderstanding before it infected everything downstream. Let’s come back now to the idea of you being the bottleneck.
Automation has an advantage over human development in scalability and accuracy, two metrics that continue to improve over time. You, however, will most definitely not scale in the same way, so what needs to change? The Goal holds some answers here. In the Theory of Constraints, the bottleneck determines the flow of work through a system. Not all work needs to flow through the bottleneck; only the work that requires human judgment does. Automation can build up a pile in front of a bottleneck precisely because it can generate more code than a person can review. Defects can still occur, so having a quality process around each stage makes sense to protect the bottleneck’s time from being spent on work a machine could have caught. This is known as protecting the constraint. You can also expand constraint capacity; in a team setting, that means adding more reviewers. But before we get there, let’s talk about the mechanism that makes all of this work.
Drum, Buffer, Rope
Goldratt introduces a scheduling method in The Goal called Drum-Buffer-Rope, a deceptively simple framework that, once you see it, you start recognizing everywhere.
The drum is the constraint. It beats, and everything else marches to its rhythm. In a factory, it’s the slowest machine on the line. In AI-assisted development, it’s you: your review capacity, your judgment, your time. The drum doesn’t speed up just because you want it to. The goal is not to make the drum faster; it’s to make sure the drum is never stopped waiting for work, and never swamped by more than it can absorb.
The buffer sits directly in front of the drum. It’s a protective queue designed to absorb variability from upstream. When something upstream runs slow or produces defective output, the buffer takes the hit, and the drum keeps working. In software, the buffer is your automated quality gates: tests, linting, static analysis, PR checks. Their job is not to slow things down. Their job is to ensure that nothing defective ever reaches the drum. When a test fails before the work reaches you, that’s the buffer doing exactly what it was built to do.
The rope is the signal that ties the release of new work into the system to the drum’s pace. You only start new work upstream at the rate the constraint can process it downstream. Without the rope, the buffer fills up regardless of your quality gates, and you’re back to a mountain of WIP building up in front of the bottleneck. In practice, the rope is task discipline: you don’t hand the AI a new feature until you’ve reviewed the last one. A ticket is a unit of rope. The size of your sprint is the length of the rope.
Together, drum-buffer-rope is a way of saying: build the system around the constraint, not around the tools. AI is fast. Tests run automatically. Pipelines execute without asking permission. But none of that speed matters if the work backs up at the one place that requires human judgment. The right design amplifies the drum, protects it from waste, and synchronizes everything else to it.
The Line Supervisor
In my last post, I described the ideal development environment as a factory floor: automation handling the repetitive, measurable work, with humans watching the line, catching what the sensors miss, and making the calls that require judgment. Shipping Go uses the CI pipeline as a conveyor belt: code moves through a series of stations in sequence, each one adding verification before the next. The question I’ve been sitting with since writing that is: what does a developer’s role actually look like when the line is running well?
Frederick Winslow Taylor spent his career arguing that the goal of process improvement isn’t to extract more work from people; it’s to replace repeatable, variation-prone tasks with standardized methods, freeing human judgment for the work where it actually creates value. I’ve thought about this framing a lot while working on a project that required building a multi-stage automated pipeline: each stage takes a well-defined input, applies deterministic transformation (with AI assisting at the bounded, structured moments where it’s genuinely useful), and produces a well-defined output for the next stage to consume. At each handoff, a human reviews what was produced, not to verify every line, but to confirm that the output matches the intent, and to catch the things no generator can catch: the design smell, the missing edge case, the scope creep buried in the implementation.
The insight is that AI is most effective when it operates inside a bounded, structured stage, not when it’s handed an open-ended problem and left to interpret it freely. The core of such a pipeline can be deterministic and auditable. AI helps at the seams. And at every stage boundary, there is a human. Not as a bottleneck to be minimized, but as the drum.
This is the shift I think developers need to make: from writing and testing to reviewing and guiding. It isn’t a demotion. It’s what happens when the line is working. The engineer doesn’t disappear when automation handles the repetitive work; they move to where their judgment is actually scarce and actually matters. On a production line, the most skilled workers aren’t the ones threading bolts. They’re the ones who can look at the line, see that something is subtly wrong, and know exactly where to intervene.
A Pipeline with Humans in the Loop
Here is what I’ve been running in my own projects, framed as a prescription: a four-stage development pipeline where a human is the required decision-maker at each transition. I introduced this experimentally; I’m pitching it as a pattern.
Stage 1: Design. You write the design. Not a vague prompt: a real document: what you’re building, why, what success looks like, what constraints apply. Then you hand it to AI for enhancement. Not execution: enhancement. The AI suggests alternatives, surfaces edge cases you didn’t consider, proposes structure. You review what comes back. You decide what to keep, what to discard, what to clarify. Nothing proceeds until you have approved a design you can actually stand behind. This stage has the highest leverage of any in the pipeline: errors caught here cost almost nothing. Errors caught in production cost everything.
Stage 2: Task Breakdown. You hand the approved design to AI and ask it to decompose it into discrete, composable tasks (tickets, in the traditional sense), but sized and ordered by something that has read your entire design document and understands the dependencies. You review the resulting list. Is the ordering right? Are any tasks underspecified? Are there edge cases that didn’t make it into the list? You approve the task breakdown before a single line of code is written. This is the rope in action: you’re controlling how much enters the system, at the rate you can absorb it.
Stage 3: Implementation. AI completes tasks. As each one finishes, automated tests run: unit tests, integration tests, linting. The layered testing pyramid that Shipping Go describes as the backbone of any trustworthy pipeline. Work does not advance to review until it is green. Not “mostly green.” Green. The buffer is protecting the drum: defective work is caught here and cycled back, not forwarded to your review queue. Every failed test is the system working as designed.
Stage 4: Review. You review green work. This is not rubber-stamping; it is the most skilled work in the pipeline. You’re looking for things that tests cannot look for: whether the implementation matches your design intent, whether the approach will hold up when requirements change, whether the edge cases you care about are covered in spirit and not just in letter. The PR is the formal handoff mechanism: it contains the code, the context, and the verification results. No handoff without all three. This is the 10% I mentioned in my last post: the fraction of the work that AI gets you to the edge of but cannot cross without you.
Visibility runs through all four stages. Tickets make the design concrete and reviewable. PRs make implementation changes explicit and attributable. Test results make the quality gate objective. None of these are process overhead; they are the rope. Without them, you have no signal. And without signal, the drum runs blind.
Proof in Progress
I’ve been building toward this pattern across several personal projects, and one experiment in particular has been the most clarifying: building a multi-stage automated toolchain to support a complex industry standard. The pipeline takes a structured specification as input and produces, at successive stages, documentation, client libraries, server scaffolds, and test suites, one stage per output, each consuming the previous stage’s artifacts as input.
The design principle was that each stage’s interface should be explicit. What goes in, what comes out. Any stage can be improved independently. Any stage can have a better tool dropped in without affecting the others. Barbara Liskov’s substitutability principle, that abstractions should be defined by their inputs and outputs not their internals, applies here just as cleanly as it does to object-oriented design.
AI is wired into specific stages of this pipeline, not the whole thing. At the stages where a task is well-bounded and the output is verifiable against a schema or a spec, AI dramatically accelerates the work. At the stages where determinism and auditability matter more than speed, code generation handles it without LLM involvement. The result is a pipeline that is repeatable and trustworthy at its core, with AI amplifying specific seams rather than running the whole show.
When the specification changes (the upstream “standard” that drives the whole pipeline), the pipeline runs. The OODA loop applies here at the system level: the change is observed, the affected stages are identified, the generators are triggered, and updated artifacts are published. A human reviews the delta. Not the process, not every intermediate artifact: the delta. What changed, and does it match what was intended?
Engineers who work in this kind of system are not threading bolts. They’re reviewing the specification, validating that the pipeline produced what the design called for, and writing the business logic that no generator can infer. The throughput of the line goes up. The work the engineers do becomes higher-value. And visibility at each stage makes it possible to see, at any moment, exactly where the system stands and what is waiting for judgment.
The Tools Are the Rope
The mechanisms that make this pipeline work are not new. Tickets, pull requests, automated tests: these have been part of software development for years. What changes in an AI-assisted workflow is what they’re for.
A ticket is not just a unit of work; it’s a unit of rope. When you approve a ticket for AI implementation, you’re releasing a measured amount of work into the system. Size it to what you can review in a sitting. A ticket too large is a batch size problem: it creates a traffic jam at the review stage and overwhelms the drum with context it can’t easily absorb. Small, well-scoped tickets aren’t just best practice; in a DBR system, they’re load management.
A pull request is the handoff. It’s the moment work crosses from the buffer into the drum’s queue. A PR without context is a handoff without a note; the drum has to reconstruct intent from code, which is slow and error-prone. A PR without passing tests is a handoff of defective work; the buffer failed. A good PR contains three things: what changed, why, and evidence that the automated quality gates agreed. Missing any one of those makes the drum’s job harder.
Automated tests are the buffer. This is the frame Shipping Go describes in terms of the testing pyramid: many fast unit tests at the base, fewer integration tests in the middle, fewest end-to-end tests at the top. The pyramid isn’t shaped that way for aesthetic reasons; it’s shaped that way because the drum can’t wait for slow tests on every commit, but also can’t trust results that only came from fast ones. The layering is the architecture of a buffer: cheap and fast at high volume, slower and deeper only when needed.
All of it exists to make work visible. The prerequisite for drum-buffer-rope to work in any system is that the drum can see what’s in the buffer and what’s waiting upstream. Without visibility, the drum can’t manage its own pace. Without visibility, the rope goes slack. Without visibility, the system falls back to what it was before: a pile of WIP in front of a person who can’t tell where anything stands.
Staying in the Room
The sorcerer’s apprentice didn’t fail because he used magic. He failed because he walked away. He set something powerful in motion, abdicated his judgment, and let it run unchecked until the room was flooded. I said this at the end of my last post, and it’s still the right note to end on here, because this post is the practical answer to the lesson.
The pipeline described above is designed to keep you in the room. Not to slow things down, but to make sure that every stage of the process has a moment where your judgment is the deciding factor before work proceeds. You’re in the room at the design stage. You’re in the room when tasks are scoped. You’re in the room when green work is ready for review. Not all day, not for every line, but at every stage transition, because that’s where the drum lives.
Being a bottleneck isn’t something to engineer away. It’s something to engineer around. The drum sets the pace. Without the drum, there is no pace, just work accumulating with no one to give it direction. The buffer and the rope exist to protect you, not to replace you. The goal is to make sure that when work reaches you, it’s worth your time, and that when you make a call, it actually moves the system forward.
Developers who embrace this shift aren’t giving up the craft. They’re practicing the most important part of it: knowing when to build, what to review, and when to trust that the line is doing its job.