Auditing Vibe-Coded Architecture: The Hidden Failure Modes of Unreviewed Rewrites
An architectural audit of AI-generated rewrites of Basecamp's Campfire reveals critical runtime flaws when vibe-coding without reading code. From blocking database queries in cooperative Tokio threads to overflowing broadcast channels dropping 99% of messages, agents make silent architectural compromises.

Why it matters
Inspect your agent-generated async code for blocking synchronous calls and bounded channel buffers before shipping vibe-coded services to production.
TL;DR
- 01LLMs frequently mix synchronous blocking primitives with async runtimes, causing thread pool starvation.
- 02Bounded channels without explicit backpressure handling result in silent, catastrophic data loss under load.
- 03Throughput benchmarks hide reliability flaws; test with constant arrival rate and measure event delivery integrity.
Key facts
- Rust Notification Delivery Under Load
- 1% (Zach Daniels stress benchmark)
- Rust Event Delivery (100 POSTs/s)
- 14% received (0% HTTP errors, disconnects)
- Elixir Event Delivery (100 POSTs/s)
- 60% received (23% HTTP timeouts, up to 180s latency)
Non-Functional Drift in Agentic Rewrites
When prompts lack strict architectural specifications, language models make silent trade-offs. In the AI-driven rewrite of Campfire from Ruby on Rails to Rust and Elixir, the Rust version unilaterally dropped CSRF tokens to make caching simpler and replaced Redis with in-process message queues. Conversely, the Elixir version maintained closer adherence to Rails defaults. Because LLMs lack global architectural reasoning, requirements such as backwards compatibility, session persistence, and crash resilience become random coin flips.
Thread Starvation in Async Rust
The Rust output illustrates a severe misunderstanding of cooperative scheduling in tokio. Unlike preemptive runtimes, Tokio worker threads freeze if a task fails to yield. The generated code placed blocking, synchronous SQL operations directly inside async tasks rather than executing async I/O. Furthermore, the code used standard blocking synchronization primitives instead of tokio::sync::Mutex. Holding a synchronous lock for even 10ms starves all other tasks multiplexed onto that worker thread.
The 99% Notification Drop and Backpressure
Concurrency benchmarks by Zach Daniels exposed disastrous failure modes: under heavy load, the Rust service delivered only 1% of new post notifications out of 6,000–7,000 attempts. The AI wired the notification pipeline to a tokio::sync::broadcast channel with a fixed capacity. When subscribers lagged, messages were silently dropped. In subsequent tests at 100 POST requests per second with constant arrival rates, Rust delivered only 14% of events (with zero HTTP errors but aggressive client disconnects), while the Elixir version achieved 60% delivery but experienced 23% HTTP timeouts and latencies reaching 180 seconds.
Try it in 2 minutes
// Replace blocking synchronization with async-aware primitives
use tokio::sync::Mutex;
// Avoid std::sync::Mutex inside async tasks (blocks Tokio workers)
// let guard = sync_mutex.lock().unwrap();
// Correct pattern for cooperative concurrency:
let guard = async_mutex.lock().await;rust
✓ When to use
- When planning architecture migrations where prompts can specify exact concurrency and queue primitives.
- When establishing review criteria for vibe-coded codebases entering production.
What to do today
- Audit agent-generated Rust code for std::sync::Mutex and replace with tokio::sync::Mutex in async blocks.
- Ensure database operations inside async workers use asynchronous client drivers or spawn_blocking wrappers.
- Verify channel capacities and subscriber overflow policies whenever using bounded broadcast channels.