Possible causes (most to least likely)- Randomization bug (hash function, seed, rollout code) causing non-random assignment- Targeting rule or filter applied asymmetrically (segment, geography, device)- Duplicate/merged users or identity stitching issues leading to unequal denominators- Tracking instrumentation missing or broken for one variant (pixel, event)- Sampling/traffic leakage (bots, internal traffic) concentrated in one variant- Time-based rollout / staggered deployment causing temporal imbalance- Small sample or pure chance (but measurable pre-test difference)Prioritized remediation plan1) Immediate SQL checks (fast, non-invasive)- Verify counts and proportions by cohort, user, and timesql
-- Unique users per variant
SELECT variant, COUNT(DISTINCT user_id) AS users
FROM experiment_assignments
WHERE assigned_at < '[experiment_start]'
GROUP BY variant;
sql
-- Pre-test conversion by variant (baseline period)
SELECT variant,
COUNT(DISTINCT user_id) AS users,
SUM(CASE WHEN converted_at BETWEEN '[pre_start]' AND '[pre_end]' THEN 1 ELSE 0 END) AS conversions,
SUM(CASE WHEN converted_at BETWEEN '[pre_start]' AND '[pre_end]' THEN 1 ELSE 0 END)::float / COUNT(DISTINCT user_id) AS conv_rate
FROM experiment_assignments a
LEFT JOIN events e USING(user_id)
GROUP BY variant;
sql
-- Assignment stability over time / drift
SELECT variant, DATE(assigned_at) AS day, COUNT(*) FROM experiment_assignments GROUP BY 1,2 ORDER BY 2;
- Check duplicate IDs, multiple assignments, identity mergessql
SELECT user_id, COUNT(DISTINCT variant) as variants, COUNT(*) as rows
FROM experiment_assignments
GROUP BY user_id HAVING COUNT(DISTINCT variant) > 1;
- Verify hashing/uniformity (if using hashing)sql
SELECT variant, COUNT(*) FROM (
SELECT user_id, CASE WHEN ABS(MOD(HASH(user_id||'[salt]'),100)) < X THEN 'treatment' ELSE 'control' END AS variant FROM users
) t GROUP BY variant;
- Inspect device/geo/browser distributionsql
SELECT variant, device_type, COUNT(DISTINCT user_id) FROM experiment_assignments JOIN users USING(user_id) GROUP BY 1,2;
2) Triage instrumentation & traffic- Confirm event pipelines and pixel/firehose delivery for both variants- Look for deployment logs showing staggered rollout or errors- Check internal/bot filtering: compare internal IPs or known bot user agents by variant3) Short-term analysis mitigations (if experiment cannot be stopped)- Adjust analysis using pre-test covariate adjustment (ANCOVA) or include baseline conversion as covariate- Use inverse-propensity weighting if assignment probabilities differ- Restrict to users with stable identity and single assignment4) Experiment-level fixes (longer-term / corrective)- Fix code bug (hash/seed/targeting) and re-deploy; if assignment changed, either: - Restart experiment (best) with corrected randomization and fresh sample - If restart impossible, archive current and run new experiment; do NOT mix data across assignment regimes- Implement deterministic hashing with explicit salt/versioning and unit tests- Add stratified/randomization checks in CI and monitoring dashboards (daily parity metrics)- Enforce pre-rollout smoke tests and canary checks to validate assignment balance5) Postmortem & prevention- Root-cause analysis, document fix, update runbook- Automate SQL parity checks to run hourly on new experiments: sample sizes, baseline metrics, assignment stability, instrumentation health- Educate product/eng on targeting interactions that can bias assignmentWhen to stop the experiment- Stop immediately if assignment bug causes systematic bias (e.g., all mobiles to treatment) or instrumentation loss; otherwise continue only with corrective analysis and clear communication to stakeholders.This plan emphasizes quick diagnostic SQL checks, triage of telemetry/instrumentation, cautious interim analysis fixes, then code-level corrections and preventative monitoring to avoid recurrence.