Authenticating...
Skip to main content

Ship / Show / Ask: A Lighter PR Review Process

Campaign Delivery's branching + review strategy, adapted from Martin Fowler's Ship/Show/Ask and piloted on ad-suite since June 2026. Every PR still goes through a pull request — that stays our record of what changed and why — but the label on it decides how much review has to happen before it merges, instead of every PR defaulting to the same review weight regardless of risk.

The problem it solves​

Before this, every PR waited on review the same way, whether it was a one-line config fix or a new integration with a third-party API. Small, obviously-safe changes sat in queues for hours or days next to changes that actually needed scrutiny — reviewer attention is a shared, limited resource, and treating every PR as equally risky spends it on the wrong things.

The three levels​

LabelMeaningUse when
ShipNo review needed. Merge as soon as other required checks pass.Established patterns, routine, low blast radius — docs, config, a small self-contained fix.
ShowNo need to wait on review; merge, feedback comes after.Correct and low-risk but worth visibility — a refactor, an interesting fix, a new-ish pattern.
AskHolds for review before merge.Migrations/schema changes, auth/authorization, CI/infra changes, a new architectural pattern, or external side effects (creating records, sending notifications, third-party writes) — or just when you're unsure.

The level is about the change's actual risk, not its Conventional Commits type — a feat can be a Ship, a fix can be an Ask. When torn between two levels, pick the higher one.

Merging itself is always a separate, explicit action for every level — nothing here auto-merges. Ship/Show just means nothing is blocking the merge; someone still has to click the button.

What it's actually bought Campaign Delivery​

  • A PR that used to take ~2.5 days to get approved — the data point that made the case for piloting this in the first place — is exactly the kind of change that should be a Ship.
  • A backfill Airflow DAG went from decision doc to production in about a week using Ship/Show, with review happening in parallel instead of gating each step: "I can imagine that if [it] had actually [been] reviewed very diligently, we would be still here hoping it would be merged."
  • Zero incidents traced back to a Ship/Show PR that should have been an Ask — the auto-Ask triggers (migrations, auth, infra, external side effects) have held so far.

How this actually gets enforced (not just convention)​

Labels alone are a convention — nothing stops someone from merging an unreviewed Ask PR by accident, or on purpose. Since Sep 2026, ad-suite enforces the Ask half with two small, portable pieces:

  1. A CODEOWNERS catch-all (.github/CODEOWNERS): * @your-team at the top of the file (must be first — CODEOWNERS is last-match-wins, so a catch-all placed after more specific rules would silently override them). This gives GitHub someone to suggest as a reviewer on everything; it doesn't by itself require anyone's approval.
  2. A label-gated required status check (.github/workflows/check-ask-label.yml): fails when a PR carries the Ask label and has no approving review from someone other than the author, or has an unresolved CHANGES_REQUESTED. Ship, Show, and unlabeled PRs pass immediately — this check has zero effect on them. Added to the branch ruleset's required status checks so it actually blocks merge, not just reports red.

Why not GitHub's native "require review from code owners" setting: that rule applies to every PR uniformly — there's no way to scope it to just Ask-labeled PRs. Turning it on would force a second reviewer onto every Ship PR too, defeating the entire point of the label. A label-gated Actions check is the only mechanism that can express "review only when Ask." Full reasoning: ad-suite decision record 013.

Known limitation, left open on purpose: repo admins carry a standing bypass on most branch rulesets, so this check is binding for the team but an honor-system gate for admins. Worth knowing before you assume it's airtight.

Bringing this to your team​

  1. Create the three labels — Ship, Show, Ask — and agree on the auto-Ask triggers for your repo (start from the list above; migrations and auth are close to universal, infra paths will differ per repo).
  2. Add a CODEOWNERS catch-all for your team, following the last-match- wins ordering note above if you already have more specific rules.
  3. Copy check-ask-label.yml from ad-suite's .github/workflows/ — it's self-contained (no dependency on a shared reusable workflow), so it drops into any repo as-is.
  4. Add the check to your branch ruleset's required status checks. It has to have reported at least once before GitHub will let you select it as required — open one throwaway PR first if needed.
  5. Write down the convention for your repo — see ad-suite's docs/ship-show-ask.md as a template for what contributors need to know.

Reference implementation​

Questions: ask in #team-engineers or reach out to Ben Giese (Campaign Delivery), who piloted and maintains this on ad-suite.