Engineering with AI · Engineering Process
Reading time · 7 min
The Bottleneck Moved: When Writing Code Became the Cheap Part
How AI coding agents shifted StackLiberate’s engineering bottleneck from producing code toward specification, architecture, review, verification, durable context, visual validation, and acceptance.

For most of software history, implementation was expensive.
A feature might be easy to describe and difficult to produce. Engineers spent hours translating requirements into functions, components, migrations, tests, configuration, and glue code. Even after the architecture was understood, there was still a large amount of mechanical work between an idea and a working system.
Coding agents changed that equation for us.
Today, once a StackLiberate change is well understood, an agent can often inspect the relevant repository, modify several layers, update types, write tests, run validation, investigate failures, and revise the implementation far faster than we could reasonably reproduce the same sequence by hand.
That sounds like the bottleneck disappeared.
It did not.
It moved.
When implementation became cheap, everything required to decide whether an implementation deserved to exist became more important.
That has been one of the most consequential changes in how we build StackLiberate.
Faster coding does not mean proportionally faster shipping
Recent research is starting to quantify something that is easy to feel when working with coding agents.
AI can increase coding activity dramatically while producing much smaller gains by the time work reaches actual releases.
That makes sense.
Software does not travel directly from:
idea → code
It travels through something closer to:
intent
↓
design
↓
implementation
↓
integration
↓
verification
↓
review
↓
release
↓
real-world behavior
Speeding up one stage increases pressure on whatever comes next.
If implementation capacity doubles but review capacity stays constant, review becomes the constraint.
If review becomes automated but nobody can confidently determine whether a change preserves architectural intent, understanding becomes the constraint.
If implementation and review both become fast but product acceptance still requires careful human judgment, acceptance becomes the constraint.
This is basic systems behavior.
Remove one bottleneck and another becomes visible.
For us, AI did not eliminate engineering work.
It exposed where the expensive engineering work had actually been hiding.

We noticed it before we had a name for it
Early in building StackLiberate, the workflow could still resemble conventional development.
Understand a feature.
Write it.
Test it.
Move on.
As coding agents became more capable, implementation increasingly stopped dominating the elapsed effort.
Something else started happening.
An agent could produce a substantial change surprisingly quickly.
Then we would spend far longer asking questions such as:
- Is this actually the right layer?
- Did it reuse the existing system or create a parallel one?
- Does this survive reload?
- Does another lifecycle path reconstruct the same state?
- Did an apparently harmless shortcut weaken an invariant?
- Did a shared component change behavior somewhere outside the feature?
- Does the real UI behave correctly, not just the test fixture?
- Does the result still work when exported?
- Was anything silently broadened beyond the requested scope?
Sometimes the first implementation was good.
Sometimes it was locally excellent and architecturally wrong.
And sometimes the quickest implementation generated enough downstream investigation that the supposedly “fast” path was slower overall.
That changed what we optimized.
The question stopped being:
How quickly can the agent produce the feature?
It became:
How quickly can we reach a result we understand well enough to accept?
Those are not the same metric.
Code became abundant; confidence did not
This is the part of AI-assisted development that can be easy to underestimate.
An agent can generate more implementation than a human reviewer can deeply reason about.
That creates an asymmetry:
Generation capacity Human attention ─── Architectural knowledge ─── Validation time ─── Product judgment ─── ```
The scarce resource is no longer necessarily keystrokes.
It is confidence.
Not confidence as a feeling.
Confidence backed by evidence that:
- The requested behavior works.
- The system still has coherent ownership boundaries.
- Existing behavior remains intact.
- Failure modes are understood.
- The change can be maintained.
- The implementation represents the intended product decision.
OpenAI has described encountering a closely related constraint in an agent-first codebase: once agents could produce enormous amounts of software, human QA capacity became a bottleneck. GitHub is now explicitly describing the industry problem in similar terms: generating code has become easy enough that review, security, governance, and shipping increasingly determine throughput.
That feels familiar to us.
Our response was not to slow down generation.
It was to build more structure downstream.
Plan First was partly a throughput optimization
At first glance, planning before implementation sounds like the opposite of moving faster.
Why spend time writing a plan when the agent could already be coding?
Because a bad implementation is now cheap to create and expensive to unwind.
Before agents, producing a large wrong implementation carried enough friction that engineers often discovered uncertainties while writing it.
Coding itself was part of the thinking process.
Agents compress that interval.
A weak assumption can become a clean multi-file implementation almost immediately.
So we moved more reasoning upstream.
For meaningful changes, we increasingly ask for read-only discovery first.
Then a plan.
The plan should identify enough of the system to answer questions such as:
What is authoritatiWhich contract owns this behavior?
What must remain invariant?
What is the expected blast radius?
How should failure behave?
How will we validate the result? ```
Only then does implementation begin.
This does not make coding slower.
It prevents cheap coding from generating expensive confusion.
Contracts became more valuable than instructions
As implementation capacity increased, we also became less interested in telling agents exactly how to write every change.
That does not scale.
Instead, the valuable information became constraints that survive individual implementations.
A strong contract might establish:
- One source of truth.
- A valid state transition.
- A required lifecycle property.
- A permission boundary.
- A compatibility requirement.
- A deterministic reconstruction rule.
Then the agent has room to implement inside those constraints.
This creates an important shift.
The human does not need to prescribe:
write function A
then helper B
then condition C
The system needs to communicate:
these properties must remain true
That is much more durable.
It also makes review meaningful.
We can compare the result against a contract instead of merely asking whether the agent appears to have implemented its own idea correctly.
When writing code becomes cheap, clarity about what code is allowed to mean becomes expensive and valuable.
Context became part of production infrastructure
There is another bottleneck that only becomes obvious over time.
Understanding does not automatically scale with generated code.
An agent can understand a subsystem extremely well during one session and lose much of that context later.
A different model can arrive without the history.
A future task can rediscover an implementation shortcut that was previously rejected for a good reason.
The system can continue growing while the reasoning behind it disappears.
That creates a strange situation:
More code
More tests
More featubut
Less understanding of why they fit together ```
So part of our downstream investment became durable context.
Important architectural knowledge should not depend entirely on yesterday's conversation.
Plans, invariants, decisions, validation rules, and relevant project boundaries need durable homes where future work can recover them.
This is not documentation for documentation's sake.
It is capacity management.
If every new agent must rediscover the architecture before useful work begins, context recovery becomes another bottleneck.
If the architecture cannot be rediscovered at all, the problem is worse.
Review changed from proofreading to systems reasoning
AI has also changed what we find valuable in review.
When implementation is scarce, code review often spends significant effort on implementation details.
Is this helper correct?
Could this loop be simpler?
Is this abstraction clean?
Those questions still matter.
But increasingly, the high-leverage review questions for us are:
Did this change put responsibility in the right place?
Did it create another writer?
Did the agent solve a visible symptom instead of the underlying contract?
Is this generalization justified by actual product needs?
What happens outside the happy path?
Did the implementation preserve the system we intended to have?
That is a different form of review.
It is less like proofreading code and more like inspecting a structure after a very fast construction crew finished building it.
The construction crew may be excellent.
You still need to know whether the building is standing on the correct foundation.
This is also why we increasingly use AI for review itself.
Generation does not have to be the only stage agents accelerate.
Agents can independently trace behavior, search for duplicate ownership, inspect failures, compare an implementation against its plan, and challenge another agent's assumptions.
If generation increases, verification capacity needs to increase too.
Automated tests are necessary, but they are one kind of evidence
This shift also changed how we interpret green tests.
Tests are enormously valuable.
But when an agent can generate both the feature and the tests, we need to be careful not to let the implementation define the only questions used to evaluate itself.
A green suite may establish:
The behavior we tested works.
It does not automatically establish:
We tested the right behaviThe state lives in the right place.
Another lifecycle path still works.
The architecture did not quietly fork.
The product interaction is actually acceptable. ```
So our validation stack became broader.
Depending on the change, confidence might require some combination of:
Types
+
Unit tests
+
Contract tests
+
Integration tests
+
Build validation
+
Real browser behavior
+
Visual inspection
+
Architecture review
+
Human acceptance
That looks like more work.
It is.
But the amount of implementation that can now arrive upstream has increased dramatically.
Downstream capacity has to adapt.
Visual products reveal the problem quickly
StackLiberate makes this especially visible because it is a visual product.
A browser test can prove that a button was clicked.
A unit test can prove that an operation produced the expected state.
Neither necessarily proves that the resulting editing experience feels right.
Something can be technically correct and visibly wrong:
- an overlay can cover the wrong area;
- responsive behavior can collapse awkwardly;
- an interaction can technically work while feeling confusing;
- editor and exported output can each pass isolated tests while differing in an important visual detail.
This means visual validation remains part of the acceptance loop.
We let agents help with it.
They can operate browsers, inspect screenshots, reproduce sequences, and compare expected behavior.
But someone still needs to decide:
Is this actually the experience we intended to ship?
When code generation accelerates, subjective product judgment does not automatically accelerate with it.
That becomes another visible bottleneck.
“Done” became a more expensive word
One consequence is that the agent saying done carries less meaning than it once might have.
An agent can honestly report:
- implementation complete;
- typecheck passing;
- tests passing;
- build passing.
That is useful.
But it describes the implementation state, not necessarily the engineering state.
For us, meaningful completion is closer to:
Implemented
↓
Validated
↓
Reviewed against invariants
↓
Tested in the real product
↓
Unexpected blast radius resolved
↓
Accepted
Only then does the change become something we are comfortable treating as finished.
This may sound conservative.
In practice, it is how we preserve the speed advantage.
The goal is not to produce patches quickly.
The goal is to avoid spending next month repairing today's velocity.
The bottleneck can move again
There is nothing permanent about today's workflow.
Agents are already becoming better reviewers.
They can operate browsers.
They can inspect logs and traces.
They can work independently for hours.
They can evaluate each other's implementations.
Companies building agent-first workflows are increasingly making applications, observability systems, test infrastructure, and repository knowledge directly legible to agents.
That means some of today's downstream bottlenecks can also be automated.
We expect that.
But moving the bottleneck is not the same as eliminating it.
Suppose agents eventually handle:
implementation
+
tests
+
review
+
visual verification
extremely well.
Then the scarce resource may become something else:
- defining product intent;
- deciding architectural commitments;
- choosing which tradeoffs are acceptable;
- evaluating novel user behavior;
- deciding what not to build.
The constraint keeps moving toward judgment.
That is why we do not think the future of engineering is simply “agents write more code.”
The more interesting future is:
Every time AI makes one stage abundant, engineering reorganizes around whatever remains scarce.
We do not measure this precisely yet
There is an important caveat to our experience.
We have not run a controlled experiment measuring StackLiberate development with and without coding agents.
We cannot claim that Plan First improves throughput by a particular percentage.
We do not have formal measurements of review time, agent rework, cognitive load, or defect rates.
What we have is repeated operational experience building one increasingly complex product this way.
And the pattern has been consistent enough to change our process.
Implementation became faster.
So we invested more heavily in:
- discovery;
- plans;
- explicit contracts;
- durable context;
- independent review;
- automated validation;
- real browser testing;
- visual inspection;
- acceptance.
Not because AI was failing.
Because it was succeeding at implementation fast enough to expose the next constraint.
The new unit of productivity is not code
This is ultimately why we are becoming less interested in measuring AI-assisted engineering through lines of code or even the number of patches an agent can complete.
More code is easy to produce.
More software that we are willing to depend on is harder.
The useful output of our engineering process is not:
a diff
It is:
a change
we understand,
can verify,
can maintain,
and are willing to ship.
AI has made one part of producing that output dramatically cheaper.
That is an extraordinary advantage.
But the rest of the pipeline has to evolve around it.
For us, that meant an unexpected realization:
Writing the code was becoming the cheap part.
The valuable work had moved into deciding, constraining, understanding, verifying, and accepting what gets built.
The bottleneck moved.
So we moved with it.