Why Your AI-Written Code Survives Dev but Dies in Production
Let's be honest: vibe coding is a game-changer. You describe what you want, watch the agent build it, see the tests turn green, and ship. It feels like magic until it isn't.
That "until" usually arrives around 3 AM. Your app starts fine, handles a few requests beautifully, then gets unceremoniously killed by an OOM reaper. Or it opens ten thousand file descriptors and collapses. Or it runs flawlessly on your sample data and melts down when real users show up.
The code was correct. It solved the problem exactly as specified. It just assumed infinite memory and infinite file handles — because nothing in your prompt said otherwise.
The Silent Killer: Unstated Assumptions
This is the sneaky part about vibe coding that nobody talks about at conferences. When you write code yourself, you carry mental models of constraints everywhere. You know you're running on a laptop with 16GB RAM. You know the production server has file descriptor limits. You know that 400GB CSV file is not something you can just load into memory.
But when an AI writes your code, those constraints don't exist. The AI sees "load the file, sort it, write the result" and thinks: great, I'll load the whole thing. It works perfectly in testing. The test file is 50KB.
Code reviews won't catch this either. The offending lines look completely reasonable. Nothing raises a red flag when you're scanning for logic errors — because there aren't any. The bug isn't in the logic; it's in the invisible box the logic was designed to fit inside.
What If the Compiler Actually Knew?
Here's where things get interesting. A developer named Nicolas Grislain has been experimenting with a provocative idea: what if resource constraints were types, not comments?
Instead of hoping your AI-generated code respects memory limits, what if the compiler literally refused to compile code that violated them? What if "this function never holds more than 100 records in memory" and "this program never has more than 3 files open simultaneously" were facts the compiler verified, not prayers you whisper during code review?
This isn't just theoretical hand-waving. The experiment uses Lean 4 — yes, the same Lean that's been making waves in formal mathematics — to encode resource budgets directly into function types. The compiler becomes a resource auditor, automatically checking that your code stays within limits before it ever runs.
Making Resources Count
The core trick is surprisingly elegant: thread resource counts through the type system. Rather than tracking "how many files are open" as a runtime variable that might get ignored, the type system tracks it as a phantom parameter that must balance.
When you open a file, the type signature reflects the change: you enter the function with N files open and exit with N+1. When you close it, you go from N+1 back to N. The compiler tracks this at every step, and you literally cannot compile code that opens a file without closing it, or opens files past a defined cap.
Memory works similarly, but with a twist. Records don't float freely in memory — they live in a bounded pool with a fixed number of slots. You don't hold an Event object; you hold a reference into that pool. The type tracks how many live references exist at any moment, and allocation requires proof that there's room.
The magic happens at the entry point: the program must start with zero resources in use and end with zero. You can't leak handles or refs. You can't exceed caps. The compiler simply won't let you.
Why This Matters for Vibe Coding
This approach transforms how we think about prompting AI assistants. Today, you might add a note like "be careful with memory usage" or "close all file handles" — hoping the AI pays attention. With resource-aware types, you specify constraints formally, and the implementation must reorganize itself to satisfy them.
The AI gets the unconstrained version first. Tests pass. Then you enable the limits. The compiler immediately rejects the implementation. The AI must restructure its approach — perhaps processing the file in chunks instead of loading it all at once, or using a connection pool instead of opening files directly.
The implementation doesn't just happen to work; it provably works within the budget.
The Practical Reality
Let's be clear: this isn't production-ready tooling for most teams yet. The Lean 4 approach requires significant setup, and there's overhead in thinking in terms of indexed types. But the underlying insight is valuable regardless of implementation.
When vibe coding, you're outsourcing not just the code writing but the mental model of your system. Your AI assistant doesn't know your production environment. It doesn't know your container has 512MB RAM. It doesn't know your Linux kernel caps file descriptors at 1024.
Until we have better ways to encode these constraints, we have a few pragmatic options:
Be explicit in prompts — "The input file may contain up to 10 million rows" beats "handle large files efficiently"
Test with production-scale data — If your training data is tiny, your AI won't learn resource patterns
Use bounded APIs — Architecture that naturally limits resource usage (connection pools, streaming instead of loading) is harder to misuse
Watch for resource-aware tooling — The industry is starting to explore ways to make constraints explicit in AI-generated code
The Bottom Line
Vibe coding's dirty secret isn't that it writes buggy code — it's that it writes code that's correct within an invisible constraint space. That space happens to include your laptop, your test environment, and maybe your first thousand users. It definitely doesn't include "production at scale."
Resource-aware type systems like this Lean 4 experiment point toward a future where "correct" means more than "logically right." It means "proven to stay within the bounds that actually exist."
That's a future worth building toward. Until then, keep your test data close to production size, and maybe add an extra note in your prompts about those file descriptor limits.
Your future on-call self will thank you.