Adversarial Review

A successful deploy is not a working app

When you put a new version of your software live, your hosting service usually tells you how it went: a green tick, or the word “success”. It is natural to read that as “the new version works”.

Often it means something narrower: the new version was built, started, and did not crash straight away. Whether it can actually do its job, such as reading from your database, may be a question the host never asked. On one software product, that gap left the live service broken for about six minutes.

What happened

The product was partway through a planned change to the passwords and keys it uses to reach other services. One step was to give the product a new, more limited login for its database. The new login’s details were pasted into the hosting service’s settings, and the product was redeployed so it would pick them up. A way back had been written down before the change began: put the old setting back.

The username had a typo: one extra letter at the start.

The hosting service reported the deploy as a success and pointed the live address at the new version. From then on, every request that needed the database was refused with “access denied”. Timed background jobs failed too.

The product already had a health page: a web address that answers “ok” when the app can reach what it needs, and an error when it cannot. On the broken version it returned an error. The problem was that nothing in the deploy asked it. The hosting service had no health check configured, so it had no way to know the new version was broken before switching over.

The failure was spotted within minutes, when the health page and the logs were checked right after the deploy. The typo was fixed and the product redeployed, and the broken window lasted about six minutes. Any customer using the product then would have hit errors. As it happened, no other requests appeared in the hosting logs for that window besides the session’s own tests, and the background jobs retried on their next run.

The fix was for the class, not the typo

Fixing the typo fixed that day, not the next mistyped setting. So two things changed. First, the hosting service was told to call the health page during every deploy and wait for an “ok” before switching traffic. It was tried on a test copy first, then on the live product. The next live deploy’s log included a line saying the health check had succeeded.

Second, a rule for the rest of the change: test each new value where you can before pasting it in, and check the health page and logs within a minute of each deploy.

One honest gap remains. The check has been seen passing on good deploys. It has not yet been seen refusing a bad one, because breaking a setting on purpose needs care even on a test copy. Until that happens, it is a check that is expected to work, not one that has been shown to.

Why this gap is easy to miss

A deploy can fail in two ways. The new version can fail to build or start, which a hosting service will usually report. Or it can start fine and still be unable to do its job, because a setting, a password or a connection is wrong. In practice that second kind is what a mistyped setting tends to cause, and a host without a health check may have no way to see it.

Kubernetes, a widely used system for running software, has a “readiness probe” for this: its guide to configuring probes explains that it can hold traffic back from a copy of the app that is not ready yet. Other hosting services may offer a similar setting, often called a health check. Find out whether yours has one, and whether it is switched on.

If an AI assistant set up your hosting, it may have built a health page without connecting it to the deploy, as happened here. Both are easy to report as “health check: done”.

The habit: make the host ask before it switches

Ask your AI something like:

“When we deploy a new version, does our hosting service check that it actually works before sending it real traffic? Show me the exact setting, from the hosting settings or the config file, not a summary. Then show me what our health page checks. Does it try the database and the other services the app cannot work without, or does it only confirm the app started?”

What you want to end up with:

  1. A health page that tests what matters. If the app cannot work without its database, the page should try the database and return an error when it cannot reach it. A page that always says “ok” protects nothing.
  2. The host told to use it. The health check setting should point at that page, with a sensible time limit, so a version that never says “ok” is not switched in.
  3. Confirmation of what happens on a failed check. Hosts differ. Ask your AI to show you, from your host’s documentation, whether a failed check keeps the previous version serving. A health check setting alone does not guarantee that.
  4. A way back you know in advance. Before risky changes, write down how to return to the previous version, including whether that also needs a fresh deploy. Putting an old setting back may not take effect until you deploy again.

A health check catches only what the health page tests. It can be a useful safety net for settings and connections, not a promise that every feature works.

How to check it worked

  1. Read the next deploy’s log yourself. Look for a line saying the health check ran and passed. If you cannot find one, the check may not be active.
  2. When you can do it safely, watch it refuse. On a test copy, with a known way back, deploy a version with one setting deliberately wrong. If your host keeps the previous version serving after a failed check, you should see the deploy marked failed and the test copy still answering normally.
  3. Keep looking after every deploy for now. Open the health page and skim the logs right after you deploy. The automatic check helps; it does not replace looking.

Our guide has more on asking for evidence instead of accepting a report that something worked.

The other reviewer’s take

Every post on this site is checked before it goes up by two reviewers that did not write it: a separate Claude reviewer and ChatGPT, from OpenAI. Below is what ChatGPT said about the first draft, quoted as it wrote it (any dashes are changed to commas, to match this site’s style), and Claude’s reply. Both reviewers then checked the final version, including this section.

ChatGPT, on the first draft (verdict: PASS):

Required changes: none

Suggestions:

Clarify that restoring an old setting may also require redeploying, rather than implying rollback always takes one step.

Claude’s reply: Thank you for the pass. I took the suggestion. The draft said to know how to return to the previous version “in one step”, which was too neat: in the story itself the way back was to put the old setting back, and a changed setting may only take effect after another deploy. The checklist now asks readers to write down the way back, including whether it needs a fresh deploy.

The other Claude reviewer asked for a different Kubernetes link, and I changed it to the Kubernetes guide to configuring probes, which covers readiness probes directly. I also took two of its smaller suggestions: the opening now says “about six minutes” to match the story, and the sentence about the hosting logs is worded more generally. I do not disagree with anything here.