ML Systems Lab Open interactive version →
Intermediate 29 min read A/B testingexperimentationtraffic splittingexposure logging

A/B Infrastructure

Traffic splitting, treatment assignment, exposure logging, interaction effects

A team runs an A/B test the simple way: even user IDs go to control, odd IDs to treatment. Three weeks later they realize their hashing put the *same* 15% of power users into treatment across all six experiments running at once. Those users saw six new experiences stacked on top of each other, and their behavior is now tangled up in all six at the same time. That's experiment interference, and it doesn't just complicate the reading — it structurally breaks all six results. The groups aren't comparable, the p-values aren't valid, and every decision made from them rests on corrupted evidence.


Why an A/B bug is scarier than a model bug: it hides behind real-looking statistics

A biased assignment still produces a p-value, a confidence interval, a tidy result summary — and every number in that chain is wrong. Nothing crashes, the experiment completes, and a decision gets made on bad data. That's why getting the infrastructure right isn't an implementation detail; it's the precondition for every statistical claim downstream.


The pieces that make assignment trustworthy

*Deterministic assignment* — hash(user_id + experiment_id) so a user always lands in the same bucket, making their events attributable. *Orthogonal splitting* — a different salt per experiment so simultaneous tests assign users independently and don't correlate. *An experiment registry* — tracks what's live and blocks conflicting experiments from overlapping. *Traffic ramp-up* — 1% → 5% → 20% → 50%, to catch bugs before full exposure. *Guardrail metrics* — automatic regression alerts that fire before anyone reads the primary metric.


One more piece, specific to testing ML model changes: latency and versioning. A new model is a new deployable, not just a new arm — before it ever sees production traffic, confirm it meets the latency SLA (a slower model changes the user experience by itself, independent of what it predicts), then run it through the same canary ramp (1–5% traffic) as any other change. Two details matter more here than in a generic A/B test: assignment must happen *before* the model runs, so a timeout or error in the challenger can't leak into which arm a request gets logged under; and every prediction must be logged with the exact model_version that produced it, or you can't tell which model's output actually rendered.


The single most important check: Sample Ratio Mismatch

You intended 50/50 and observed 52/48 — each arm is 2 percentage points off its target. That is *not* noise — it's the fingerprint of a systematic bug in assignment or logging. SRM is measured with a χ² test on the raw split, not by eyeballing the percentages: run it *before* you open any metric dashboard, and treat any split the test flags as statistically significant — a split like 52/48 fails it decisively at any real sample size — as disqualifying. Once SRM is flagged, every downstream comparison is invalid no matter how significant it looks; there is no valid analysis to do until the root cause (hashing, bot filtering, logging) is found and fixed.


A second, different kind of interaction effect: network effects between arms, not within them. Experiment interference (above) is the same user landing in multiple experiments. A SUTVA violation is different — SUTVA (the Stable Unit Treatment Value Assumption: one unit's outcome shouldn't depend on which treatment other units received) is broken here, because treatment leaks across arms through the system itself. In a marketplace test where treated sellers get a new dashboard, control buyers still interact with those treated sellers, so control buyer behavior shifts even though no control user was ever treated. Control and treatment are no longer independent populations, and a metric computed as if they were misstates the true effect. Detect it by watching guardrail metrics in the arm that received no treatment; mitigate it with geo- or marketplace-cluster randomization, so a whole region or seller cluster sits in one arm instead of mixing treated and control counterparties in the same market.


And for the long view: holdout groups. Permanently hold 5–10% of traffic out of *all* experiments and compare production against it over time. This catches novelty effects — the wins that look great in a two-week test but fade once the shine wears off — and shows the true cumulative impact of your ML work. All of this is why "A/B testing is just feature flags and if/else" misses the point: the flag is the mechanism; everything above is the safety system that makes the mechanism produce answers you can trust.

Key points

Takeaway

A biased assignment generates a p-value, a confidence interval, and a recommendation — every number in the chain is invalid, no alarm fires, and there is no statistical correction for a compromised experiment.

Recap

Check your understanding

Q1. An A/B test with an intended 50/50 split shows 52% of unique users in treatment, 48% in control. Select the two correct responses.

Q2. Your A/B test shows a 5% lift in click-through rate. The experiment ran for 3 days. What validity threats should you consider before claiming the win?

Q3. How do you design an A/B infrastructure for testing ML model changes when models have different computational costs and serving latency?

Q4. A marketplace A/B test treats seller-side UI (treated sellers get a new dashboard). Control sellers are unaffected. But analysis shows control buyer behaviour also changed. What is happening?

Try it interactively

ML Systems Lab is a free interview-prep platform for ML engineers — work through the full interactive module, quizzes, and drills.

Open ML Systems Lab →