Promotion Guard
Every build ends with a safety check before the new site replaces the old one: the promotion guard compares the finished build against the last good build — on page count, broken links, unresolved content markers, and accessibility issues — and refuses to publish a build that looks like a regression. The worst case it allows is stale output, never broken output.
This page explains what it checks, how to configure it, and how to force a build past it.
What the guard checks
Four independent gates, evaluated per build and summarized in one report:
| Check | What it compares | Default threshold |
|---|---|---|
| Page count drop | Files in the finished build vs the last good promotion | More than an 80% drop blocks |
| Broken internal links | Increase vs the count stored at the last clean promote | An increase of more than 25 |
| Unresolved block markers | Absolute count of <!-- block not found --> comments in the output | Off until you set the limit (0 means “not even one”) |
| Accessibility issues | Increase vs the last clean promote (images without alt text, missing lang, empty links, multiple H1s per page) | An increase of more than 10 |
Why deltas rather than absolutes for two of the four: absolute counts naturally scale with the size of your site (every page may share a link or an image style), so what matters is a sudden jump, not a steady-state total. A page-count baseline that has drifted downward no longer applies either — failed and blocked builds never set it, and a “promote anyway” doesn’t reset it either. The comparison point is always the last build that the guard let through cleanly, so the guard can’t be talked into tolerating a slow slide.
The three modes
Under Settings → Workflow:
- Warn (default) — a build that breaches a threshold still promotes, but a clear warning line is written to the build log: what breached, by how much, and what the limit was. Best while you learn what the guard sees on your site.
- Enforce — a breaching build is not published: the staging copy is discarded and the previous live site keeps serving. The build log records the result as blocked, with the reason and the quality counts, and the dashboard shows a Promotion Blocked banner.
- Off — no guard runs. Not recommended as a standing setting; use “Warn” instead if the guard is noisy.
Thresholds are clamped to sane values at save (the drop percentage 0–100; the others non-negative integers). The unresolved-marker gate starts switched off on upgraded sites so a routine upgrade never suddenly blocks builds for an old content bug — set a number (even 0) to switch it on deliberately.
When a build is blocked
- The dashboard’s status panel switches to Promotion blocked with the reason, and a Promote anyway button appears — but only in that state, and only for admins.
- The built site is not shown: everything in the failed candidate is discarded cleanly, and the live site never serves a half-done promotion.
- The build history keeps the failed attempt with its complete log and the quality counts, so you can see exactly what regressed (a page-crash, a broken template producing missing-link noise, a mass of unpublished pages) before deciding.
- A blocked build is a warning about your changes, not a fault in the system: the classic cause is publishing a build while a broken template or bad draft is live.
Promote anyway (the escape hatch)
If a build is blocked and you’re confident it’s correct — for example, you deliberately deleted a third of the site — click Promote anyway on the dashboard (or, for scripted builds, CHINASKI_FORCE_PROMOTE=1 perl builder/build.pl):
- The guard is bypassed for that one build only; the next normal build runs the full checks again.
- The bypass does not refresh the quality baselines. This is deliberate: forcing bad numbers into the baseline would make the same regression “normal” and be ignored on future builds. The next regular build still compares against the last clean promotion, so the regression stays visible until it’s fixed.
- The dashboard’s bypass button appears only while a build is blocked; further checks stay active — the escape hatch is a one-shot, and the log records it.
Configuring the guard
| Setting (Settings → Workflow) | Field | Effect |
|---|---|---|
| Guard mode | Warn / Enforce / Off | Whether breaches warn or block |
| Page-drop threshold | percent | How many files a build can lose before the guard speaks |
| Broken-link increase | integer | Max growth vs last clean promote |
| Unresolved block markers | blank/number | Blank = gate off; a number (even 0) = hard limit on missing block embeds |
| A11y issue increase | integer | Max growth of accessibility issues vs last clean promote |
The thresholds are per-instance. If you’re seeing frequent warnings on a healthy site, check the breaches report first — the guard tells you exactly which gate tripped and by how much, and every threshold has a safe default that fits most sites.
Disabled-guard cases (promotes without comparison)
- Guard mode set to Off.
- A forced build (escape hatch above).
- The first build after a fresh start (nothing to compare against yet; the quality report is still produced).
- Broken-link and a11y deltas when no previous baseline exists (first build, or pre-dating databases) — those gates wake up as soon as a clean promote has stored baseline numbers.
Fine print
- The “page count” gate counts the files the build wrote, which includes small support files as well as content pages — so very small builds (three-page sites) have proportionally more sensitivity. The 80% default absorbs that.
- Incremental builds get the same guard as full ones: staging is a complete copy of the site either way, so counts remain comparable.
- The guard never changes the output itself — it can only advance or discard the staging copy.