Our delivery train does not wait for review
How our agent delivery train keeps work moving while code review runs: parallel lanes on separate files, review as a queue, and a failed review as a new task rather than a blocked lane.
Development track
Most software teams know the pattern. Work finishes, a pull request opens, and then the work waits: for a reviewer to find time, for automated checks to run, for someone to come back with comments. The author waits with it, because starting the next thing feels like abandoning the first. Our delivery train is a pipeline in which agents design, build, review, and verify software changes, working through a queue of tasks. Agents do not get bored, but they burn time and money while they sit idle, and a pipeline that waits at every review produces its output in a stop-start rhythm that has little to do with how fast the work itself gets done.
This post describes the rule we run instead, and the incident that made us fix its weakest point.
What happened
Our train ran the conventional way at first. A lane, which is one agent work stream carrying one task from start to a pull request, would finish its task, open the pull request, and wait. Review and automated checks ran in their own time. The lane had nothing else assigned, because the next task was supposed to follow the verdict on this one.
One of our products ran with a single lane. That made the arithmetic plain. While its one lane waited on a review, the product had zero work in progress. Every review delay, every slow check, every request for changes became a full stop for the whole product. We flagged the single lane openly as a stall risk, in writing, and then for a while we lived with it anyway. Naming a stall and removing it turned out to be two different decisions.
The timeline
The change ran as follows:
The same timeline in text form:
- Before October 2026: the train's doctrine is written down: lanes and asynchronous review, review catches up on the pull request, no force-merges.
- October 2026, before the fix: one product still runs a single lane and is flagged as a stall risk.
- October 21, 2026: the lane limit for that product is raised from one lane to two, and the change is verified live in the running dispatcher.
What was actually wrong
The waiting was self-imposed. Review protects quality at the point where a change is proposed for merging. Nothing about that protection requires the author of the change to stop working while it happens. We had coupled two things that only looked connected: the state of one pull request, and the availability of the agent that wrote it.
There was a second coupling underneath. When a review failed, the original work resumed as the same blocked item, at the front of everything. A failed review is information about a specific change. Treating it as a stop sign for a whole lane turned a small, bounded problem, one change that needs rework, into a scheduling event for the entire queue.
We should admit one gap in our own record here. We did not keep a clean count of the hours the train lost to waiting before we changed the rule. The stall was visible in the queue, work sat unstarted while finished work sat unreviewed, but nobody measured the idle time as a number. A post that invented a tidy figure for that loss would read better and be worth less. The fix below is structural, and it stands on the scheduling logic rather than on a loss figure we cannot back up.
What we changed
The train now runs up to two lanes at once on a train, under three rules.
Lane two starts while lane one is in review. When a lane opens a pull request, that pull request goes into review and the lane's task is done for scheduling purposes. The next task in the queue starts on the other lane. The constraint that makes this safe is file separation: concurrent lanes work on tasks that touch separate files, so two agents are never editing the same code at the same time and manufacturing conflicts for the review to sort out.
Review is a queue, and it catches up on the pull request. Reviewers, human or agent, work the review queue in their own order. A review that asks for changes does not recall a lane or block one. The requested rework becomes a new task in the queue, sized and scheduled like any other task. The lane system never has to decide whether rework is urgent enough to interrupt something; it enters the same queue everything else enters.
Nobody force-merges, and red checks stop a merge cold. Keeping work moving applies to starting work, never to landing it carelessly. A pull request with failing checks does not merge. What changed is only where agents spend the waiting time: on the next task instead of in front of a pending verdict.
The two models, side by side:
The same comparison in text form:
- What does an agent do while its pull request is in review? Waiting model: waits for the verdict. Lane model: starts the next queued task on the other lane.
- What does a failed review do? Waiting model: blocks the lane and resumes the same item ahead of everything. Lane model: becomes a new task in the queue.
- How many tasks are in progress while a review is pending? Waiting model: one, and it is the one waiting. Lane model: up to two lanes of new work, plus the review itself.
- What can override a failing check? Waiting model: nothing. Lane model: nothing: no force-merge, ever.
Figure 1. Concurrent work lanes for the product that ran a single lane. Look at the left bar: with one lane, a review wait leaves zero other work in progress for that product. Raising the limit to two lanes is a small change with a structural effect.
The same numbers as a list:
- Before the October 21, 2026 change: 1 concurrent lane.
- After: 2 concurrent lanes.
What it cost
The cost of the lane model is coordination, and it is paid in the queue rather than in idle time. Tasks have to be specified so that their file boundaries are known before a lane starts, because two lanes on overlapping files would recreate the conflicts the model exists to avoid. That pushes real work upstream, into how tasks are written. A vague task that a single waiting lane could muddle through becomes a problem when it blocks lane assignment, so task writing got more exact, and occasionally slower, even as delivery got faster.
Review also has to be staffed as a queue rather than as an interruption. If review capacity falls behind lane output for long, pull requests pile up, and the pile is the same stall wearing different clothes. The lane rule does not create review capacity. It makes a review backlog visible as a backlog, measured in unreviewed pull requests, instead of hiding it inside agent idle time.
What we take from it
Waiting felt like diligence. An author sitting with a pull request looks attentive, and a pipeline that pauses for every verdict looks careful. The care is real only at one point, the merge decision, and we kept that point strict: failing checks stop a merge, and no one overrides them. Everywhere else, the pause was a scheduling habit carried over from how human authors protect their own attention, applied to agents that do not need the protection.
If you run more than one agent, the transferable version is small. Separate the verdict on finished work from the availability of the worker. Give the next task its own lane and its own files. Let a failed review re-enter as work, because that is what it is. Then watch the queue. The stall does not disappear from a system like this; it moves to wherever capacity is actually short, and at least then it is standing somewhere you can see it.