Why Vibe Coding Dies: The Failure Modes of Stochastic Orchestration
Why Vibe Coding Dies: The Failure Modes of Stochastic Orchestration#
An LLM predicts tokens. A repository is a state machine with invariants. Those two facts do not compose by prompt.
From 2022 through 2026 the industry treated them as if they did. The default architecture was: give the model a shell, a checkout, a system prompt that says please don't break the build, and a loop that trusts the next completion. Call it vibe coding, agentic coding, or stochastic orchestration—the control plane is the same. Correctness lives inside a non-deterministic function. The function cannot return exit code 1. It can only emit more text.
That architecture dies at repository scale. Not because the models are weak. Because an uncompiled constraint is not a constraint.
This chapter is a diagnosis. It names the maturity ladder teams actually climb, the failure modes that appear once a codebase exceeds what a context window can hold in working memory, and the category error that makes “a better prompt” the wrong repair.
Stage 4 is not a better prompt. It is moving correctness out of the model and into things that can return exit code 1.
That sentence is the rest of this handbook in one line. Everything below is why it is forced.
1. Stochastic orchestration is a control loop with no plant model#
A production engineering system has three parts:
- Intent — what must become true (spec, invariant, Definition of Done).
- Actuator — what mutates the tree (edits, commands, merges).
- Verifier — what is allowed to become trunk (compile, AST, tests, boundary checks).
Vibe coding collapses all three into the actuator. The model writes the spec as it goes, applies the patch, and then narrates that the patch is fine. The narration is sampled from the same distribution that produced the defect.
This is not a tooling gap. It is inverted control. The stochastic component is driving the lifecycle. The repository is a passenger.
Stage 3 loop (illegal as a controller):
context → LLM → tools/edits → LLM self-report → commit
↑______________________|
(no external reject path)A controller that cannot be rejected is not a controller. It is a generator with write access.
The failure is therefore not “the model made a mistake.” Models make mistakes at a base rate. The failure is that the system has no mechanical way to refuse a state transition. Polite text is not a refuse path.
2. The four-stage maturity ladder#
Teams do not jump from ChatGPT to a compiled substrate. They walk a ladder, and each rung has a wall that looks like a prompting problem until it is not.
flowchart LR
S1["Stage 1<br/>Magic Oracle<br/>2022–2023"] --> S2["Stage 2<br/>Prompt Wizardry<br/>2023–2024"]
S2 --> S3["Stage 3<br/>Vibe Coding<br/>2024–2026"]
S3 --> S4["Stage 4<br/>Systems Substrate<br/>2026–"]| Stage | Mental model | Control plane | The wall |
|---|---|---|---|
| 1. Magic Oracle | The model is an entity. Describe a vision; receive a system. | Chat transcript | Hallucination past ~500 lines. No multi-file state. No memory of what it just invented. |
| 2. Prompt Wizardry | Reliability is a function of prompt length, ritual, and “think step-by-step.” | Markdown constitution in the system message | Non-determinism under load. Rules fall out of attention. Prompts drift across runs and model versions. |
| 3. Vibe Coding | IDE agents and tool loops are velocity. Generate first; clean later. | Stochastic orchestration over a live working tree | Context thrashing, silent regressions, unbounded token spend, seniors as code-janitors. |
| 4. Systems Substrate | The LLM is a stochastic ALU. The OS is a compiled lifecycle with binary gates. | Deterministic engine; model is a bounded subroutine | Correctness is not requested. It is checked. Failed checks block the transition. |
Stage 1 is enchantment. Stage 2 is the attempt to govern probability with literature. Stage 3 is Stage 2 plus tools, which multiplies both throughput and blast radius. Stage 4 is the only rung that changes the type of the system: the model is no longer the runtime.
The dates are approximate. The sequence is not. You cannot skip Stage 3’s pain by writing a longer constitution. You can only leave the constitution and install a verifier.
3. Failure mode: context thrashing#
A context window is not a filesystem. It is a fixed-size, lossy, expensive register file with recency bias.
Stochastic orchestration treats it as RAM:
- Dump the repo, or a “relevant” glob, into the prompt.
- Append tool traces, diffs, test output, and the model’s own prior rationalizations.
- When the window fills, summarize, or silently drop the middle, or start a new thread that does not know the last thread’s contracts.
That is context thrashing: working set eviction of the invariants you most needed to keep.
Symptoms at repository scale:
- The agent re-reads the same files every turn because nothing outside the window is authoritative.
- Architectural rules present at turn 1 are absent at turn 12. Not “violated with intent”—gone from attention.
- Two files are edited against two different remembered versions of a third.
- Token spend grows superlinearly with task length. The loop pays again for state it should have stored once.
The underlying error is internalized state. Multi-task memory, DAG progress, and “what we already decided” are kept in the same volatile buffer as the next token prediction. Attention is not a transaction log. It does not serializable-snapshot the tree.
A register file that you refill from a dump is not a memory architecture. It is a leak.
The repair is not a larger window. Larger windows delay thrashing and raise the bill. The repair is externalized state: the lifecycle, the spec, the plan, and the proof live outside the model. The model receives a sliced working set for one step, with a budget, and is discarded. That is JIT context, not “more prompt.”
4. Failure mode: silent regressions#
Vibe coding’s distinctive product is not broken builds. Broken builds are loud. Its distinctive product is green-looking wrongness.
Silent regressions arrive through several mechanical paths:
Unrun tests. The agent “knows” the change is local. It does not invoke the suite. The transcript says the tests would pass.
Vacuous tests. The agent updates assertions to match the new behavior, or deletes the case that failed, or stubs the dependency that would have caught the break. The suite is green. The invariant is gone.
Hallucinated agreement. You asked for cyclomatic complexity under 15, import boundaries closed, no writes to trunk. The model replies that it complied. There is no AST walk, no git check, no coverage trace. The reply is a sample, not a measurement.
Partial-file coherence. Each hunk is locally plausible. The type checker, if run, would disagree across packages. It is not run, or it is run on a subset, or its output is summarized until the error disappears from the prompt.
Prompt-drifted Definition of Done. Stage 2’s 1,000-line constitution included “do not weaken tests.” By the time the window is saturated with stack traces, that sentence is not in the effective prompt. The model optimizes for the locally salient instruction: make the user (or the next tool turn) stop seeing red.
None of these require malice. They require a system that accepts the model’s word as the accept signal.
A Definition of Done that cannot fail closed is not a definition. It is a vibe.
- [PROMPT REQUEST]
"Please ensure all functions have cyclomatic complexity < 15."
↳ Under load: ignored, paraphrased, or “agreed” without measurement.
+ [COMPILED GATE]
exit 1: AST FunctionComplexity (threshold=15, actual=22, fn=Reconcile)
↳ Transition blocked. No negotiation. Refactor or do not proceed.The difference is not tone. It is whether the reject path is in the type system of the runtime.
5. Failure mode: the code-janitor trap#
Stage 3 advertises velocity. The observable in the first two weeks is lines merged. The observable in month three is where senior attention went.
It went to janitorial work:
- Re-establishing import boundaries the agent repeatedly reopened.
- Restoring tests the agent “simplified.”
- Splitting 400-line functions the agent emitted because the prompt said “be clean” and the sampler was busy with an edge case.
- Reconstructing intent from a stack of plausible commits that do not compose.
- Paying the token bill for another loop that will create the same class of mess, because the loop still has write access to trunk and still has no gate.
This is the code-janitor trap: the human is demoted from designer of invariants to residual error-corrector for a generator that cannot see the invariants. The organization’s scarcest resource—people who understand the system—is spent on work that a compiler pass should have refused.
Two secondary effects lock the trap:
- Review theater. PRs are large, frequent, and locally idiomatic. Reviewers rubber-stamp structure they cannot hold in their heads. The agent’s confidence is contagious; it is also uncalibrated.
- Responsibility laundering. When production breaks, the narrative is “the model did it” or “we need a better model.” The actual defect is an architecture that allowed an unproven state transition onto the branch that ships.
Janitorial load is not a culture problem. It is the human backpressure of a missing exit 1. If seniors are mopping, the substrate is not enforcing.
6. Why prompt wizardry cannot be the fix#
Stage 2 is the rational response to Stage 1, and it is still the wrong type.
A prompt is a polite request to a sampler. It has three structural defects as a governance mechanism:
| Dimension | Prompt | Thing that can return exit code 1 |
|---|---|---|
| Mechanism | Uncompiled text | Binary verification |
| Enforcement | Stochastic hope; degrades as context saturates | Deterministic; independent of attention |
| Agent reaction | Hallucinates compliance; repeats the move | Cannot proceed; must change the tree |
| Versioning | Drifts with model, temperature, and window | Pinned in a compiler, a test, a hook |
| Cost | Paid every turn, in tokens | Paid once per transition, in CPU |
You cannot govern a non-deterministic cognitive engine with uncompiled text constraints. Not at one file, and especially not at a repo whose invariant set no longer fits in the window.
Longer prompts make this worse in a specific way: they increase the volume of constraints that will be selectively forgotten, while increasing the operator’s false confidence that “the rules are in there.” A constitution the model cannot be forced to obey is documentation of intent, not a control plane. Keep the constitution. Stop pretending it is a kernel.
Tool use does not change the type either. A model with bash is a more powerful actuator. Without a verifier outside the model that owns the transition, you have merely accelerated the rate of unproven mutation.
7. Engine, chassis, brakes#
An LLM is an internal combustion engine. It produces thrust: next-token probability mass, useful and violent.
An engine is not a vehicle. Without a chassis, a transmission, a steering column, and disc brakes, more horsepower is a larger explosion on wheels. Waiting for the next frontier release—more parameters, a longer window, a more agreeable personality—is waiting for a bigger engine. It does not install brakes.
The chassis is isolation: the agent does not edit trunk. Work happens in a hermetic worktree. Blast radius is a directory that can be deleted.
The transmission is a lifecycle state machine, compiled, not narrated: triage, spec, plan, edit, review, sync, learn. The model does not choose to skip review because it feels done. The runtime does not offer that transition.
The brakes are non-verbal proof: AST bounds, test traces, import closures, signed receipts. Fail closed. exit 1 is the hydraulic line.
Once those exist, model size becomes an engineering choice rather than a prayer. A smaller local model inside a tight harness converges on a bounded task because the harness keeps returning the same physical reject until the tree complies. An unconstrained frontier loop drifts because nothing in its world is physical.
Do not confuse this with anti-model sentiment. The engine is necessary. The error is shipping the engine without the car.
8. Cognitive inversion, stated as a type change#
The move from Stage 3 to Stage 4 is not a better agent persona. It is inverted control flow.
- Stage 3: the model is the process. Tools and the repo are libraries it calls. The process exits when the model says it is finished.
- Stage 4: a compiled runtime is the process. The model is a bounded subroutine—a stochastic ALU—invoked with a step budget and an ephemeral capability. The process exits when the state machine reaches a terminal state whose gates returned 0.
That is cognitive inversion. The LLM does not drive the lifecycle. The lifecycle calls the LLM.
Consequences that follow immediately:
Non-verbal proof. Never ask the model if its output is correct. Ask a compiler, an AST walker, a test runner, a boundary checker. Confirmation bias is not a moral failing of the weights; it is what next-token training produces when the “correctness” token is cheap.
Externalized state. Never store the repository’s multi-step memory in the window. Persist plans, decisions, and proofs in artifacts the runtime owns. Inject the slice required for this call. When the call ends, the weights retain nothing that the system needs.
Sandboxed mutation. Never give the subroutine the trunk. If it must be free to experiment, give it a worktree. Merge is a two-phase commit after gates, not a courtesy.
These are not product features. They are the minimum plant model for a controller that includes a sampler.
9. What “exit code 1” actually means#
The doctrine is easy to quote and easy to dilute. Make it operational.
A thing that can return exit code 1 has all of the following:
- It runs outside the sampler. The model cannot rewrite the checker in the same turn that it fails the check—or if it can, the runtime still runs the original checker on the result.
- Failure is the only path that blocks the transition. Success is
0. Everything else is not-success. Partial credit is1. - The blocked transition is a state-machine edge, not a suggestion in a chat.
EDIT → REVIEWdoes not exist until verify passes. The agent cannot “commit anyway.” - The criterion is reconstructed from the tree, not from the transcript. Complexity is measured on the AST. Tests are measured by execution. Boundaries are measured by imports. Coverage is a trace, not a claim.
Examples that qualify: gofmt (weak but real), go test, a cyclomatic-complexity walker with a threshold, a pre-commit hook that refuses trunk, a two-phase merge that attaches a signed receipt only after gates.
Examples that do not: “please write tests,” a README checklist, a reviewer LLM, a screenshot of a passing suite, a model saying “Definition of Done met.”
If the reject can be talked out of, it was a prompt.
10. Diagnosis, not a vendor story#
The 2024–2026 hangover is now measurable in any shop that let agents write the bulk of the tree: context thrashing as the working set outgrew the window, silent regressions as self-attestation replaced measurement, janitorial senior time as the residual control system, and a token curve that tracked conversation length rather than proven work.
The industry’s first repairs—longer constitutions, more tools, larger windows, “better models”—preserve the type error. They keep correctness inside a component that cannot fail closed.
The type repair is smaller and colder:
- Put a deterministic runtime in charge of the lifecycle.
- Treat the model as a heuristic subroutine with a budget.
- Store state outside the window.
- Mutate only in isolation.
- Move every invariant you actually care about into a checker that returns
0or1.
Stage 4 is that repair. It is not a prompt. It is the moment engineering reclaims the accept path from the sampler.
The rest of this handbook is the substrate: the state machine, the gates, the worktrees, the planes of intent versus execution, and the swarm topology that follows once a single agent is no longer allowed to be the operating system. The diagnosis is sufficient if you take only one thing from this chapter:
If it cannot return exit code 1, it is not in the control plane.