A/B Test Design & Statistical Rigor Questions
Designing and statistically defending a controlled online experiment: framing a testable hypothesis, defining control and treatment variants, choosing the randomization unit, setting the primary success metric, and computing sample size, power, and minimum detectable effect. Covers the statistical foundations that make a readout trustworthy, including hypothesis testing, p-values, confidence intervals, statistical vs practical significance, and Type I/II error. Emphasizes avoiding the common pitfalls that invalidate a test, such as peeking, multiple-comparison inflation, underpowered designs, and how test duration and stopping rules affect the validity of conclusions.
You are defining metrics for a new product experiment. Explain the difference between a primary metric and a guardrail metric, and how a guardrail differs from a secondary metric. For a monetization change such as a new ad placement or premium feature, propose one primary metric and at least three guardrail metrics, and for each guardrail specify the direction of harm you are watching for and the minimum threshold that would make you pause or roll back the test.
Sample Answer
Direct answer
The primary metric is the single metric that answers "did this change achieve its intended goal," and it is what the ship decision is nominally based on. Guardrail metrics are metrics you are not trying to improve, but are watching to make sure the change does not cause unacceptable harm elsewhere; a guardrail regressing can override a primary metric win. A secondary metric is different from both: it is additional signal you are curious about or want to understand mechanism through, but a secondary metric moving in a bad direction does not, by itself, block a ship decision the way a guardrail breach does. The distinction that matters operationally is that guardrails carry a pre-committed threshold and a pause-or-rollback consequence; secondary metrics do not.
Structured elaboration
Primary vs. guardrail vs. secondary
| Primary | Guardrail | Secondary | |
|---|---|---|---|
| Purpose | The thing you're trying to move | The thing you must not break | Additional context / mechanism |
| Pre-committed threshold | Yes, the success bar | Yes, the harm bar | Usually not |
| Can it block a ship? | It's the basis for shipping | Yes, on breach, regardless of primary result | No, on its own |
| Typical count | One | A handful (three to five is common) | As many as useful |
An equivalent framing some teams use is proximal vs. distal metrics: a proximal metric sits close to the mechanism of the change (click-through rate on a redesigned button) and moves quickly; a distal metric sits further downstream (long-term retention, lifetime value) and moves slowly but is closer to what the business actually cares about. A guardrail is frequently a distal metric precisely because the harm you are worried about (retention erosion, trust damage) is often slower to appear than the primary win.
Worked proposal for a monetization change (new ad placement)
Primary metric: net revenue per user in the experiment arm. Direction of success: increase. This is the metric the change exists to move.
Guardrail 1: 7-day retention. Direction of harm: decrease. Rationale: an intrusive placement can drive short-term revenue while quietly eroding the reason people come back. Pause/rollback trigger: agreed in advance as a stated relative-drop threshold with the confidence interval's upper bound also below zero (i.e., not just a point estimate dip that could be noise), reviewed before rollout, not chosen after seeing the result.
Guardrail 2: core-task completion rate (the product's main non-monetization action, e.g., completing a search, finishing a checkout, reading an article to completion). Direction of harm: decrease. Rationale: an ad placement that visually or functionally interferes with the primary task is trading long-run product health for short-run revenue.
Guardrail 3: user-initiated complaint or ad-block/opt-out rate. Direction of harm: increase. Rationale: a direct, unambiguous signal of user tolerance that is available faster than retention, useful as an early-warning guardrail even before the retention window has fully played out.
Guardrail 4 (optional, if the surface has one): page load or responsiveness regression, since an added placement can degrade performance in a way that suppresses every other metric indirectly; direction of harm: increase in load time or error rate.
This maps onto the same structure whether you are testing an ad placement, a checkout-flow revenue change (where the natural guardrail set expands to include cart-abandonment rate and support-ticket volume), or a premium-feature paywall (where conversion rate is typically the primary, and DAU, ARPU, and system error rate sit alongside it as guardrails against gating too aggressively or destabilizing the product). The framing also transfers outside pure monetization: for a conversational AI product's response pipeline, the primary might be task-completion rate while the guardrails are safety and quality signals such as a harmful-response rate or an unresolved-escalation rate, because the mechanics of "one thing you're optimizing, several things you refuse to let break" do not change with the domain.
Setting the threshold, not just naming the metric
A guardrail without a pre-committed threshold is not actually a guardrail, it is a chart someone glances at. The threshold should be set from business tolerance for harm (how much retention erosion is worth this much revenue) agreed before the experiment starts, not derived by re-deriving statistical power mid-flight; whether the observed guardrail movement is distinguishable from noise at that threshold is a separate, purely statistical question the analysis answers once data is in, not something this design step needs to resolve.
Worked example
A checkout-flow revenue experiment adds a one-click upsell at the payment step. The team pre-commits four guardrails before launch: cart-abandonment rate (harm: increase), 7-day repeat-purchase rate (harm: decrease), support-ticket volume tagged "checkout confusion" (harm: increase), and page load time at the payment step (harm: increase). Two weeks in, revenue per session is up and three of the four guardrails are flat, but cart-abandonment is up beyond the pre-committed trigger. Because the threshold and the pause rule were set before launch, the team pauses the rollout to investigate the upsell's placement rather than debating in the moment whether the abandonment increase is "bad enough" to matter.
Trade-offs and pitfalls
- Naming too many guardrails dilutes the signal and invites false alarms purely from checking many metrics at once; a handful of well-chosen, harm-specific guardrails beats a long generic list.
- Do not let a metric quietly slide from "secondary" to "guardrail" after the fact because it happened to move in a bad direction; that is choosing your rules after seeing the data, which defeats the purpose of pre-committing thresholds.
- A guardrail with no pre-committed threshold is not enforceable in the moment it matters; agree on the trigger, and who has authority to invoke it, before the experiment ships.
You ran an A/A test and observed a 7% difference in conversion between the two identical groups with p=0.04. List the possible explanations for this surprising result, such as a broken hashing or salt scheme, covariate imbalance from a logging bug, or a genuinely low-probability chance event, and outline the concrete diagnostics you would run, in order, to determine which explanation is correct and what you would do next.
Sample Answer
Direct answer
A 7% conversion gap between two arms of an A/A test with p = 0.04 is surprising but not automatically evidence of a broken pipeline: with a conventional alpha, roughly 1 in 20 A/A tests will cross p < 0.05 by chance alone even with perfect randomization, so a single significant A/A result sits right at the boundary between noise and something worth investigating. The right response is a fixed sequence of diagnostics, cheapest and most mechanical first, that can positively confirm or rule out each concrete failure mode: broken hashing or salting in the assignment logic, a covariate imbalance introduced by a logging bug, or ordinary sampling variation.
Structured elaboration
Ordered diagnostics
- Reproduce on raw logs with a fixed seed. Re-run the exact analysis against raw exposure and outcome events, not a downstream aggregated table, to rule out an analysis or pipeline bug before suspecting randomization itself.
- Check the allocation ratio. Confirm the number of users landing in each arm matches the intended split; a large deviation from the intended ratio is one of the strongest and cheapest signals that the hashing or salting scheme is broken, and it is a distinct check from the 7% conversion gap itself. An experiment can have a balanced allocation and still show a spurious metric difference, or a skewed allocation and a metric difference that is actually the real symptom.
- Audit covariate balance, not just the topline metric. Compare the two arms on pre-experiment covariates that should be identical under correct randomization: browser type, geography, device, and signup cohort. If, for example, one arm has a meaningfully different browser or region mix, that points directly at the hashing or salting scheme, perhaps it is keyed on something correlated with browser or region rather than a clean user id, rather than at chance.
- Audit instrumentation and logging for the affected population, not just in aggregate. Check whether the difference is spread evenly across all users or concentrated in a specific segment, for example a subset of power users whose events are logged differently or who hit a code path that assigns or tags them incorrectly; a difference concentrated in one segment is far more consistent with a logging bug than with chance, since chance-driven noise does not usually cluster by user type.
- Check for multiple looks and multiple metrics. Confirm this is the primary metric and the first pre-registered look at the data; if the gap emerged after peeking at several days or several metrics, the effective false-positive rate is higher than the nominal 5% used to compute that p = 0.04.
- Re-run on an independent window if steps 1 to 5 find nothing. If every mechanical check comes back clean, run a fresh A/A on a new time window, not the same data re-sliced, before concluding the original result was real noise; a second clean A/A is much stronger evidence than reasoning about a single result in isolation.
Practical thresholds for concern
A single A/A test crossing the standard p < 0.05 threshold is expected roughly 1 in 20 times under correct randomization and is not, by itself, cause for alarm. Because allocation-ratio checks tend to run on every experiment in a mature program, many teams apply a stricter threshold specifically to that check, for example requiring p < 0.001 before treating a deviation as a real problem, because running a 0.05-threshold check on every one of hundreds of experiments would itself generate frequent false alarms. This is a practitioner convention for managing check-your-own-checks noise, not a statistical property being claimed as derived; teams calibrate the exact cutoff to their own experiment volume.
Worked example
Take the power-user logging-bug scenario concretely, with stated illustrative inputs. Suppose the population is 1,000,000 users, correctly randomized 50/50 by the underlying hashing scheme. Power users are 10% of the population (100,000 users), and a logging bug causes every power user's exposure event to be recorded under the control label regardless of which arm they were actually assigned to.
Non-power users (900,000) log correctly: 450,000 recorded as control, 450,000 recorded as treatment. Power users (100,000) all log as control regardless of true assignment.
Recorded control=450,000+100,000=550,000,Recorded treatment=450,000
Recorded split=55%:45%
A 55/45 recorded split against an intended 50/50 is a large, easily detectable sample-ratio deviation, exactly the kind of signal step 2 is designed to catch, and it would also explain a spurious conversion difference: if power users convert at a different rate than the general population, mislabeling all of them into "control" pulls the control arm's average toward the power-user rate and creates a gap that has nothing to do with the treatment itself.
Trade-offs and pitfalls
- Investigating every marginal A/A result exhaustively is expensive; teams running many experiments generally accept a small, known false-alarm rate rather than deeply diagnosing every borderline case, but should still run the cheap mechanical checks (steps 1 to 3) before shipping a launch decision built on top of infrastructure that produced a suspicious A/A.
- A clean allocation ratio does not prove randomization is unbiased end to end; a hashing scheme can produce a correct overall 50/50 split while still being correlated with a covariate, for example alternating by the last digit of a sequential user id, which can correlate with signup cohort. The ratio check and the covariate-balance check are complementary, not substitutes for each other.
- Re-running on a new window is the strongest single diagnostic but takes real calendar time, so it should be the last check, not the first, when cheaper log-based checks can often localize the problem faster.
- Concluding "just noise" without running the mechanical checks at all is itself a pitfall: an unresolved instrumentation bug found only after it has already contaminated a live experiment is far more costly than the time it takes to check allocation ratio and covariate balance up front.
What is the Stable Unit Treatment Value Assumption (SUTVA) in online experimentation? Explain its two components, and give two concrete examples from real online products where SUTVA is violated (for example, a social feed where a treated user's action visibly changes what their connections in control see, or a shared inventory or capacity constraint that lets treatment eat into control's resources). Explain why each violation biases how you would interpret the A/B test result.
Sample Answer
Direct answer
SUTVA, the Stable Unit Treatment Value Assumption, is the assumption underlying a standard A/B test that one unit's observed outcome depends only on which arm that unit itself was assigned to, and not on which arms other units received. It has two components: no interference between units (your outcome is not affected by someone else's assignment) and no hidden variation of treatment (everyone labeled "treatment" received the same treatment). When either fails, the simple difference-in-means between arms is no longer an unbiased estimate of the causal effect you think you are measuring.
Structured elaboration
The two components
- No interference between units. Unit i's potential outcome under any assignment vector depends only on i's own treatment, not on the treatments assigned to units j=i. This is the component that breaks in networked or shared-resource products.
- No hidden variation of treatment (consistency). There is exactly one version of "treatment" and one version of "control"; a unit's potential outcome is well defined given only its treatment label. This breaks when the same nominal arm is implemented differently for different users (different rollout timing, different creative, a bug that only affects some treatment users).
Two real violations and why each biases interpretation
Social feed, no-interference violation. A treated user gets a new sharing feature and posts more; their connections, who are in control, now see more of that content in their own feed even though they were never assigned to treatment. The control group's outcome (engagement) is contaminated by treatment spillover, which pulls control's measured engagement up and understates the true treatment effect: you are comparing "treatment" against "control that is partially treated," not against a clean counterfactual.
Shared inventory or capacity constraint. A promotion arm drives more purchases, which draws down a shared inventory pool or a fixed daily capacity (delivery slots, support-queue capacity) that both arms draw from. Control users now see stockouts or longer wait times caused by treatment's demand, not by anything intrinsic to being in control. This inflates the apparent treatment effect (control looks artificially worse) and, separately, means the effect you measured at the tested traffic share will not hold at 100% rollout, because the resource contention itself scales with the treatment allocation percentage.
In both cases the estimate is not merely noisy, it is biased in a specific, name-able direction, and the bias would not shrink with more sample size because it comes from the assignment mechanism interacting with the product, not from sampling error.
Designing around a suspected violation
Once you suspect interference, the standard fix is to change the unit of randomization to one large enough to contain the spillover, i.e., cluster randomization: randomize by friend-group, geographic market, or server shard instead of by individual, so that most of the interference happens within a cluster (which is internally consistent, either all-treated or all-control) rather than across the treatment/control boundary.
Cluster randomization has its own cost, though: fewer independent units means higher variance for the same total traffic, since the effective sample size is closer to the number of clusters than the number of users. It also requires the outcome to be measurable and meaningful at the cluster level, and it does not eliminate the shared-capacity case unless the constrained resource is itself scoped per cluster.
Detecting a violation you did not design around
If the violation is discovered mid-experiment rather than anticipated, e.g., a caching-configuration bug causes some control users to intermittently render treatment-arm content, the diagnostic sequence is: quantify the leak rate first (what fraction of control exposures actually rendered the treatment experience, pulled directly from logs, not estimated), then decide whether the leak is small enough to bound the bias and proceed with a documented caveat, or large enough that the read is unusable and the fix is to patch the bug and rerun rather than to try to model the contamination away after the fact.
Worked example
A marketplace runs a two-armed test on a checkout redesign, expecting independent per-user outcomes. Mid-experiment, a shared caching layer bug is found: a same-session user occasionally gets served a stale cached page from the opposite arm. Pulling exposure logs, engineering finds this affected roughly 4% of control-arm page views (a number read directly from the cache-hit logs, not assumed). That is a version-of-treatment violation, not an interference violation: some "control" users received a materially different experience than the rest of control, so the control arm is not internally consistent. The team's next step is not to reweight or model this away, because the mechanism (a caching bug) has no principled correction; it is to fix the bug and rerun the experiment cleanly, treating the contaminated run as informative only about the presence of the bug.
Trade-offs and pitfalls
- Do not assume interference is symmetric or negligible just because the product does not look "social." Shared backend resources (queues, inventory, ranking models retrained on pooled data) create interference in products with no visible network feature.
- Cluster randomization trades bias for variance; do not adopt it reflexively for every experiment on a networked product when the actual interference is small relative to the direct effect, since you would be paying a real power cost for a small bias fix.
- A violation discovered after the fact is a data-quality incident, not a modeling problem to be adjusted away; resist the temptation to "correct" biased data with a post hoc statistical patch when the honest fix is to rerun cleanly.
What is an A/A test, and why would you run one before or alongside a real A/B test? Describe at least two valid use cases, such as validating the assignment and instrumentation pipeline or establishing a baseline-variance estimate, and two limitations or common misinterpretations of A/A testing. If an A/A test shows a statistically significant difference between the two identical groups, what steps would you take to root-cause it?
Sample Answer
Direct answer
An A/A test randomly splits traffic into two groups that receive the identical experience and compares their metrics as if they were a real experiment. You run one to validate the assignment and measurement pipeline before trusting a real A/B result on the same platform: since both groups get the same product, any statistically significant difference between them signals a problem in the pipeline (randomization, instrumentation, or analysis) rather than a real effect, because by construction there is no effect to detect.
Structured elaboration
Two valid use cases
- Validating the assignment and instrumentation pipeline. Confirms that the bucketing hash actually produces the intended split ratio, that each unit sees a stable, single experience, and that event logging correctly attributes actions to the assigned arm end to end (client instrumentation through to the analysis table).
- Establishing a baseline-variance estimate. Because there is no true effect, the spread of the A/A metric difference across many runs (or across a well-chosen resampling of the same data) tells you what "just noise" looks like for this metric on this population, which is useful input for planning: it is a sanity check on your variance assumptions, not a substitute for a proper power calculation.
What to check while it runs
- The realized split ratio against the intended one (a sample-ratio check): meaningfully off the intended ratio (say, 50/50 skewing to 49/51 in a way that recurs, not a single noisy day) points at a bucketing bug before you even look at outcome metrics.
- Core funnel and event counts by arm (sessions, page views, primary conversion event) to confirm the two arms are tracked with equal fidelity, not just equal traffic.
- Whether the metric of interest for the upcoming real experiment behaves as expected in the A/A read, since that is the metric whose baseline variance you actually need.
- Run it for at least one full natural cycle of the traffic (typically a full week, to span weekday/weekend mix) rather than a single day, since a one-day A/A window can look clean by luck or flagged by a day-specific anomaly that has nothing to do with the platform.
An A/A test is, at its core, a targeted way to surface three distinct failure classes: instrumentation errors (events not logged or misattributed), non-random assignment (the bucketing hash is not producing a genuinely random, independent split), and sampling biases (the two arms end up systematically different in composition despite a technically-random split, e.g., a bot-filtering rule that behaves differently by arm). Each class points at a different fix, which is why segmenting the flagged difference (below) matters more than the raw significance flag itself.
Two limitations or common misinterpretations
- A clean A/A result is not proof the pipeline is bug-free. With enough traffic, small true differences in a specific test can still slip through if the bug is intermittent (e.g., only affects a rare browser) or if the metric checked in the A/A test is not the one that will matter in the real experiment. Absence of a flagged difference is reassurance, not a guarantee.
- A single significant A/A result does not, by itself, mean the pipeline is broken. At a conventional significance threshold, some fraction of A/A tests will show a "significant" difference purely by chance even with a perfectly correct pipeline; treat one flagged metric as a prompt to investigate, not as an automatic verdict, especially if you are checking many metrics at once and did not correct for that.
Root-causing a significant A/A result
- Recheck the sample ratio first. A skewed split is the fastest, most common finding and points straight at a bucketing bug rather than a downstream measurement issue.
- Segment the difference. Break the flagged metric down by platform, geography, and new-vs-returning user; a difference concentrated in one segment (e.g., one app version) points at an instrumentation bug specific to that segment rather than a global randomization failure.
- Check for a known confound in how the two arms are served, such as one arm being disproportionately served through a code path with different latency or caching behavior, which is functionally a version-of-treatment bug even though no real treatment was intended.
- Re-run before escalating, if the first read used a short window: a single noisy day is a weaker signal than a difference that persists across multiple independent A/A windows.
- If it persists and is not explained by a segment or a known bug, treat the underlying real-experiment platform as unvalidated until the discrepancy is resolved; shipping A/B decisions on top of an unexplained A/A anomaly defeats the purpose of running the check at all.
Worked example
A team runs an A/A test ahead of a planned homepage experiment and flags a significant difference in click-through rate. Step 1, sample ratio: 50.1% vs 49.9%, within normal noise, so not a bucketing problem. Step 2, segmentation: the CTR gap is near zero on Android and web but noticeably present on iOS. Step 3: engineering finds one arm's iOS client is on an older app version with a slightly different default tab order, an artifact of how the A/A test's client-side flag was staged rather than anything about the experiment platform itself. The root cause is a version-of-treatment bug traced to a real, checkable fact (the iOS staging config), not a p-value alone; the fix is correcting the staged rollout, not adjusting the metric.
Trade-offs and pitfalls
- Running A/A tests constantly, on every metric, invites exactly the false-alarm problem described above; use them at meaningful checkpoints (new platform, new metric pipeline, post-incident) rather than as a standing tax on every experiment.
- Do not use a single A/A run's variance estimate as your only power-planning input if you have a more direct historical baseline available; treat it as a cross-check.
- A quiet A/A test on a low-traffic metric provides much weaker reassurance than the same result on a high-traffic metric, because a real problem of a given size is harder to detect with less data; do not treat "clean" as equally strong evidence across metrics of very different volume.
Plan an experiment that will run across a period with strong weekly seasonality, where weekday and weekend behavior differ a lot, and possibly a holiday. How would you choose the test duration, the traffic allocation, and the analysis window to avoid seasonality confounding the result? If you later observe that the treatment effect looks positive on weekdays but negative on weekends, how would you investigate whether that pattern is real, an artifact of traffic composition, or noise?
Sample Answer
Direct answer
Run for a whole number of full weekly cycles, decide before looking at any data how a holiday inside that window will be handled, and hold traffic allocation balanced by day-of-week (and by region and time zone if the test spans them) rather than trusting that a single aggregate 50/50 split will average out. When a weekday-positive, weekend-negative pattern shows up later, treat it as a hypothesis to falsify with three specific checks, real heterogeneity, a traffic-composition artifact, or noise, rather than reading the raw split at face value.
Structured elaboration
Duration and analysis window
Run for at least two, ideally three or more, full 7-day cycles. A partial week biases the pooled result toward whichever days happen to be over-represented, and a single week does not let you separate a real weekday/weekend pattern from that week's idiosyncrasies. If a holiday falls inside the planned window, decide up front, before seeing any results, between two options: exclude the holiday period from the primary analysis window and report a "typical week" estimate, or explicitly include it and report a distinct holiday-period estimate. Choosing between those two after looking at which one produces a better-looking result is a form of after-the-fact window selection and should be avoided; pre-register the choice in the analysis plan.
Traffic allocation and balance across time and geography
Stratify random assignment by day-of-week, and by region or time zone if the rollout spans them, so the same proportion of each arm is exposed every day and in every zone rather than relying on an aggregate split that could hide a skew. For a multi-region or multi-time-zone test, anchor "day" and "week" boundaries to each user's local time rather than a single server or UTC clock; otherwise one region's weekend gets miscounted against another region's weekday, and verify the treatment-to-control ratio stays constant across regions and hour-of-day buckets individually, not just in the combined total. Aggregate balance can look fine while a specific region or time window is quietly imbalanced, and that imbalance is exactly what later gets mistaken for a day-of-week effect.
Modeling the temporal structure instead of ignoring it
Rather than computing one pooled treatment effect and hoping seasonality washes out, fit day-of-week (and holiday, and region, if relevant) as explicit terms: outcome ~ treatment + day_of_week + treatment:day_of_week + region. This is standard regression-formula shorthand: ~ means "model the left-hand outcome using the terms on the right," so this line reads as "predict the outcome from the treatment, the day type, and the region," and treatment:day_of_week is an interaction term, a piece that lets the treatment's effect itself differ by day type rather than assuming it is the same on weekdays and weekends. The interaction term is what actually tells you whether the treatment effect differs by day type, instead of a single pooled number that could be hiding it.
Investigating a weekday-positive, weekend-negative split
Three checks, run in this order:
- Is it real? Fit the treatment-by-day-type interaction term from the model above and check whether it is distinguishable from a null effect. This is one specific comparison, not a license to slice every available dimension until something looks significant; keep the interaction pre-specified as part of the analysis plan for exactly this reason.
- Is it a traffic-composition artifact? Check whether the user mix itself differs by day type: a different device split, acquisition channel, or new-versus-returning ratio on weekends than weekdays. Re-run the interaction model with that covariate added and interacted; if the day-type interaction shrinks toward zero once the segment mix is controlled for, the apparent weekday/weekend split was really a segment-level pattern wearing a calendar label. Also check whether the rollout itself was staggered mid-week (a ramp that reached full exposure partway through the window) or whether an assignment-pipeline issue caused the treatment:control ratio to drift on certain days; both produce a day-type-looking artifact that has nothing to do with actual weekday or weekend behavior.
- Is it noise? Compare the confidence interval on each day-type's estimate rather than the point estimates alone. Weekend traffic is frequently a fraction of weekday traffic, so a "negative" weekend estimate often carries a wide interval that comfortably contains the weekday estimate.
Worked example
Suppose the weekday arm has 8,000 users per group with control conversion 10.0% and treatment conversion 10.6% (a +0.6 percentage point delta), and the weekend arm has 2,000 users per group (lower weekend traffic) with control conversion 10.0% and treatment conversion 9.4% (a -0.6 percentage point delta). This is exactly the pattern in the question: positive on weekdays, negative on weekends.
Standard error of each delta, using SE=npc(1−pc)+npt(1−pt):
Weekday: SEwd=80000.10×0.90+80000.106×0.894=0.00481, so the weekday delta's 95% interval is roughly −0.34pp to +1.54pp, which already crosses zero.
Weekend: SEwe=20000.10×0.90+20000.094×0.906=0.00936, so the weekend delta's 95% interval is roughly −2.43pp to +1.23pp, also crossing zero.
Testing whether the two deltas actually differ from each other: z=0.004812+0.0093620.006−(−0.006)=0.010520.012≈1.14, well under the 1.96 threshold for a two-sided 5% test. Both individual intervals already contain zero, and the two deltas are not statistically distinguishable from each other. With these particular sample sizes, the weekday-positive-weekend-negative pattern is fully consistent with noise, before ever needing to invoke a real behavioral difference or an artifact.
Trade-offs & pitfalls
- Trusting the point estimate over the interval. A sign flip between two point estimates feels meaningful; whether it survives a formal comparison of the two deltas, as above, is what actually determines whether there is anything to explain.
- Deciding the holiday treatment after seeing results. Choosing whether to include or exclude a holiday period based on which choice produces the preferred outcome is a subtle form of p-hacking through window selection, even when no single test is repeated.
- Assuming aggregate balance implies balance everywhere. A day-of-week or region-level imbalance can hide inside an aggregate 50/50 split and later masquerade as a real seasonal effect.
- Over-correcting into paralysis. Not every day-type split needs a full forensic investigation; reserve the three-check process for patterns that would actually change a rollout decision, and size the investigation to the stakes.
Unlock Full Question Bank
Get access to all 21 A/B Test Design & Statistical Rigor interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.