Appendix A - 8. Staged deploy gates (canary → smoke → promote)

The Structure of Staged deploy gates (canary → smoke → promote) — its shape at a glance:

The pipeline is a staircase: a cheap pre-launch predicate gates the whole thing, then a canary takes no traffic, smoke tests it against its own URL, and promotion happens only on green.

flowchart LR
  Pre{Pre-launch green?} -->|no| Skip([Never start])
  Pre -->|yes| Canary[Deploy canary, no traffic]
  Canary --> Smoke{Smoke passes?}
  Smoke -->|no| Block([Promotion blocked])
  Smoke -->|yes| Promote([Promote to production])

Accessible description: a pre-launch predicate gates the deploy; if green a canary revision is deployed taking no traffic and smoke-tested against its own URL, and promotion to production happens only when the smoke stage passes, otherwise promotion is blocked.

Projected from the catalogue entry gates-and-merge-train / Staged deploy gates (canary → smoke → promote).

On this page: Intent · Motivation · Applicability · Structure · Sample Code · Consequences · Example use within DocAble · Related Patterns

Intent

Intent — A deploy pipeline that escalates canary → smoke → promote, blocking promotion to production until each cheaper stage passes on a traffic-free revision, so a bad build is caught before users see it, not after.

Motivation

Shipping a build straight to production means a regression lands on users; the failure is the incident. This is standard practice everywhere, but it matters far more at agentic velocity, precisely because deploys are frequent and agent-initiated: the more often you ship, the more often an un-gated bad build reaches users.

Applicability

Structure

The Structure diagram appears at the top of this page.

Sample Code

The deploy is a staircase of gates, each cheaper than the next stage it guards. The pre-launch predicate avoids paying build minutes for a doomed deploy; the canary and smoke gates catch a break on a revision no user can reach.

def staged_deploy(pre_launch_green, build, deploy_canary, smoke, promote) -> int:
    if not pre_launch_green():           # cheapest gate: lints green, no known flaky class, changed-set clean
        print("pre-launch predicate red — not starting"); return 0
    artifact = build()
    canary = deploy_canary(artifact)     # a revision taking NO production traffic
    if not smoke(canary.url):            # exercise the canary's own URL with real dependencies
        print("smoke failed on canary — promotion blocked"); return 1
    promote(canary)                      # only a green canary reaches users
    return 0

Consequences

Example use within DocAble

Contents
© James C. Davis, 2026–present