Testland
Browse all skills & agents

peeking-problem-reference

Pure-reference catalog of the peeking problem in online A/B testing. Defines the problem (repeatedly looking at experiment results inflates the false-positive rate above the declared alpha because each look is a separate test), the canonical mitigations (fixed-horizon test with pre-declared sample size; sequential testing with alpha-spending functions e.g., O'Brien-Fleming, Pocock; always-valid inference / mSPRT per Johari et al.), and the policy choices (data-peek schedule, stop-early thresholds, decision-time guard rails). Use when designing an experimentation platform's stop-early policy or auditing why a result was declared significant.

Install with skills.sh (any agent)

npx skills add testland/qa --skill peeking-problem-reference
View source

peeking-problem-reference

Overview

In classical (fixed-horizon) hypothesis testing, the test is run once, on a pre-declared sample size, at a pre-declared alpha (typically 0.05). Looking at the data and stopping when significance is reached before the pre-declared end inflates the false-positive rate well above alpha - sometimes to 30%+ at naive 0.05.

This is the peeking problem. Per Kohavi et al. Trustworthy Online Controlled Experiments (ISBN 978-1108724265): "Repeated significance testing is one of the most common mistakes in practical A/B testing."

This skill is a pure reference consumed by the AB-test validity checklist and SRM detection.

How to use this reference

  1. Choose the analysis regime up front: fixed-horizon (no peeking) or a peek-protected method (sequential alpha-spending or always-valid / mSPRT) - see the three corrections below.
  2. If you must stop early, pick a sequential schedule (Pocock vs O'Brien-Fleming) or mSPRT, and pre-declare it before launch.
  3. Lock the look schedule: hourly dashboards and "where are we now?" checks are not decision looks - only the pre-declared schedule is.
  4. Read the peek-protected p-value at the gate, never the naive mid-experiment p-value.
  5. Stack corrections: if the experiment also has guardrails, combine the peeking correction with the guardrail (Bonferroni / FDR) correction - see the worked example below.

When to use

  • Designing the stop-early policy for an experiment platform.
  • Auditing an "early ship" decision - was the math valid?
  • PR review of a new experiment dashboard / analysis flow.
  • Investigating "we shipped, then the effect disappeared."

Why naive peeking inflates false positives

At alpha=0.05, the test is calibrated to give a 5% false-positive rate if you look once. If you look every day for 30 days and ship at the first significance - at each look, the test has a fresh chance to spuriously hit. The total false-positive rate compounds.

Per Microsoft Experimentation Platform research (microsoft.com/en-us/research/group/experimentation-platform-exp/ (opens in new window)): common patterns that surface this - dashboards that update hourly, "early-stop" buttons in experimentation UIs, manager asks for "where are we now?" mid-experiment.

Three corrections

1. Fixed-horizon test (pre-declared)

Decide N in advance via power analysis; collect N samples; do one test; ship or not. No peeking, no early stop.

Pros: standard p-value interpretation, full alpha budget on the declared test.

Cons: must wait for N. Cannot stop early on obvious winners (opportunity cost) or obvious losers (continuing risk).

2. Sequential testing with alpha-spending

Pre-commit to multiple looks, each with a fraction of the alpha budget. Two canonical schedules:

SchedulePattern
PocockEqual alpha at each look; symmetric
O'Brien-FlemingTiny alpha early, large alpha late; conservative early-stop

Implementation: declare K looks in advance; at each look k, the rejection threshold is computed from the cumulative alpha spent (per the schedule). If the test stat exceeds the threshold, stop.

Math: Σ alpha_k = alpha_total.

3. Always-valid inference / mSPRT

Per Johari, Pekelis, Walsh "Always Valid Inference" (paper ID: arXiv:1512.04922) and related work, the mixture sequential probability ratio test (mSPRT) lets you peek arbitrarily often without inflating alpha. The trade-off: less powerful per sample than fixed-horizon.

This is the foundation of "valid sequential" experimentation in Optimizely / Statsig / similar - they expose p-values that are always valid under continuous monitoring.

Per Optimizely's sequential-testing docs (a derivative of mSPRT): the platform allows the user to look at any time; the p-value remains valid.

Visual intuition

ApproachLook 1 (day 1)Look 30 (day 30)Final
Naive fixed-horizonDon't lookDon't lookLook once at day 30, alpha=0.05
Fixed-horizon + early-stop = WRONG"Hmm 0.04, ship!"n/aFalse positive risk inflated
Pocock 5 looksalpha=0.016 (=0.05/√5 ish)alpha=0.016Sum ≤ 0.05
mSPRT / always-validLook any time; p-value validLook any timeSame alpha guarantee

Decision boundary in tests

Tests for an experimentation platform must verify:

BehaviourTest
Naive p-value not auto-significant on peekRun synthetic A/A test; look 100×; ≤5% false positives
Sequential adjustment correctly enforcedAt look N, threshold matches the declared schedule
Stop-early threshold consistent with declared methodPocock vs O'Brien-Fleming asymmetric on early vs late
Always-valid p-value never decreases below declared alphaSimulate; check never-exceeds-alpha
Ship-decision gate enforces the peek-protected p-valueMock low-p naive p, observe gate rejection

Worked example - stacking peeking + guardrail corrections

Per guardrail-metrics-reference: the guardrail-correction (Bonferroni / FDR) stacks with the peeking correction. Don't apply only one if both are needed.

For an experiment with one OEC, 10 guardrails, and 5 looks:

Naive alpha per look per metric0.05
With 5 looks alpha-spending0.011 per look
With Bonferroni for 11 metrics at each look0.001 per (look, metric)

The strict math is rarely applied this thoroughly; pragmatically most platforms apply sequential + per-metric alpha but not formal multi-comparison correction across guardrails.

Anti-patterns

Anti-patternWhy it failsFix
Peek + early-stop on naive p-valueFalse positive rate explodesUse sequential / always-valid
Dashboards refresh hourly, treated as "data"Implicit peeking; humans see + reactLock decisions to pre-declared look schedule
Stop-loss without symmetric stop-winOne-sided peeking still inflatesSymmetric or pre-committed
"We'll just look once at midpoint"One unscheduled look = one inflation eventEither fixed-horizon OR sequential - not "fixed + one peek"
Different metric uses different scheduleCoordination mismatch; inconsistent alphaOne schedule per experiment
Re-running an experiment after p=0.06 to "find significance"Garden of forking pathsPre-commit; accept null result
Stop-early on a guardrail aloneGuardrails should be assessed at horizonStop-early only on OEC (with sequential math)
Treating "p=0.04 mid-experiment" as significantNaive interpretationUse the sequential / always-valid p-value

Limitations

  • Always-valid inference is less powerful. Same effect size requires more samples than fixed-horizon. Trade convenience for sample efficiency.
  • Sequential methods require pre-declared schedules. The alpha-spending isn't "fluid"; the schedule is fixed in advance.
  • Multiple-testing correction across many metrics is brutal. Per-metric alpha after Bonferroni × 20 metrics = 0.0025.
  • Operator behaviour is the real bottleneck. Math is robust to peeking; humans are not. Education + UI gating matter.
  • Doesn't help with novelty / primacy effects. Statistical validity doesn't fix "users react to change, then revert."

References

  • Kohavi, Tang, Xu. Trustworthy Online Controlled Experiments (Cambridge Univ. Press, 2020). ISBN 978-1108724265, ch. on sequential testing.
  • Johari, Pekelis, Walsh. Always Valid Inference: Continuous Monitoring of A/B Tests (arXiv:1512.04922).
  • Microsoft Experimentation Platform: microsoft.com/en-us/research/group/experimentation-platform-exp/ (opens in new window).
  • Companion catalogs: guardrail-metrics-reference, ab-test-validity-checklist.
  • Consumed by: statsig-test, optimizely-test, vwo-test, amplitude-experiment-test.

Related skills

ab-test-validity-checklist

Workflow skill that builds an A/B-test validity checklist from an experiment proposal, walking the canonical design-correctness gates - pre-registered OEC/power/guardrails, randomization unit + SRM check, assignment integrity, telemetry, peeking discipline, novelty/primacy, post-experiment SRM re-check - into a per-experiment checklist + sign-off form. Use when launching, auditing, or governing an experiment. For pitfall mechanics use guardrail-metrics-reference or peeking-problem-reference; to read an already-valid result use experiment-results-interpreter; for per-SDK harness tests use optimizely-test or statsig-test - this gates DESIGN, not SDK code.

amplitude-experiment-test

Wraps Amplitude Experiment SDK testing patterns: client initialization with API key (or a bootstrapped local flag config for offline tests), the fetch / variant API, exposure-event suppression in tests, and assignment-integrity tests. Use when writing tests for code that uses Amplitude Experiment for A/B testing or flag management.

experiment-results-interpreter

Interprets the results of a valid online controlled experiment, one whose harness, SRM, and telemetry have already been confirmed. Covers the distinction between practical and statistical significance, reading confidence intervals instead of binary p-values, novelty and primacy week-over-week decay that causes post-ship reversion, interaction effects from concurrent experiments, Simpson's paradox in segmented results, and the ordered guardrail-check sequence required before a ship decision. Use when a data scientist or PM is ready to draw conclusions from an experiment whose telemetry and randomisation have already passed the ab-test-validity-checklist. Distinct from ab-test-validity-checklist (harness setup and SRM detection) and from interaction-effect overlap auditing during experiment design.

guardrail-metrics-reference

Pure-reference catalog of guardrail-metric methodology for online controlled experiments. Defines guardrail metrics (metrics that must NOT degrade for an experiment to ship, even if the primary metric improves), the standard guardrail set (latency / errors / engagement / opt-out), the relationship to OEC (Overall Evaluation Criterion) per Kohavi et al., and pre-commitment of the metric set. The quantitative evaluation mechanics (per-metric alert/block thresholds, Bonferroni / Benjamini-Hochberg multiple-comparison correction) live in references/. Use when designing the metric set for a new experiment, auditing existing experiment configs, or reviewing experiment results before ship-decisions.

optimizely-test

Wraps Optimizely Feature Experimentation SDK testing patterns - client init from a fixture datafile (offline-friendly), the decide / decideAll v5 API, forced-decisions for per-test arm pinning (fixing which variation a user gets), OptimizelyUserContext + activate/track events, assignment-integrity (deterministic bucketing) tests. Use when writing A/B tests or feature-flag tests for Optimizely-instrumented application code. For another experimentation SDK use the matching harness - statsig-test, vwo-test, amplitude-experiment-test, or split-io-test; for experiment DESIGN gates not SDK code use ab-test-validity-checklist.

split-io-test

Wraps Split.io (Harness FME) SDK testing patterns: hermetic localhost/offline mode with an in-memory features map (JavaScript/browser) or a YAML fixture file (Node.js server-side), getTreatment and getTreatmentWithConfig evaluation, the SDK_READY event and whenReady() promise, impression listener verification, sync.impressionsMode configuration, and CI setup. Use when writing tests for application code instrumented with the Split.io or Harness Feature Management & Experimentation SDK.

statsig-test

Wraps Statsig SDK testing patterns - server-side statsig.initialize with an API key, gate / experiment / dynamic-config evaluation (checkGate, getExperiment, getConfig), local-evaluation offline mode, overrideGate / overrideConfig to force a user into an arm, assignment-integrity tests. Use when writing tests for Statsig-instrumented application code. For another experimentation SDK use the matching harness - optimizely-test, vwo-test, amplitude-experiment-test, or split-io-test; for experiment DESIGN gates not SDK code use ab-test-validity-checklist.

vwo-test

Wraps VWO (Visual Website Optimizer) SDK testing patterns: SDK initialization with the settings file (offline-capable), `getFeatureVariableValue` and `activate` API, force-bucketing for per-test assignment, and assignment-integrity tests against the bucketing algorithm. Use when writing tests for VWO-instrumented application code.