A comment in our deploy script, dated 15 October 2026, still makes us wince: Cloudflare keeps only the last block for a repeated path, so a second header block would have silently dropped a site’s own security headers. Nobody’s site shipped broken because of it. The fix landed the same day the bug was found, as a change to the script, not a line added to a document asking the next person to remember.
That is the real shape of our launch checklist. It did not start as a list of good intentions. It is the trail of things that nearly went wrong, each one now a check a script runs instead of a fact a person has to recall at the one moment they are also dealing with a client, a domain registrar and a deadline.
Noindex first, indexable only on purpose
Every static site we build goes through one Cloudflare Pages project and one script, run by hand from a director’s Mac, not from a CI job. It understands eight verbs: doctor checks the login and the project exist, test and quick run whatever the repo has, gate runs the full build and test pass, init creates the Pages project once, deploy ships to preview, staging or production, verify checks what landed, and urls prints the three links. Preview is any branch, built on request. Staging is one stable link we hand the client. Production only deploys from a clean main, because production ships what is in the repository, not what happens to be on someone’s machine that afternoon.
The rule that matters most is the one nobody has to remember: every environment, production included, is served noindex and a closed robots.txt unless a site’s own config says its real domain is live. A search engine is told to stay out by default. Only a deliberate flag, set once a domain is attached and a client has said yes, opens the door.
verify is the step that proves a deploy did what it should: a 200 response, the right noindex header for the environment, and that robots.txt and sitemap.xml both answer. It retries quietly for up to a minute, because a brand new link can take that long to get its certificate, so a person checking it five seconds too early does not read a false failure.
Every line is there because something nearly happened
Before 4 November 2026, the credit line in a new site’s footer was whatever got typed into that one file. A live client site shipped with the wrong credit line where the zxn.uk badge should have been. The fix was not a reminder to check the footer. It was a test, added to whatever gate already runs for that site’s own stack, so the badge is enforced the same way a broken link would be.
Seven client sites, three ways of gating one line
Each site's footer-credit check rides on whatever test setup it already has.
Source: New-site footer-credit rule, 4 November 2026
The DNS step on a client’s launch exists for the same reason, written larger. Moving a domain’s nameservers to Cloudflare means first reading everything the old host was doing with it: on a launch with live mail that can be a long list of records, because the domain’s mailboxes and spam filter, not just its website, depend on getting the move right. The records that matter have to be copied across exactly, each one ticked off against what the old host actually answered, not what a dashboard’s import guessed. Every record was also set to a five minute refresh instead of a day, for one reason only: so that if the move went wrong, undoing it would not take until the next morning.
Production also refuses to deploy from a dirty working tree, and will not run at all without site.json in the repo. Neither rule exists because someone imagined a disaster. Both exist because a deploy once nearly happened without one of them being true.
The obvious objection to all of this is that a list this long is bureaucracy: a way to make launching feel harder than it needs to be, more ritual than safeguard. We think the honest answer is that most of the list is no longer something a person does. verify curls the live URL and reads the header itself, rather than asking someone to open a browser and squint at it. The footer badge is a test that fails the build, not a line in a document. The noindex default is written into the deploy step, not into a box on a form. One of our sites has more than two thousand automated tests, and its gate runs them before anything ships. The checklist has grown longer over the months. The number of things a person has to personally remember on launch day has not grown anything like as fast, because almost every new line became code instead of prose.
What we skip, and why that is defensible
Not every site needs every step, and saying so plainly is better than quietly skipping it and hoping nobody asks.
Each of those is a decision about this client, at this size, not a permanent exemption. A password gate goes back on the moment a preview carries anything under embargo, whatever the site’s size. The DNS comparison comes back the day that domain grows a mailbox. None of them are a shortcut we would defend at a bigger scale; they are the right call for the thing actually in front of us today.
What the checklist cannot prove
Some of the most important facts on a launch cannot be checked by a script, because they are not technical facts. Whether a privacy policy is legally adequate for the business it describes, whether a photo on the site has the rights to be there, whether a client’s written sign-off actually arrived from the client and not from whoever happened to reply to the right email: a script can confirm a page exists, not that the right human agreed to it. On a client launch, the privacy page shipped as a labelled draft, not legal advice, because that is what it was, and the owner was asked directly whether a registration duty applied to their business, because nothing in the code could answer that for them.
Deliverability is the same kind of fact. We can check that a sending domain’s authentication records exist. We cannot check, from our side, whether a particular inbox trusts them enough to skip the spam folder, which is why the only real proof is sending an actual message and reading it arrive, every time, on a live domain, before calling the job done.
On a client launch, the old host stays live for two weeks after the cutover, on the chance any of this was wrong.



