From b391e0d358b708e544e805c9121904bbe1257282 Mon Sep 17 00:00:00 2001 From: Paul Keen Date: Sun, 19 Jul 2026 00:21:11 +0200 Subject: [PATCH] added new media --- .../vibe-coding-disposable-by-design/index.md | 37 ++++++ .../patch-doesnt-stick.svg | 110 ++++++++++++++++++ .../pay-twice-math.svg | 57 +++++++++ themes/beaver/assets/css/single-post.css | 11 ++ 4 files changed, 215 insertions(+) create mode 100644 content/blog/vibe-coding-disposable-by-design/patch-doesnt-stick.svg create mode 100644 content/blog/vibe-coding-disposable-by-design/pay-twice-math.svg diff --git a/content/blog/vibe-coding-disposable-by-design/index.md b/content/blog/vibe-coding-disposable-by-design/index.md index 6e931f1f6..374ba24e9 100644 --- a/content/blog/vibe-coding-disposable-by-design/index.md +++ b/content/blog/vibe-coding-disposable-by-design/index.md @@ -46,6 +46,8 @@ What's missing is everything below the surface. The AI wasn't asked to write tes AI generates code from scratch on each prompt instead of refactoring existing patterns. After a hundred prompts, your codebase has fourteen slightly different implementations of the same auth check, six places that handle currency rounding differently, and two competing definitions of who counts as a paying user. When a bug shows up and you ask the AI to fix it, it patches one of those places. The duplicates keep producing the bug. +![Why the fix doesn't stick: one bug - the retry loop double-charges - pasted into seven files. The dev patched file 3; files 4 through 7 kept firing. The commit said "fixed retry logic"; four days later the same bug fired from a different file.](patch-doesnt-stick.svg) + Founders feel this chain without seeing the cause directly. The fixes don't stick. New features take longer to ship than the last ones did, and nobody on the team can quite say why. Eventually you hire your first engineer to make sense of it, and they reach the verdict most engineers we've placed on inherited vibe-coded codebases reach within a week: rebuild, don't refactor. A developer used to need months to create the kind of messy system a senior engineer needs months to clean up. With AI-assisted code, the same complexity gets built in a weekend. The fragile system arrives ten times faster, but cleanup is still set by humans reading every line - and that pace hasn't changed. @@ -62,6 +64,15 @@ The maintenance failure mode is the quiet one. The loud one is what surfaces whe **EnrichLead (March 2025).** Founder Leo Acevedo [shipped a sales-lead SaaS](https://vibegraveyard.ai/story/enrichlead-vibe-coded-saas-shutdown/) built entirely in Cursor with what he publicly called "zero hand-written code." Within two days of his viral launch post, attackers bypassed the subscription paywall, manipulated user data, and burned through his API budget. The product shut down in seven days. +Four companies, one failure shape: + +| Incident | What surfaced | How fast | +|---|---|---| +| Lovable (Apr 2026) | 170+ of 1,645 sampled apps leaking personal data | 48 days exposed | +| Moltbook (Jan 2026) | Open database: 1.5M API tokens, 35K emails | Days after launch | +| Replit + SaaStr (Jul 2025) | Production database deleted mid code freeze | During a 12-day test | +| EnrichLead (Mar 2025) | Paywall bypassed, API budget drained | Dead in 7 days | + Veracode's 2025 study tested over 100 LLMs and found [45% of generated code samples failed security tests and introduced OWASP Top 10 vulnerabilities](https://www.veracode.com/blog/genai-code-security-report/). [Escape.tech scanned over 1,400 vibe-coded production applications](https://escape.tech/state-of-security-of-vibe-coded-apps) and reported that **65% had at least one security issue and 58% had a critical vulnerability**. None of these failures came from hostile attackers doing clever things - they came from codebases nobody could read or audit. ## The math: every vibe-to-production shortcut pays twice @@ -74,6 +85,8 @@ Then the rebuild estimate lands. Across our rescue engagements, rebuilds typical Compare honestly. The greenfield-from-scratch path ($40K) skips validation entirely - so it's not a real alternative. Vibe-validate ($1,500) plus production rebuild after the vibe attempt fails under load ($80K) lands at $81.5K total. Vibe-validate ($1,500) plus a production build on the validated hypothesis ($40K) lands at $41.5K. The $40K premium comes from rebuilding a rushed production app, not from the validation work. +![Three paths to a production app, drawn to scale: build from scratch with no validation ($40K), vibe-validate then build fresh ($41.5K), or ship the prototype and rebuild under fire ($81.5K plus months of runway)](pay-twice-math.svg) + Add the lost months to that bill. While you were rebuilding, your competitor shipped two new features and a paid integration. Your conversion rate is drifting. Your investor update for next quarter is a sentence you don't want to write. GitGuardian's [2026 State of Secrets Sprawl report](https://blog.gitguardian.com/the-state-of-secrets-sprawl-2026/) found AI-assisted commits expose hardcoded credentials at more than twice the rate of human-only commits - 3.2% vs 1.5%. That's the per-commit version of the same math: every shortcut on the way in becomes a debt on the way out. @@ -88,6 +101,30 @@ Once the hypothesis is real, kill the prototype. Don't try to maintain it - it c Rebuild in a stack a human can read - Rails, Django, Laravel, or whatever your engineer is fluent in. Write [tests as you go](/blog/why-how-use-tdd-main-tips-testing/). Deploy through CI. Let someone read every line before it ships. What ships from this stage is a product that survives paying customers and the next twelve rounds of feature requests. +```mermaid +%%{init: {'theme':'base', 'themeVariables': {'fontFamily':'Caveat, Patrick Hand, Comic Sans MS, cursive', 'primaryColor':'#faf7f2', 'primaryBorderColor':'#555', 'lineColor':'#333', 'primaryTextColor':'#1a1a1a'}}}%% +flowchart TD + A["Weekend prototype
Cursor / Replit / Lovable "] --> B["Show it to ten
potential customers"] + B --> C["Verified hypothesis:
what they will pay for"] + C -->|"keep the spec "| D["Kill the prototype
throw the code away"] + D --> E["Rebuild fresh
tests, CI, code review"] + E --> H["Survives paying customers
and feature requests"] + C -.->|"the trap "| F["Keep iterating
on the prototype"] + F -.-> G["Rebuild anyway, later,
with less runway"] + + classDef step fill:#faf7f2,stroke:#555,stroke-width:2px,color:#1a1a1a + classDef kill fill:#f5e9ff,stroke:#7c3aed,stroke-width:2.5px,color:#1a1a1a + classDef win fill:#f0f9f0,stroke:#2e7d32,stroke-width:2.5px,color:#1a1a1a + classDef warn fill:#fffbe6,stroke:#bf8a00,stroke-width:2px,color:#1a1a1a + classDef trap fill:#fff5f5,stroke:#cc342d,stroke-width:2.5px,color:#1a1a1a + + class A,B,C,E step + class D kill + class H win + class F warn + class G trap +``` + The validation work survives the kill. User flows, edge cases the prototype exposed, the data model that survived first contact with customers - those become the spec for what you build next. A senior move on the rebuild is to write tests against the running prototype first, capturing the actual behavior including discount logic and customer-specific carve-outs nobody wrote down. Then build against the tests. Otherwise you ship v2 and customers tell you "but the old one did X" for six months. Skipping the rebuild is the trap. The MVP works, the customers pay, the founder thinks: "I'll just keep iterating on this." Six months later the rebuild is happening anyway, only now the founder has runway pressure and ten production users who hit a new bug every time the team ships a fix. diff --git a/content/blog/vibe-coding-disposable-by-design/patch-doesnt-stick.svg b/content/blog/vibe-coding-disposable-by-design/patch-doesnt-stick.svg new file mode 100644 index 000000000..fb1a4bfbd --- /dev/null +++ b/content/blog/vibe-coding-disposable-by-design/patch-doesnt-stick.svg @@ -0,0 +1,110 @@ + + Why the fix doesn't stick: one bug - the retry loop double-charges - was pasted into seven files, one prompt at a time. The dev patched file 3. Files 4 through 7 kept firing. The commit said fixed retry logic; four days later the same bug fired from a different file. + A red bug card at the top reads: one bug - the retry loop double-charges. An arrow fans down to a row of seven file cards, each containing the same retry-plus-charge logic. File 3 is green and marked patched. Files 4 through 7 are red and marked still firing. Files 1 and 2 are neutral and marked same logic. Below, two outcome cards: a cream card reading the commit - fixed retry logic, ticket closed - and a red card reading four days later, same bug, fired from a different file. A caption states: a patch lands in one duplicate; the other six keep producing the bug. + + + + + + + + + Why the fix doesn't stick + AI regenerates instead of refactoring - the same logic gets pasted into file after file. + + + + + One bug: the retry loop double-charges + + + + + pasted into seven files, one prompt at a time + + + + + file 1 + retry + + charge + same logic + + + + file 2 + retry + + charge + same logic + + + + file 3 + retry + + charge + patched ✓ + + + + file 4 + retry + + charge + still firing ✗ + + + + file 5 + retry + + charge + still firing ✗ + + + + file 6 + retry + + charge + still firing ✗ + + + + file 7 + retry + + charge + still firing ✗ + + + + + + + The commit: "fixed retry logic" + ticket closed, everyone moves on + + + + + + Four days later: same bug + fired from a different file + + + + A patch lands in one duplicate. The other six keep producing the bug. + diff --git a/content/blog/vibe-coding-disposable-by-design/pay-twice-math.svg b/content/blog/vibe-coding-disposable-by-design/pay-twice-math.svg new file mode 100644 index 000000000..bc7f73e82 --- /dev/null +++ b/content/blog/vibe-coding-disposable-by-design/pay-twice-math.svg @@ -0,0 +1,57 @@ + + Three paths to a production app, drawn to scale. Build from scratch skipping validation: 40 thousand dollars, full price for an unvalidated guess. Vibe-validate, kill it, build fresh: 1.5 thousand for the weekend prototype plus 40 thousand for the production build, 41.5 thousand total - the play this post recommends. Vibe-validate, ship it, rebuild under fire: 1.5 thousand prototype plus 80 thousand rebuild after the prototype fails in production, 81.5 thousand total plus three to six months of runway. + Three horizontal hand-drawn bars drawn to a common dollar scale. First bar, 40 thousand, cream: production build with no validation, marked with an amber warning. Second bar: a thin purple sliver for the 1.5 thousand weekend prototype, then a 40 thousand cream production build segment; green total 41.5 thousand with a check mark. Third bar, the longest: the same thin purple prototype sliver, then a red 80 thousand segment labeled rebuild after the prototype fails in production; red total 81.5 thousand plus three to six months of runway. Caption: the forty-thousand premium is the same app built twice - once rushed into production, once properly. + + + + + + Three paths to a production app + Drawn to scale. The prototype is cheap either way - the detour is not. + + + Build from scratch, skip validation + + $40K - production build + $40K + full price for an unvalidated guess + + + Vibe-validate, kill it, build fresh + + + $40K - production build + $41.5K ✓ + validated first - the play this post recommends + + $1.5K - the weekend prototype + + + Vibe-validate, ship it, rebuild under fire + + + $80K - rebuild after the prototype fails in production + $81.5K + plus 3-6 months of runway + + + The $40K premium is the same app built twice - once rushed into production, once properly. + diff --git a/themes/beaver/assets/css/single-post.css b/themes/beaver/assets/css/single-post.css index 36ab3ec9e..4d55cc372 100644 --- a/themes/beaver/assets/css/single-post.css +++ b/themes/beaver/assets/css/single-post.css @@ -239,6 +239,17 @@ display: block; margin: 0 auto; } +.mermaid .nodeLabel p, +.mermaid .edgeLabel p { + /* Mermaid wraps HTML labels in

. Article paragraph styles (e.g. + .blog article.single-content .fl-rich-text p at 1.4rem/1.7) apply + AFTER mermaid has measured the label, re-wrapping text and inflating + node boxes. !important because the article rule wins on specificity + and mermaid labels must never take article typography. */ + font-size: inherit !important; + line-height: inherit !important; + margin: 0 !important; +} /* GFM task lists: Goldmark emits

  • ...
  • without a class. Hide the default bullet on items that contain a checkbox so the