Eleven commits. Three blog posts. Two structural rebuilds. Three production regressions caught in flight. One full operating-discipline document updated with new rules drawn from the day’s near-misses.
That was yesterday. Sunday, 26 April 2026. Started around 09:00 BST, last commit landed at 00:42 the next morning. Sixteen hours, give or take, with breaks.
The shipping list, on its own, would be a respectable post. But the more interesting story — the one worth the editorial attention — is what the system caught while we were shipping. Three real production regressions, none of them small, all of them surfaced inside the same session that introduced them. The site never spent more than a few minutes in a broken state for any one of them. The discipline that caught them is now permanent.
This post is the honest accounting.
What shipped
Working backwards from completion to set the stage:
- A community page rebuild for V8 Nexus, switching from invitation-gated inquiry to a free closing page with proper FAQ schema, member benefits, photo of the community lead, and gathering history embedded
- A homepage upgrade adding a five-pain section, a client outcome case study, the iFAST launch event photo, custom typographic lettermarks for the three pillars, removal of a duplicate notebook conversion path, and proper centring across all sections at wide-screen widths
- Three blog posts: an Operator’s Log on consistency-as-asset (published yesterday), an Operator’s Log on the looks-correct-vs-actually-works pattern (yesterday), and a Community Intelligence post in Gina’s voice on why solo operators with stacks burn out (yesterday). Each one shipped as a full content patch — markdown, mobile-first infographic SVG, OG social card, FAQ entry on the routed pillar page with both visible HTML and JSON-LD schema in sync, CHANGELOG entry, copy-paste-ready commit commands
- Site-wide layout fixes: footer centring on every page, hero section centring on the homepage, a
Cache-Controlheader trap quietly removed from the asset directive - A full sweep of
CLAUDE.md, the operating contract, with four new sections capturing the discipline lessons from the day’s near-misses
That’s the surface. The shape is hopefully familiar to anyone who runs a site under regular content pressure. The texture underneath is what the rest of this post is about.
What almost broke — three regressions caught in the act
Three things went wrong yesterday that, on a less disciplined day, would have shipped to production and stayed broken until somebody complained.
Regression one — the photo that wasn’t there
The Nexus rebuild referenced Gina’s portrait at a specific path. The path was correct. The file existed locally. The page rendered fine on local build. The production deploy fired green.
In production, the photo 404’d.
What happened: the photo had been generated locally and dropped into the right directory, but git add had never been run on it. Astro’s local build picks up assets from disk regardless of git state. Production sees only what’s in the repo. The image was missing on Cloudflare’s side because it never made the commit.
The recovery was a hot-fix commit landing the photo file. Total exposure: about 15 minutes.
But the recovery wasn’t the lesson. The lesson was what made it possible to catch quickly. Cloudflare served the homepage HTML in response to the missing-asset URL, with content-type: text/html, masking the 404 as a 200 OK with wrong content type. If we hadn’t actually opened the page in a browser to spot-check, the broken photo could have lived in production for days, and we’d have been confused about what was wrong because the URL “worked.”
The new rule, now codified in CLAUDE.md: before every push that introduces references to new files in public/, run git ls-files --others --exclude-standard public/. If anything’s untracked, either stage it or remove the reference. No exceptions.
Regression two — the cache lock
While diagnosing the missing-photo issue, a second-order problem surfaced. Cloudflare had cached the wrong response (homepage HTML masquerading as image content). Even after the photo file was committed and deployed, the cache was serving the old wrong response.
That should have been a 30-second cache purge. It wasn’t. The asset directory’s _headers configuration included Cache-Control: public, max-age=2592000, immutable. The immutable directive is exactly what it sounds like — the cache will not revalidate against origin until the TTL expires. A 30-day TTL combined with immutable had created a 30-day stuck-cache trap, set off by a wrong response that happened to be cached at the deploy moment.
The fix was two-step: manual cache purge for immediate recovery, then permanent removal of immutable from the asset directive in _headers. immutable is a real and useful directive, but only on content-hashed paths — filenames where any content change produces a new filename, like Astro’s dist/_astro/ build output. Stable-named files in public/assets/ should never carry it.
The new rule: immutable only on content-hashed paths. Codified in CLAUDE.md.
Regression three — the OG infrastructure that vanished
This was the worst one, and the most instructive.
Mid-afternoon, working on a homepage centring fix, the patched file accidentally dropped 13 lines of OG social-card infrastructure from Layout.astro — specifically the ogImageAlt prop, the ogImageAbsolute resolver function, the og:image:type meta tag, and the og:image:alt and twitter:image:alt tags. The CSS centring fix was correct. The OG infrastructure regression was a side-effect of editing a stale version of the file.
Stale how? The file I’d been editing in chat was an upload from earlier in the same session. Between when the upload landed and the moment of the patch, an unrelated improvement had been made to Layout.astro directly on disk. The patch I generated was correct against the upload but wrong against current state. Replaced with my patched version, the disk lost the intervening changes silently.
Caught by curl spot-checks of the deployed pages and a post-merge git show revealing 13 deletions where I’d expected zero. Recovery was git checkout against the prior commit hash to restore Layout.astro, then re-applying only the intentional CSS edits as a fresh patch on top of the current state.
The new rule, also in CLAUDE.md: before patching any near-global file (Layout, global CSS, the operating contract itself, brand identity files), request a fresh cat output to confirm current state. Files in any working context represent state at upload time, not current state on disk. The cost of asking for a fresh paste is small. The cost of silent regressions in shared layout is large.
The three principles in one sentence
Each regression had a specific principle hidden in it. All three are now permanent discipline:
- Asset commit verification: never push with untracked files in
public/ - Cache header conservatism:
immutableonly on content-hashed paths - Global file edit discipline: re-verify current state before patching any shared layout, contract, or brand file
What unifies them is that all three are about not trusting the apparent state. The local build looked correct, but the photo wasn’t in git. The deploy looked successful, but the cache was holding a wrong response. The patch looked clean, but the file it was generated against had moved on. In each case, the apparent state and the actual state had drifted, and the cost of that drift was real.
Which is, not coincidentally, the same pattern as the post we shipped yesterday on looks-correct versus actually-works. That post was about Axia’s build day. This post is about V8’s site build day. The pattern repeats across surfaces. The discipline is what catches it.
What worked — the failure recovery rate
Three regressions. Three recoveries. Total exposure to broken production: under thirty minutes across all three combined. Zero of the regressions made it into a state where any visitor or AI crawler would have seen broken behaviour for more than a few minutes.
That’s not luck. It’s the result of a few disciplines compounding:
- Direct
curlspot-checks of every deployed change, not just relying on Cloudflare’s deploy-success notification - Visual incognito-mode browser checks of all changed pages
- A clear rollback path (
git checkoutagainst a known-good commit hash) that’s faster to execute than debugging in place - A bias towards small, single-concern commits — eleven commits today, not three big ones, because small commits localise blast radius
The slowest part of recovery is figuring out what broke. The fastest path through that is to be able to say “this commit is bad, restore the prior state, redo the intentional change cleanly.” Single-concern commits make that trivial. Mega-commits with seven changes interleaved make that nearly impossible.
What this is for
V8 builds AI-native systems for SME owners. The marketing is about consistency, structure, and operator-grade reliability. Posts like this one are the proof — not because we ship without bugs, but because the system catches the bugs we ship, recovers cleanly, and turns each recovery into permanent discipline.
If you are evaluating an AI build vendor, the question that separates serious operators from demo-stage providers is genuinely what did your last bad day look like? Yesterday is a clean answer to that question.
For the build conversation about your specific operations, start with Scaffold.
For the community of people running comparable systems, V8 Nexus is free to join.
Alan Law is founder of V8 Global and architect of Axia. Operator’s Log posts document how AI-native systems get built — and operated — in practice. The discipline of catching, recovering, and codifying compounds. The blog you are reading is one of the systems doing it.
Ready to take the next step?
Join London's executive AI community — events, practical intelligence, and curated introductions for established business leaders.
How Scaffold builds the production layer