Staged rollout: how to turn on filtering in slices

Enforcement does not have to begin everywhere at once. Choose a slice small enough that a mistake is recoverable and ordinary enough that success there tells you something about the rest. Everything else on this page follows from those two words: recoverable, and representative.

Section Operations Updated Start by path

Three ways to slice, and what each costs

The slice you choose decides what you can learn, not only what you risk.

By path. Enforce on one URL path and leave the rest observing. Attribution is unambiguous: anything that changes, changed there. The blast radius is a route you picked deliberately, and rolling back means touching one thing.

By rule. Enforce one group of rules everywhere and leave the others observing. Useful when a specific class of request is the reason you are doing this at all, and it answers a different question: what this rule does to your whole site rather than what your whole configuration does to one part.

By share of traffic. Enforce for a fraction of requests across everything. This is the one that looks most scientific and helps least at the start, because the effect is spread thinly across every route: a real problem appears as a small anomaly in many places rather than an obvious one in a single place, and the first thing you lose is attribution.

Start by path. Move to rule-level once you have a route where enforcement is uneventful, and treat share-based slicing as a way to widen at the end rather than a way to begin.

BY PATH ATTRIBUTION: UNAMBIGUOUS ANYTHING THAT CHANGED, CHANGED THERE BY RULE ATTRIBUTION: TO ONE RULE SET A DIFFERENT QUESTION, ANSWERED WELL BY SHARE OF TRAFFIC ATTRIBUTION: LOST A SMALL ANOMALY IN MANY PLACES AT ONCE, RATHER THAN AN OBVIOUS ONE IN A SINGLE PLACE
// the slice decides what you can learn, not only what you risk

Choosing the first path

Two rejections and one criterion.

Not the busiest route, and not the one that carries money. Both are the places where a surprise is most expensive, and neither is where you want to be learning what your rules do to your own content.

Also not something so unusual that nothing follows from it. A route nobody uses, or one whose traffic looks like nothing else on the site, produces a clean result that predicts nothing about the pages you actually care about.

The criterion between those rejections: the route should resemble what you will enforce on later. If your risk is people submitting text, pick a route where people submit text. If it is an API consumed by other systems, pick one of those. Representativeness is the whole reason for going first, and a slice that is not representative is a delay rather than a test.

What to watch, and for how long

Two signals, and the second is the one that catches what the first misses.

The record of refusals on the enforced route tells you what the rules are doing. Read it the way false positives describes, looking for refusals that sit inside otherwise ordinary sequences of requests.

The business signal for that same route tells you what the refusals cost. Completions of the form, orders through that path, successful calls from that integration: whatever the route exists to produce. For an API, that means watching the HTTP responses its callers receive rather than any page. This is the signal that notices the people who left without saying anything, and the time to agree on it is before enforcement starts rather than afterwards.

Watch for at least one full cycle of that route rather than for a fixed number of hours. A path used by staff behaves differently at the weekend; a checkout behaves differently on a payday; an integration that runs a nightly job produces nothing worth reading until the night it runs. The cycle, not the clock, decides when you have seen enough.

THE SAME FIXED WINDOW, THREE ROUTES A FIXED NUMBER OF HOURS STAFF PATH SEEN CHECKOUT PAYDAY MISSED SCHEDULED JOB THE NIGHT IT RUNS MISSED // the cycle, not the clock, decides when you have seen enough
// a route shows its real behaviour only across its own cycle

Expanding without losing the thread

One dimension at a time, and each expansion is a new first enforcement for a new population.

Widen the set of routes, or add the next group of rules, but not both in the same change. Two changes made together produce an outcome that cannot be attributed to either, and attribution is what the staging was for.

Each new slice deserves the same short watch as the first, though usually a shorter one, because by then you know which of your own content collides with which rules. What you carry forward is the list of exceptions built along the way, written calmly rather than during an incident, and each one dated as exceptions describes.

Deciding in advance what makes you stop

Write the rollback trigger down before you enforce anything, because afterwards it will be negotiated.

A usable trigger names an observation rather than a feeling: refusals on the enforced route rising without a matching change in traffic, the route's completions falling while comparable routes hold steady, or a single confirmed report from a real customer. Any one of those is enough. The purpose of writing it beforehand is that during the event, everybody's instinct is to wait a little longer and see, and that instinct is what turns a five-minute rollback into an afternoon.

Returning the route to observation is not a failure of the rollout. It is the mechanism working: you learned something at the cost of one route for one period, which is the price you agreed to pay when you chose to stage this rather than enable it everywhere.

Two timing rules. Do not begin during a peak period, since the point is to learn cheaply and a peak makes every lesson expensive. And do not widen enforcement immediately before a stretch when nobody is watching, such as a holiday or a weekend, because the failure mode of a bad expansion is silent and the people it affects will not wait for Monday.

What you have at the end

A configuration where each part was observed before it refused anything, and a record of what changed when.

That record is worth more than it looks. Reports about refused requests arrive days late, and the question they raise is always which change is responsible. A staged rollout answers it by construction: each step was one change, watched for one cycle, on one slice, with a trigger written down in advance.

Questions

Where should enforcement start?

On one route, chosen because it resembles the traffic you will enforce on later, and because a surprise there is affordable. Not the busiest path and not the one carrying money, since those are where a mistake costs most and where you least want to be discovering what your rules do.

How long should each stage run?

Long enough to cover a full cycle of that route rather than a set number of hours. A path used on weekdays, a checkout with a payday pattern, and an integration with a nightly job all need different durations, and each one shows its real behaviour only across its own cycle.

Can I enforce for a percentage of traffic instead?

You can, and it is a better tool for widening than for starting. Spreading the effect thinly across every route means a real problem shows up as a small anomaly in many places at once, which costs you the attribution that makes early stages worth running.

What if I have to roll back?

Return that slice to observation, keep everything you recorded, and treat it as the mechanism working rather than as a setback. Deciding the trigger beforehand is what makes this a quick decision instead of a debate held while the problem continues.

Where the platform sits

Returning a slice to observation is not a failure of the rollout. It is the mechanism working.

off

Nothing is inspected on that slice. The state to return to if something is badly wrong.

monitor

The slice is observed and recorded. This is where every stage begins and where a rollback returns.

block

The slice enforces. One change, one cycle, one trigger written down in advance.