search_ads_recsys / 33 · A/B testing deep dive lesson 33 / 39

A/B testing deep dive - from algorithm change to launch decision

The book treats A/B testing as the bridge between offline model quality and real business impact. This lesson linearizes that material: define the decision, build the metric hierarchy, randomize traffic correctly, verify the experiment, analyze segments, diagnose offline-online mismatch, and only then decide whether to ship.

Book anchors
Based on the book's A/B and evaluation questions: 1.3.2 A/B testing for recommendation, 1.5.1 online tests for multi-objective ranking, 2.2.2 high offline AUC but weak online A/B, 6.8.5 feature-value experiments, and 22.4.3/22.5.1 short-video A/B diagnostics.
Metric prerequisite
This lesson uses short-video metrics as examples before lesson 34 expands them. The experiment logic is independent: pick a primary metric, guardrails, and diagnostics. If terms like VTR, fast-swipe, completion, and creator exposure are unfamiliar, read lesson 34 immediately after this and then revisit the launch-rule section here.

1 · The experiment is a causal instrument

An A/B test is not a dashboard comparison. It is a controlled intervention: one population is served the old policy, another comparable population is served the new policy, and the metric difference is attributed to the policy change after randomization removes most confounders.

algorithm idea │ ▼ offline validation │ ▼ A/A test and logging check │ ▼ small A/B canary │ ▼ full A/B with primary metric + guardrails │ ▼ ship / rollback / segment launch / iterate

The book's recurring answer shape is simple: name the core business metric, split users by a stable hash, keep the control and treatment isolated, run long enough for significance, and analyze the result by user group and content group. The important upgrade is to treat that as a causal design, not as a statistical ritual.

2 · Start with the launch decision

Before choosing metrics, write the launch rule in a sentence. This prevents metric shopping after the test starts.

launch rule example Ship ranker B if per-user watch time rises by at least 0.5%, retention is not worse, crash/latency guardrails remain green, creator exposure does not collapse, and the lift is stable across new users, active users, regions, and major content categories.
Metric roleQuestion it answersShort-video example
Primary metricShould we ship?Per-user watch time, per-user effective watch time, D7 retention
Secondary metricsWhy did it move?CTR, completion, like/share/follow rate, session depth
GuardrailsWhat harm vetoes launch?Crash rate, latency, report rate, negative feedback, diversity, creator exposure
DiagnosticsWhere did it move?New vs old users, high vs low activity, region, device, content vertical

The book often names per-capita viewing time as the first-level metric for short-video ranking, with CTR, completion, and interaction as supporting metrics. Keep that hierarchy explicit: CTR is often a process signal; retention and durable watch behavior are closer to user value.

3 · Randomize at the right unit

The default split for a personalized recommender is user-ID hash bucketing. The reason is educationally important: one user sees many impressions, so impressions from the same user are correlated. If users are randomized but impressions are analyzed as independent rows, variance is understated and false positives become easy.

SurfaceTypical randomization unitWhyRisk
Short-video feedUser IDStable feed experience and correlated repeated sessionsNew-user mix imbalance
Search rankingUser or query sessionDepends whether personalization carries across queriesLow power for rare queries
Marketplace rankingUser, seller, or clusterDemand and supply interfereShared inventory spillover
Ads rankingUser, advertiser, query, or auction cellBudget and bidding loops react to treatmentPacing spillover

Use stratification when traffic is heterogeneous. The book explicitly calls out user groups such as new and old users; in practice add region, device tier, activity level, and content category. Stratification is not a license to hunt for a lucky slice. It is a way to balance important populations and interpret heterogeneous effects.

When you read many objectives and many slices, control the false-positive budget. The book mentions multi-test correction in multi-objective experiments; practically, pre-register the primary metric, mark slices as diagnostics unless powered, and use Bonferroni/FDR-style correction when you intend to make claims across many simultaneous tests.

3.1 · Switchback experiments when interference is market-wide

User-ID hashing assumes one user's treatment does not change another user's outcome. That assumption breaks when treatment and control share a finite resource. The clearest case is ads: pacing and budget loops (lesson 10) spend against a daily cap. If treatment users get a more aggressive bid policy, they exhaust the same advertiser budgets faster, so the control arm sees cheaper inventory it would never have seen at full traffic. The auction (lesson 9) is a single clearing market: both arms compete for the same slots. Marketplace supply/demand and two-sided liquidity have the same shape. Here cluster randomization does not help — the unit of interference is the whole market, and you cannot cut the market into independent clusters.

The fix is to randomize time instead of users. A switchback (time-split) experiment flips the entire system between policy A and policy B on a fixed time grid. In any window everyone sees one policy, so within-window there is no cross-arm leakage; the contrast comes from comparing A-windows against B-windows. The window — not the user — is the i.i.d. analysis unit.

switchback schedule: 48 windows of 30 min over 24h, A/B alternating 00:00 A 02:00 B 04:00 A 06:00 B 08:00 A 10:00 B ... 00:30 B 02:30 A 04:30 B 06:30 A 08:30 B 10:30 A 01:00 A 03:00 B 05:00 A 07:00 B 09:00 A 11:00 B 01:30 B 03:30 A 05:30 B 07:30 A 09:30 B 11:30 A ▲ randomize the ORDER (block- or Latin-square-balanced across hour-of-day so neither policy gets all the prime-time windows)

The carryover hazard. Time windows are not independent the way users are: a policy active in window k changes state that bleeds into window k+1 — budgets already spent, pacing controllers mid-correction, a user mid-session. This is temporal autocorrelation, and it biases the naive contrast. The standard guard is a washout window: discard the first slice of each window after a switch and analyze only the settled tail.

Worked switchback: washout cost and effective sample

Schedule: 24h × 30-min windows = 48 windows/day, balanced A/B. Pacing controllers settle in roughly 10 min after a flip, so set a 10-min washout per window.

usable fraction / window
20 / 30 = 67%
windows over a 7-day run
48 × 7 = 336
effective analysis units / arm
168
data thrown to washout
33%

You pay a third of your data to kill carryover, and your N is 336 windows, not millions of users — so switchback tests are under-powered per day and run longer. Shorter windows recover units but raise the carryover-to-signal ratio (more flips, more washout per hour); longer windows cut carryover but cost windows. The 20-to-60-min band is the usual compromise: long enough that the 10-min washout is a minority of the window, short enough to log hundreds of windows in a week.

Interference sourceDoes user-hash work?Does clustering work?Use
None (isolated per-user)Yesn/aStandard user-ID A/B
Social graph spilloverNo (friends leak)Yes (graph clusters)Cluster randomization
Shared budget / auction / supplyNoNo (one market)Switchback (time-split)

4 · Prove the experiment system works before reading lift

Run an A/A test or logging-only test before the real A/B when the experiment platform, metrics, or new instrumentation changed. The goal is to prove that two identical policies produce statistically indistinguishable metrics and that sample allocation matches the planned split.

  1. Assignment check: treatment and control counts match the target split; no sample-ratio mismatch.
  2. Profile balance: user activity, region, device, and new-user share are similar across buckets.
  3. Instrumentation check: exposure, play, click, watch-time, and negative-feedback events are logged identically.
  4. Metric sanity: historical baselines line up; no sudden schema or unit changes.
  5. Isolation check: users do not switch buckets across devices or sessions.
Sample ratio mismatch
If a 50/50 test receives 49.1/50.9 traffic without explanation, stop and debug. The bug may be assignment, eligibility, logging, filtering, or a treatment crash that prevents events from being recorded.

4.1 · Balance diagnostics with a numeric threshold

"Profile balance" needs a pass/fail number, not eyeballing. For each pre-experiment covariate (prior watch time, activity tier, region, device, new-user share), compute the standardized mean difference between arms:

SMD = ( x̄T − x̄C ) / √( ( sT² + sC² ) / 2 )

SMD divides the raw gap by the pooled spread, so it is unitless and comparable across covariates. The industry pass criterion is SMD < 0.1 on every covariate. Unlike a t-test p-value, SMD does not shrink as N grows — at billion-user scale a trivially small mean gap is "significant" by p-value yet harmless by SMD, so SMD is the right balance gauge.

Worked SMD

Prior 7-day watch time: control mean 42.0 min, treatment 42.9 min, pooled SD 30 min.

SMD = (42.9 − 42.0) / 30 = 0.9 / 30 = 0.030 — below 0.1, so this covariate is balanced even though a t-test on tens of millions of users would call the 0.9-min gap "highly significant." Now device tier: control 55% high-end, treatment 61%, pooled SD √(0.58·0.42) ≈ 0.494, so SMD = 0.06 / 0.494 = 0.121 — over the line. That arm-imbalance, not the algorithm, could explain a watch-time lift, so re-randomize or CUPED-adjust on device before reading the result.

Pre-experiment knobSettingFailure it prevents
Balance criterionSMD < 0.1 per covariateConfounded arms read as a fake lift
Hash-salt rotationNew salt per experimentSame users always in treatment → cumulative cross-experiment bias and "lucky-bucket" carryover
Platform-split hashingiOS and Android bucketed independentlyOS render/behavior gaps leaking into the arm contrast
Warmup (burn-in) windowDrop first 24h–72hModel-warmup + novelty transients polluting steady-state metrics

The salt point is subtle and senior-level: if the bucketing hash uses a fixed seed, the same users land in treatment for every experiment forever, so their idiosyncrasies accumulate as a standing bias and any one test inherits the residue of the last. Rotating the salt per experiment re-shuffles the population so each test gets a fresh independent draw.

5 · Power the test around an effect worth shipping

The book mentions minimum sample size and significance tests. The production interpretation is: decide the smallest effect that is worth changing the product, then compute whether the test can detect it.

power inputs baseline mean and variance + minimum detectable effect + alpha, usually 0.05 + desired power, often 80%+ + traffic allocation = users and days required

If the smallest meaningful lift is 0.5% watch time, do not celebrate a 0.03% statistically significant CTR lift that does not move watch time or retention. Statistics answers "is this likely noise?" Product judgment answers "is this worth shipping?"

5.1 · Significant but trivial: effect size, ROI, and the p=0.06 protocol

At hundreds of millions of users, N is so large that the standard error σ/√N collapses, so p<0.05 is nearly guaranteed for almost any non-zero effect. Significance becomes a noise filter that everything passes; it stops being a value test. Report two things alongside p.

1. Effect size (Cohen's d) — the lift in pooled-standard-deviation units, free of N:

d = ( x̄T − x̄C ) / spooled

Worked Cohen's d

Watch time: control 42.0 min, treatment 42.21 min (a +0.5% lift), pooled SD 30 min. d = 0.21 / 30 = 0.007. By Cohen's bands (0.2 small, 0.5 medium) this is vanishingly small per user — yet across 200M users it is real money. d tells you the per-user experience barely changes; the business case rests entirely on scale, not on individual impact. State both so reviewers are not fooled by a 12-zero p-value.

2. ROI of the lift — pair the gain against the serving cost it demands (extra GPU/latency from a heavier model):

Worked cost-per-0.1%-lift
measured lift
+0.5% watch time
annual value of +0.5%
$5.0M
value per +0.1%
$1.0M
added serving cost
$1.2M / yr

The new ranker raises p99 latency and needs ~30% more inference GPUs — say $1.2M/yr. The lift is worth $5.0M/yr, so net +$3.8M: ship. Flip the model: if a heavier candidate cost $1.2M/yr to serve but moved watch time only +0.1% ($1.0M), it is significant and net-negative — reject on ROI, not on p. This is the "every 0.1% of metric costs X servers" calculation that separates a statistician from an engineer.

3. The p=0.06 protocol. A 5% lift with p=0.06 is not a rejection — p=0.06 still says the data favor the treatment, it just clears α=0.05 by a hair. Binary thresholding here throws away a likely-good change (a Type II error). Instead:

borderline p (0.05 < p ≤ 0.10) decision tree ┌─ extend the run → underpowered? more N may push p < 0.05 ├─ segment → is the effect concentrated in a sub-group │ that IS significant on its own? ├─ check guardrails → do retention / negative-feedback agree in sign? └─ gray-launch → if ship cost + risk are low, roll out small and keep measuring rather than reject outright

The engineering line: a p-value is a continuous strength-of-evidence signal, not a yes/no gate. Treat 0.06 as "promising, under-powered" and buy more evidence; do not let an arbitrary 0.05 cliff discard a 5% lift.

6 · Analyze multi-objective tests as a metric graph

A recommender rarely optimizes one target. The book's multi-objective A/B section suggests first-level metrics such as per-user watch time and second-level metrics such as CTR and completion. Think of these as a graph of mechanisms:

CTR │ ├── can raise watch time if clicks become satisfying views └── can lower watch time if clickbait increases fast exits completion │ ├── can show content fit └── can be inflated by short videos interaction │ ├── can show deep engagement └── can be sparse, polarizing, or creator-biased

Read the graph in a fixed order. Primary metric first. Guardrails second. Mechanism metrics third. Segments fourth. A treatment where CTR rises but per-user watch time falls is not a win; it is a clue that the model found shallow attraction rather than durable satisfaction.

7 · Diagnose offline-online mismatch

The book repeatedly asks why offline metrics improve but online A/B does not. This is one of the highest-yield interview topics. The linear diagnosis is:

CauseWhat it looks likeWhat to check
Metric mismatchAUC improves; watch time does notWhether offline label matches business objective; add GAUC, NDCG, completion, retention
Distribution shiftOffline data lacks fresh trendsTime-window split, hotspot videos, new-user share, recent app versions
Feature freshness gapOffline model uses features unavailable onlineTrain-serve parity, online feature coverage, latency, stale values
Selection biasModel wins on previously exposed items onlyExposure policy, position bias, IPS/replay limits, exploration pool
System effectsSingle model win disappears after rerank/mixRecall, rank, rerank, diversity, business rules, UI interactions
Bad experiment designNo significant lift despite plausible model winPower, duration, bucket balance, novelty effects, interference

A strong answer does not say "offline is unreliable." It says exactly which assumption broke: static data, wrong target, stale features, biased logs, short duration, or system-level interaction.

When a conventional A/B test is too blunt or impossible, use the book's alternative evaluation tools. Interleaving can be more sensitive when two rankers are both strong and you need preference signal from the same user context. DID/quasi-experiments can help when a full randomized launch is infeasible, such as a regional policy or UI change, but they require stronger assumptions and careful pre-trend checks.

7.1 · The causal toolbox when randomization is impossible

Sometimes you cannot randomize at all: the change shipped to 100% of users, it is a region-level policy, or assignment is decided by a business rule, not a coin. The evaluation lesson (lesson 8) covers the estimation/analysis side of these tools (IPS, doubly-robust, the variance math); this lesson owns the design choice — which method the assignment mechanism forces on you. Pick by how treatment was assigned:

Assignment situationMethodMechanism (design side)Key precondition
Assigned by a threshold/cutoff ruleRDD (regression discontinuity)Compare units just above vs just below the cutoff; near the line, which side you fall is as-good-as randomNo other jump at the cutoff; enough density around it
Observational, confounders all observedPSM (propensity-score matching)Model P(treated | covariates), match treated to control with equal scores so groups look randomized; also a balance toolNo unobserved confounder (ignorability); overlap in scores
Observational, many covariates, want low biasDouble MLTwo ML stages fit the nuisances (propensity + outcome), then a debiased/orthogonal score isolates the effect; the modern observational standardCross-fitting; same ignorability as PSM, but robust to flexible nuisance models
An unobserved confounder existsIV (instrumental variable)Find an instrument that shifts treatment but touches the outcome only through treatment; use only that exogenous variationInstrument relevant & excludable (only path to outcome is via treatment)
Before/after, treated vs untreated groupDID (difference-in-differences)Subtract each group's own before→after change, cancelling fixed group gaps and common time trendsParallel trends: absent treatment, both groups would have moved in parallel — validate on the pre-period
Want which segments benefitUplift / causal forestEstimate the heterogeneous treatment effect per unit/segment instead of one averageEnough data per segment; honest splitting
DID's load-bearing assumption
DID is only valid if the two groups were on parallel trends before treatment. Always plot the pre-period: if treated and control were already diverging, DID will mislabel that drift as the treatment effect. A clean pre-trend is the design check that makes the method honest — never quote a DID number without it.

7.2 · Neyman allocation: send traffic to variance, not headcount

Stratification (Section 3) balances populations; it does not say how to split traffic across strata. The default is proportional — allocate each stratum traffic equal to its share of users. That is not power-optimal. The standard error of the overall mean is driven by the noisy strata, so the variance-minimizing split — Neyman allocation — over-samples high-variance strata:

nh / n  ∝  Wh · σh

where Wh is stratum h's population share and σh its outcome standard deviation. Proportional allocation is the special case where every σh is equal. Low-activity users have the widest watch-time variance, so they deserve more traffic than their head-count implies.

Worked Neyman allocation

Two strata. Heavy users: 70% of population, watch-time σ = 10 min. Light users: 30% of population, σ = 40 min (sparse, erratic — far noisier).

StratumWhσhW·σProportionalNeyman (∝ W·σ)
Heavy0.70107.070%7.0 / 19.0 = 37%
Light0.304012.030%12.0 / 19.0 = 63%

Proportional sends 30% of traffic to light users; Neyman sends 63% — because that stratum holds most of the total variance, and each extra sample there buys more variance reduction than a sample among the placid heavy users. Same total N, smaller SE on the global estimate, so you hit your MDE sooner. The cost: per-stratum read on heavy users is now thinner, so only over-allocate when the global effect is the decision metric.

Cluster-robust standard errors. One more variance subtlety tied to the design unit. You randomize by user-ID hash, but you often analyze per-impression rows — and a user's impressions are correlated. Treating those rows as independent understates the SE and manufactures false significance (the same trap Section 3 named). The fix is cluster-robust SEs, clustering at the randomization unit (the user, or the time window in a switchback). The variance inflation is roughly 1 + (m̄ − 1)·ρ, where is impressions per user and ρ the within-user correlation: with m̄ = 50 impressions and ρ = 0.2, the true variance is 1 + 49·0.2 ≈ 10.8× the naive value — a p-value off by an order of magnitude if you ignore clustering.

8 · Decide with long-term effects in mind

Short-video systems can win day-one watch time and lose week-two trust. The book explicitly warns about short-term versus long-term effects: over-exploitation can raise per-user time while damaging retention or satisfaction. Use a ladder:

experiment ladder A/A test -> 1% canary for safety and logging -> 5-20% A/B for mechanism metrics (drop the 24h-72h warmup window) -> long holdout for retention, creator ecosystem, fatigue -> staged rollout with rollback thresholds

Note the warmup (burn-in) window on the A/B rung: the first 24h–72h carry model-warmup and novelty transients that are not the steady-state effect, so they are dropped before the metric read — the same discipline as a switchback's washout, applied to the run as a whole.

For high-risk ranking changes, keep a small long-term holdout. The goal is not to block innovation forever; it is to learn whether the feed is creating durable value or just harvesting attention.

Interview prompts you should be ready for

  1. "Design an A/B test for a new short-video ranker." Answer with launch rule, user-ID hash split, AA test, primary watch-time metric, secondary CTR/completion metrics, guardrails, sample size, duration, segment reads, multiple-testing discipline, and rollback rules.
  2. "Offline AUC is high but A/B is flat. Why?" Walk through metric mismatch, distribution shift, feature freshness, selection bias, system effects, and experiment power.
  3. "CTR rose but per-user watch time fell. What happened?" The treatment may have optimized shallow clicks or clickbait. Inspect completion, fast exit, content type, user segment, and retention.
  4. "How do you test a new feature such as swipe speed?" Run offline ablation/SHAP/permutation checks, then an online A/B with the feature added and all else fixed; evaluate watch time, CTR, coverage, latency, and long-term guardrails.
  5. "You changed the ads bid/pacing policy and a user-split A/B shows a flat lift. Is the policy useless?" No — user randomization is invalid here: both arms share advertiser budgets and one auction, so treatment cannibalizes control's inventory and the contrast is contaminated. Re-run as a switchback (alternate the whole system on a 30-min grid), analyze at the window level with a washout to kill carryover, and use cluster-robust SEs on windows.
  6. "The new ranker is p<0.001 with a +0.4% watch-time lift. Ship it?" Not on p alone. Report Cohen's d (likely ~0.01 — trivial per user; the case is pure scale) and the ROI: value of +0.4% vs the extra serving cost of the heavier model. If the +0.4% is worth less than the GPU/latency it demands, it is significant and net-negative — reject. Also confirm SMD<0.1 balance so the lift is not a confounded arm.
Takeaway
The book's experiment logic becomes one linear rule: decide first, randomize cleanly, verify assignment and logging, power for meaningful lift, read metrics hierarchically, segment responsibly, diagnose offline-online gaps, and ship only when business value and guardrails agree.