Make the SEO contract a build gate
Most site regressions announce themselves. A broken build fails, a broken test goes red, a runtime error throws. Metadata regressions do none of that. The page renders, the deploy succeeds, and the damage shows up weeks later in a traffic graph nobody can explain.
We shipped a framework migration that carried three of them at once. Every page emitted two title tags and two description tags, with a generic value first. Sitemap and RSS generators walked a build directory that no longer existed and quietly wrote empty files. A machine-readable content index crashed on a deleted module and produced nothing. All three published successfully.
The response was to make the contract executable. The production build now runs a metadata check and a full crawl of the built site, and fails if:
- any page emits more than one title or description tag
- a page that is linked internally is missing from the sitemap
- a URL that should not exist returns anything other than 404
- a page that should be indexable is marked noindex, or the reverse
The subtle part is the exception handling
One of those rules initially failed on thirty-three pages that were deliberately set to noindex, follow and canonicalised to a hub page. They were linked internally and absent from the sitemap, which is correct behaviour for a consolidated page. The rule was right in general and wrong for that case, so the rule learned about indexability rather than being switched off.
That is the discipline worth keeping: when a gate fires on something legitimate, teach it the distinction. Disabling it costs you the next real regression.
We also keep a snapshot of the site's structure — page count, indexable count, sitemap entries, internal link totals — and diff it across large changes. A refactor that quietly drops two hundred internal links looks identical in a code review and obvious in a diff.
