Shadow deployment (a "dark launch") sends a copy of every N-th production request to a candidate model running alongside the live one. The candidate's prediction is logged and compared, but its output is never returned to the user — the response the user actually sees always comes from the production model. This is the key difference from canary rollout: canary risks real users on the new model as its traffic share ramps up; shadow deployment risks nothing, because the candidate's answers are pure telemetry.
mirror(request) = true with probability s (sampling rate)
agreement_rate = agreements / (agreements + disagreements)
shadow_latency ≈ prod_latency × overhead_factor
Because shadow traffic is compute you pay for without serving it, teams tune the sampling rate to trade statistical confidence in the agreement estimate against extra infrastructure cost — 100% mirroring gives the tightest estimate but doubles (or more, times the overhead factor) the compute bill for the candidate.
- Request rate — how often the client sends production traffic.
- Shadow sampling rate — the fraction of requests forked to the shadow model.
- Candidate disagreement rate — how often, in this scenario, the shadow model's prediction would differ from production's (the thing you're trying to measure in real MLOps, imposed here as ground truth to demonstrate the mechanic).
- Shadow compute overhead — the candidate model's relative latency; shadow inference frequently runs slower because it competes for the same GPU/CPU pool as production.
Once the agreement rate and latency overhead look acceptable over enough mirrored traffic, teams typically graduate the candidate to a canary rollout — shadow deployment is the risk-free step before any real user ever sees the new model's output. The rolling chart below tracks the agreement-rate estimate converging as more mirrored traffic accumulates; the bar panel compares average production vs. shadow latency and the mirrored-vs-direct traffic split.