<!-- generated by scripts/generate-agent-docs.ts -->

> **The Bottleneck Moves**
> Coding agents made implementation cheap, so the engineering bottleneck was supposed to move upstream into specification and architecture. Some of it did. More of it accumulated downstream, in the work of converging a plausible change into accepted behavior.
>
> Source: https://jasonstiltner.com/writing/bottleneck-moves/

---

Essay

# The Bottleneck Moves

Engineering when code becomes abundant

Autonomous Engineering · Delivery · Software Architecture · Product–Engineering

~15 min read · Published Sep 21, 2026

The observations here are my own. Production examples have been anonymized and aggregated; proprietary implementation details have been omitted. Organizational and architectural implications are hypotheses drawn from one production context, not positions of my employer.

At some point, “we’ll write this one ourselves” stopped meaning what it said.

## A note on what you cannot check

The retrospective behind this essay is a sample of twenty merged changes from a production system I work on. That repository is not mine to publish, and the underlying methodology note — sample definitions, per-change rows, calculations — is employer work product.

So every figure below is unverifiable. You cannot open the repository, re-run the gap calculation, or check that 821.9 hours becomes 71.8. You have only my word for it.

That is worth naming plainly, because the rest of this site is built on the opposite arrangement. Elsewhere here, a number is expected to carry a link to the script, notebook, results file or CI run that produced it, and [the corpus](https://jasonstiltner.com/corpus/) counts how many of them actually do. Several published claims were retracted in September 2026 for failing that test. One of them — [the orchestration write-up](https://jasonstiltner.com/projects/agentic-orchestration/) — was retracted not because it was wrong but because its backing repository was private, so the corrections cited files no reader could open. Accurate and uncheckable is its own failure, and specificity is precisely what readers use as a proxy for having checked.

This essay reproduces that shape on purpose, which is the only reason it is allowed to stand. The alternative was to round the figures off — to say “about 820 hours” rather than 821.9 — and that would have been worse: vaguer without becoming any more checkable, and quietly hiding the problem instead of stating it.

So read the numbers as what they are. They are the record of what changed my own mind, reported precisely so that the claims are at least falsifiable in principle by anyone who runs the same measurement on a codebase they do have. They are not evidence you can audit, and nothing in this piece should be weighted as though they were.

## Both paths are synthetic

There are two engineers on the team I work on. When one of us says we’ll write it ourselves now, we usually mean that we will sit with an interactive coding agent and drive an implementation rather than assign the task to a queued autonomous engineering system. Neither of us routinely authors source code directly. Both paths are synthetic; the meaningful distinction is how much human attention remains coupled to the work while it is being done.

On that team, my colleague and I own the technical architecture and the path from technical specification through verification and merge. Roughly half of our tasks can take the asynchronous route. They are not a random half. A feature confined to a well-understood part of the UI delegates well. A superficially similar feature that propagates through persistence, application services, APIs and presentation becomes a different assignment. We tend to reserve asynchronous execution for work that is well bounded, relatively reversible and limited in blast radius. More entangled work stays interactive.

My initial model was simple: if models make implementation cheap, the engineering bottleneck moves upstream. Specification and architecture become the scarce work.

That does happen.

But it is not where the story ends.

We also spend surprising amounts of time on the far side of implementation: restoring mergeability, waiting on CI, reviewing synthetic critique, directing corrections, validating those corrections, reconciling concurrently changing state, and deciding when the evidence is sufficient to ship.

The middle of the process has compressed.Pressure has accumulated on both sides of it.

This broad shift is becoming visible elsewhere. Microsoft’s recent work on spec-driven development begins from much the same problem: faster implementation increases the value of preserving intent, constraints, acceptance criteria and architectural context through the development lifecycle. The more interesting question for me is what happens farther along that curve, when implementation in a production codebase is already almost entirely model-mediated.

## A correct specification can still be a bad assignment

Traditional software development permits a great deal of requirements discovery to happen during implementation. An engineer encounters an ambiguity, discovers that two assumptions conflict, realizes that a seemingly small feature crosses an awkward boundary, asks a question, narrows the work and continues. Implementation is partly the process by which an incomplete statement of intent becomes technically concrete.

An autonomous agent can remove some of that productive friction. It may be perfectly capable of converting an ambiguity into code before the organization notices that an important question was never answered.

So “write better specs” is not quite enough.

I have started to think that an implementation-ready specification has at least two independent qualities.

SEMANTIC COMPLETENESS

What should become true? What should not change? Which edge cases matter? What observable evidence establishes success?

OPERATIONAL BOUNDEDNESS

What is the shape of the change we are about to set in motion? Which architectural surfaces does it reach? Does it contend for shared state? Can the assigned execution environment actually perform the verification demanded by its acceptance criteria? Is this one autonomously tractable task or several changes that merely share a product objective?

That second category occupies an uncomfortable organizational space. Product has the strongest claim on intent. Engineering knows the topology of the system. Neither side, acting only in its traditional role, necessarily has all the information needed to produce the artifact an autonomous implementation system requires.

In our own transition, that function has not mapped cleanly onto a job title. I am not convinced it should. The missing thing may be better understood as a negotiation surface.

The useful question during refinement becomes less “Is this estimated and ready for development?” and more “Is this understood and bounded well enough to allocate autonomy?”

Product does not need to become Engineering. Engineering does not need to seize product authority. But the familiar distinction — Product owns what, Engineering owns how — becomes porous at exactly the point where the shape of the what determines whether the how can proceed safely without continuous human attention.

More autonomous implementation may therefore make the Product–Engineering boundary more important, not less. Fast execution raises the price of information lost at the handoff.

That probably does not imply more meetings. It implies better-timed ones.

## The code arrives. Then what?

We recently went back through a small sample of our own delivery history to test whether our intuition survived contact with the repository.

We examined twenty recent merged changes across a backend service and web client. The sample was retrospective, small and non-random. We had already been routing work between interactive and asynchronous modes according to our judgment, so this cannot be treated as an experiment comparing agent quality.

It was still useful.

Across the twenty changes, there were 821.9 hours of elapsed time between the relevant start and merge events. As a deliberately crude proxy for queueing, we removed inter-event gaps of six hours or more.

That left 71.8 hours.

By this measure, roughly 91 percent of elapsed time lived in long gaps.

The wording matters. I do not know that those hours were literally idle. Engineers worked on other things. Nights happened. Reviewers were occupied. The measure describes the shape of the delivery timeline, not how people spent every minute.

But that is precisely what makes it interesting.

Once candidate implementation becomes cheap, wall-clock lead time can mostly describe the system surrounding implementation rather than the act that produced it.

The sample was almost bimodal. Eight changes completed without a six-hour gap. Twelve spent between 64 and 98 percent of their elapsed time in long gaps.

Interactive changes had a median elapsed time of 1.7 hours. Asynchronously delegated changes had a median of 19.9 hours. After removing the long gaps, those medians became 1.7 and 4.8 hours respectively.

This does not establish that the queued system writes worse code. The allocation of tasks was not random, and the execution modes have different scheduling characteristics. It establishes something more prosaic and more useful:

Round trips are expensive.

An agent pushes a change. Review arrives. The agent corrects it quickly. CI runs. Another finding appears. Another correction follows. None of those individual operations need be difficult. But when a five-minute correction requires another asynchronous review boundary, and that boundary crosses a night, a trivial correction can add half a day to delivery.

At that point, making code generation another ten percent faster is almost irrelevant.

### What the sample got wrong about my assumptions

The retrospective also challenged one of my assumptions. I expected architectural fan-out to strongly predict convergence difficulty. It did not.

Some of the widest changes in the sample touched thirteen or fourteen identifiable surfaces and still converged in about an hour when handled interactively. Much smaller changes could spend days working through repeated asynchronous review and correction cycles. Breadth alone was weak.

Other properties were more revealing.

Changes touching serialized resources — migration chains, lockfiles, other globally ordered artifacts — became expensive when multiple streams of work reached the same resource concurrently. The implementation could be straightforward; the shared artifact still admitted only one coherent next state.

Another class of task had a different structural defect. An agent could implement the requested behavior but could not independently verify an acceptance criterion requiring credentials or privileged access it did not possess. No improvement in coding ability could close that loop. The task had been assigned to an execution environment structurally incapable of proving its own completion.

Then there were deceptively tiny changes. In two examples, fewer than ten production lines generated more than two hundred lines of tests. The implementation was nearly trivial. The actual intellectual work was specifying what an invariant meant across the relevant state space.

The apparent size of a change and the size of its proof obligation can diverge radically.

Generated tests do not solve that problem by themselves. Models can produce verification code just as easily as implementation code. The scarce judgment is deciding what must actually be demonstrated.

We have encountered the inverse failure too. In one evaluation exercise, a sophisticated automated harness executed repeatably and produced convincing-looking results. Changes to the application that should have affected those results did not.

That invariance was the clue. The harness was testing the wrong system.

An evaluation can be automated, reproducible and invalid. Once verification machinery becomes cheap to generate, verification itself has to be verified. I have written about a version of this problem [elsewhere](https://jasonstiltner.com/writing/when-production-disagrees/), from the direction of what production failures should teach an architecture.

This is why I no longer describe the downstream constraint simply as testing or review. The larger problem is convergence: the work required to transform a plausible candidate implementation into accepted behavior in one coherent production system.

## Convergence has topology

What surprised me most was that some convergence costs were visible before implementation began.

If several planned changes will all advance the same ordered migration chain, the contention exists in the plan. If an acceptance criterion requires a capability the executor does not have, the inability to close the loop exists in the ticket. If a requirement enumerates many independent behavioral assertions, the eventual proof obligation is at least partly visible before a test has been written.

Implementation exposes these properties. It does not create them.

A change therefore carries something like a convergence topology. Some paths can proceed independently. Some pass through serialized resources. Some require human decisions. Some require privileged environmental capabilities. Some are likely to create multiple review boundaries. Some become meaningful only after another change lands.

This gives me a more useful picture of autonomous engineering than the claim that the bottleneck moves upstream. The system can be massively parallel until it encounters something that is not.

The engineering problem becomes partly one of identifying where abundant implementation is forced back through serial technical, organizational or human convergence points.

### This matters for architecture

Chris Richardson has recently made a strong case that coding agents can make microservices more attractive: smaller bounded working sets constrain blast radius, while independent delivery pipelines can safely absorb more parallel change. That is a serious argument.

DORA supplies an important qualification. The value of a service boundary depends heavily on genuine independence: the ability to change, test and deploy without fine-grained coordination or lock-step release. Its guidance also identifies many repositories, dependency management, handoffs, wait states and coordinated releases as costs when that independence breaks down.

Our small sample made me less confident in the crude intuition that more boundaries necessarily mean more convergence cost. A narrower hypothesis survives:

Parallel breadth can be cheap.Serialization is expensive.

A microservice boundary that gives an agent a small, comprehensible, independently testable world may be extraordinarily useful. A boundary that causes one logical change to require synchronized contracts, version propagation, several pull requests, several CI pipelines and coordinated deployment introduces convergence obligations that cheap implementation does not erase.

The traffic analogy is therefore not that more roads create too many intersections. It is that faster cars do not increase the capacity of a one-lane bridge.

This is why I increasingly want to separate modularity from distribution. Agentic implementation appears to reward strong conceptual boundaries. Whether every useful boundary should also become an independently versioned and deployed system remains a separate economic question.

## Building faster against a moving target

There is another source of pressure that would be easy to miss if this were only a story about coding agents.

The systems we build with these tools sit on top of an AI substrate that is itself changing unusually quickly.

Before our voice system became large, we aligned on several architectural principles. Latency would be treated as architectural rather than cosmetic. Deterministic machinery would retain control wherever deterministic control was available. Third-party orchestration frameworks would sit behind our own abstractions. Voice transport would remain separable from higher-level conversational behavior.

Then the substrate moved.

On September 10, 2026, OpenAI released GPT-Live-1 in the API, bringing a full-duplex voice model capable of listening and speaking at the same time and explicitly positioning the model as a way to simplify voice-agent architecture and reduce latency.

The product opportunity did not arrive through the roadmap. Engineering noticed the capability change and carried it upstream.

Product looked at what the new model appeared to make possible and approved an experiment. There was little need for prolonged negotiation because the architecture had already made the decision relatively cheap: the existing voice path could remain intact while the new substrate was introduced alongside it for comparison.

At the time of writing, that experiment had been implemented but not yet validated. That distinction matters. The architecture appears to have made the change additive; testing still has to establish whether the new capability actually improves the product.

I initially regarded this merely as a satisfying architectural outcome. I now think it illustrates something larger: architecture can reduce the cost of organizational decision-making.

If evaluating a frontier capability requires replacing a large part of the existing system, Product must authorize a substantial bet. If architecture turns the same change into a bounded and reversible experiment, the product decision becomes smaller.

Architecture creates option value.

The episode also complicates the traditional Product–Engineering relationship. Product continues to send intent toward Engineering. But when the technological substrate changes quickly enough, Engineering increasingly sends newly feasible product possibilities back toward Product.

That means a specification must distinguish durable product intent from assumptions about the present technological moment. The requirement that a voice interaction feel responsive may endure. The assumption that it must be implemented through a particular staged speech architecture may not.

INVARIANTS

what the product must continue to accomplish.

CONSTRAINTS

what an implementation must presently respect.

ASSUMPTIONS

facts about the current substrate that may stop being true.

A temporary model limitation becomes a kind of specification debt when it is mistaken for a permanent product requirement.

## The rituals were designed around a different scarcity

A great deal of familiar software-development ritual assumes that human implementation capacity is the thing being rationed.

Backlog refinement makes work understandable enough to estimate. Sprint planning distributes it among engineers. Standup reports what those engineers did and what is blocking them.

That model starts behaving strangely when implementation capacity becomes elastic enough that several tasks can move while the human engineers are occupied elsewhere.

The useful synchronization questions change.

-   What needs a human decision?
-   What is failing to converge?
-   Which task has exceeded the boundaries under which we were comfortable delegating it?
-   What newly discovered information invalidates an assumption behind work already in flight?

Upstream, refinement starts to resemble an autonomy preflight. Is the intent clear? Is the work operationally bounded? Can the executor verify completion? Does it contend for a serialized resource? Is there a reason to preserve synchronous human attention?

That direction resembles current spec-driven development efforts, but I suspect the important artifact is not simply a longer specification.

The harder problem is deciding how to shape intent into work that the engineering system can absorb economically.

That responsibility does not belong cleanly to Product or Engineering. Perhaps it should remain shared.

## What became scarce

I began with a simple prediction. Coding agents were making implementation cheap, so engineering would move upstream into specification and architecture.

Our own evidence did not support the clean version.

Some work moved upstream. Intent has to be converted into more operationally bounded units because ambiguity can now turn into implementation very quickly.

Some work accumulated downstream. Candidate changes have to survive critique, correction, CI, shared-state reconciliation, integration and merge.

Some constraints were neither upstream nor downstream. They were latent in the delivery system itself: serialized resources, unavailable verification capabilities, asynchronous review boundaries, architectural dependencies.

And some work arrived from a different direction entirely. The technological substrate changed, and Engineering had to recognize that the product had acquired a new option.

The part that consistently shrank was implementation itself.

That has changed how I think about productivity.

Generated lines of code are nearly useless as a measure. The percentage of code written by AI is not much better. In our environment, that number is already so high that it distinguishes almost nothing. Even time to first pull request captures only the cheap part of the process.

The quantity I increasingly care about is harder:

How economically can an intent become safely accepted behavior?

That includes specification. It includes implementation. It includes proof. It includes the number of technical and human round trips required to reconcile a change with the system around it.

And it suggests a different way to think about autonomy.

The best task for an autonomous agent is not necessarily the one it can code.It is the one the engineering system can afford to let it carry all the way home.

## Note on evidence

The repository analysis described here is a retrospective sample of twenty recent merged changes from two repositories in one production system. It is hypothesis-generating, not a controlled experiment. Assignment to interactive and asynchronous workflows was non-random; the repositories exhibited different cost structures; line counts are poor measures of difficulty; and treating inter-event gaps of six hours or more as a queue proxy cannot establish what humans were doing during those periods.

I include the analysis because it changed my own model. In particular, architectural fan-out was a much weaker predictor than I expected, while asynchronous round trips, serialized resources and verification constraints appeared more consequential. Those observations deserve larger samples before they deserve stronger claims.

## Related work

[When Production Disagrees with the ArchitectureThe same production system, from the other direction: what a counterexample should teach an architecture, and what it would take for an engineering system to earn autonomy from evidence.](https://jasonstiltner.com/writing/when-production-disagrees/)[Agentic Delivery: Specs, Supersession, and Eval GatesThe same convergence problem at much smaller scale — this site, written under a spec with eval gates, including the defect the process found in its own verification record.](https://jasonstiltner.com/writing/agentic-delivery/)

## References & intellectual lineage

Named rather than linked. Each entry is given in enough detail to find. None of these supports the retrospective’s own figures — see [the note on what you cannot check](#provenance).

-   Spec-Driven Development: A Spec-First Approach to AI-Native Engineering — Microsoft for Developers. Begins from the same premise: faster implementation raises the value of preserving intent, constraints, acceptance criteria and architectural context across the development lifecycle. This piece asks what happens farther along that curve, once implementation is already almost entirely model-mediated.
-   Speed limits, GenAI coding agents and Autobahns — part 2: raising the safe speed — Chris Richardson, Microservices.io. Argues that coding agents make microservices more attractive: smaller bounded working sets constrain blast radius, and independent delivery pipelines can absorb more parallel change safely. The argument this piece takes seriously and then qualifies.
-   Capabilities: Loosely coupled teams — DORA. The qualification. A service boundary's value depends on genuine independence — changing, testing and deploying without fine-grained coordination or lock-step release — and names many repositories, dependency management, handoffs, wait states and coordinated releases as costs when that independence breaks down.
-   Build more natural voice experiences with GPT-Live-1 in the API — OpenAI, 10 September 2026. The substrate change described in the second half: a full-duplex voice model able to listen and speak at once, positioned as a way to simplify voice-agent architecture and reduce latency. The occasion for the argument that architecture creates option value.

[Back to Writing](https://jasonstiltner.com/writing/)
