Testland
Browse all skills & agents

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 (guardrails, peeking) see experiment-results-interpreter's references; to read an already-valid result use experiment-results-interpreter; for per-SDK harness tests use experiment-sdk-testing - this gates DESIGN, not SDK code.

Install with skills.sh (any agent)

npx skills add testland/qa --skill ab-test-validity-checklist
View source

ab-test-validity-checklist

Overview

This skill produces the pre-flight + post-flight validity checklist for an A/B test. Each item is a gate; failing one without explicit acknowledgment invalidates the experiment.

Per Kohavi et al. Trustworthy Online Controlled Experiments (ISBN 978-1108724265): "More than 50% of experiments in practice are invalidated by issues the checklist catches."

The output: a per-experiment markdown checklist + a sign-off form for the experiment owner.

When to use

  • Launching a new experiment.
  • Auditing an experiment that produced surprising results.
  • Building experimentation governance / a peer-review process.
  • PR review of experiment configuration changes.

Step 1 - Pre-registration

Document before launch:

ItemWhat
OECThe single metric (or weighted combination) to improve
PowerExpected effect size, sample size, alpha, beta
GuardrailsPer experiment-results-interpreter references/guardrails.md - list each + threshold
Randomization unitUser / session / device / cookie / IP / tenant
AllocationPercentages per arm; rules for ramp-up
Look schedulePre-declared days; per experiment-results-interpreter references/peeking.md
Sequential methodFixed / Pocock / O'Brien-Fleming / always-valid
Stop-early rulesWhat signals stop (loss on OEC, blocking guardrail)

Candidate guardrail set to pick from, with typical block thresholds (per experiment-results-interpreter references/guardrails.md; Kohavi et al. Trustworthy Online Controlled Experiments, ISBN 978-1108724265):

ClassGuardrailDirectionTypical block threshold
Quality (web)TTFB, LCP, INPnot-increase> 10% or > 50ms, whichever is greater
Quality (API)p95 / p99 latencynot-increase> 10% or > 50ms, whichever is greater
Quality (API)error rate, 5xx ratenot-increase+0.1pp absolute
Quality (mobile)crash rate, ANR rate, app start timenot-increaseany statistically significant increase
EngagementDAU, sessions / user, retention day 7not-decrease-1%
Revenuegross revenue, AOV, conversionnot-decreaseany statistically significant decrease
Trustopt-out, complaint, refund ratenot-increaseany statistically significant increase

Each guardrail carries two levels: alert (statistically significant degradation - investigate before ship) and block (past the pre-declared limit - ship-decision flips to "no"). Per Kohavi et al., always include a quality guardrail (latency / error); it is the most-missed category. Percentage-only thresholds on fast endpoints are a trap - use max(%, absolute).

Commit this to the repo as experiments/<id>/proposal.yml. Any post-launch change requires explicit team approval.

Step 2 - Sample Ratio Mismatch (SRM)

Per Microsoft Experimentation Platform research (KDD 2019 paper "Diagnosing Sample Ratio Mismatch in Online Controlled Experiments"): if the observed allocation (e.g., 50.3% A, 49.7% B) deviates significantly from intended (50% / 50%), the experiment is invalid until root cause is found. SRM signals:

  • Logging bugs (assignments not all logged)
  • Bot filtering (different ratios filtered per arm)
  • Redirects (one variant redirects more)
  • Telemetry drops (one variant has heavier client → more drops)
  • Randomisation bugs (hash collisions)

Chi-square test:

χ² = Σ ((observed_i - expected_i)² / expected_i)

For 2 arms at 50/50 with N=1e6 users:

  • Expected: 500k each
  • Observed: 503k / 497k
  • χ² = (3000²/500000) + (3000²/500000) = 36
  • p-value: < 0.0001

Threshold: p < 0.0001 is the canonical SRM-detection boundary (the chi-square is super-sensitive at large N; this threshold prevents false-positive SRM alarms).

If SRM is detected: stop ship discussion; root-cause first.

Step 3 - Assignment integrity

Tests for the assignment SDK / service:

TestPattern
DeterminismSame (user, experiment) → same arm across calls
Sticky assignmentUser reassigned only if experiment reconfigured
Cross-experiment independenceAssignment to expt A doesn't bias expt B
Bot exclusion consistentIf bots filtered, filter applies before assignment
LatencyAssignment SDK adds < 5ms to request path

These tests live in the per-vendor harnesses of experiment-sdk-testing.

Step 4 - Telemetry correctness

Verify the event firing matches the proposal:

  • Conversion events fire exactly once per user per conversion-eligible session.
  • Exposure events fire for everyone who could see the variant (not just those who actually saw it - that's a different measure, "treatment effect on the treated").
  • Guardrail metrics are queryable against the experiment partition (variant ID joined to event stream).

Step 5 - Peeking discipline

Per experiment-results-interpreter references/peeking.md:

RuleTest
If sequential / always-valid: p-value valid at any lookDashboard p-value uses the valid math
If fixed-horizon: no early-stop UI"Ship" button disabled until N reached
If Pocock/OBF: look schedule pre-declaredDashboards lock looks outside the schedule

Step 6 - Novelty / primacy effects

Per Kohavi et al.: users react differently to novel UX. Novelty inflates the early-period effect; primacy depresses it. Mitigation:

  • Run for ≥ 2 weeks (typical mature-effect period).
  • Segment results by "first exposure vs returning to treatment."
  • For long-running tests, segment by week to spot trend reversal.

Step 7 - Post-experiment validation

Before ship:

GatePass criterion
Pre-registration honouredOEC / guardrails / unit / schedule unchanged since launch
SRM cleanp > 0.0001 on the chi-square (Step 2)
OEC significant under the declared methodSequential / always-valid / fixed-horizon p-value
All guardrails within thresholdsEach Step 1 guardrail below its block threshold; per experiment-results-interpreter references/guardrails.md
Multiple-comparison correctedBonferroni / BH if many metrics
Novelty assessmentEffect persisting in week 2+
Segment-stabilityEffect direction consistent across major segments (no Simpson's paradox)
Trust metric stableOpt-out / complaint rate not up

Document each pass in experiments/<id>/result.md with the specific numbers.

Step 8 - Emit the checklist

The output of this skill: a markdown checklist + sign-off form.

# Experiment <id> - Validity Checklist

## Pre-registration (signed by: <owner>, date: <YYYY-MM-DD>)

- [ ] OEC declared: <metric>
- [ ] Power calc: N=<X>, alpha=0.05, beta=0.20, MDE=<Y>%
- [ ] Guardrails declared: <list with thresholds>
- [ ] Randomization unit: <user_id / device_id>
- [ ] Allocation: <50/50>
- [ ] Look schedule: <Pocock 5 looks at days 2,4,7,10,14>
- [ ] Stop-early rules: <on OEC reaching alpha-threshold>

## During experiment

- [ ] SRM check: chi-square p > 0.0001 ([result: <p>])
- [ ] Assignment integrity tests passing
- [ ] Telemetry validated

## Post-experiment (signed by: <reviewer>, date: <YYYY-MM-DD>)

- [ ] Pre-registration honoured (no scope changes)
- [ ] SRM final check: p > 0.0001 ([result])
- [ ] OEC significant (p=<X>; method: <Pocock>)
- [ ] All guardrails within thresholds:
   - api_p95_latency: +<X>% / +<Y>ms - <status>
   - dau: <X>% - <status>
- [ ] Multiple-comparison adjusted (method: <Bonferroni / BH>)
- [ ] Novelty assessment: effect persists week 2+? <yes / no>
- [ ] Segment stability: direction consistent? <yes / no>
- [ ] Trust metric stable? <yes / no>

## Ship decision: <ship / no-ship / extend>

Reasoning: <one paragraph>

Sign-off: <name>, <date>

Anti-patterns

Anti-patternWhy it failsFix
Post-hoc OEC change"We found a better metric" = p-hackingPre-register
Skip SRM checkInvalidates results without detectionAlways run chi-square pre-ship
Decision before checklist completionShip-then-validate is rejected by trusted-experiments frameworkBlock ship on incomplete checklist
Reviewer = experiment ownerSelf-sign-off; no second pair of eyesDifferent sign-off than owner
Skip novelty assessmentEffect disappears post-shipLook at week-2+ subset
Skip segment stabilitySimpson's paradox: total positive, per-segment negativeAudit by major segments
Treat the checklist as paperworkItems checked without verificationEach item produces evidence (number, link, calc)

Limitations

  • Checklist is necessary, not sufficient. Quality of the underlying telemetry + assignment logic matter.
  • Multiple-comparison corrections are conservative. May reject real wins.
  • Novelty assessment needs ≥ 2 weeks. Pressure to ship fast conflicts.
  • Doesn't catch ecosystem effects. Cross-experiment interaction, carry-over, etc. require global statistics.

References

  • Kohavi, Tang, Xu. Trustworthy Online Controlled Experiments (Cambridge Univ. Press, 2020). ISBN 978-1108724265.
  • KDD 2019 paper "Diagnosing Sample Ratio Mismatch" (Microsoft Research).
  • Microsoft Experimentation Platform articles: microsoft.com/en-us/research/group/experimentation-platform-exp/ (opens in new window).
  • Companion: experiment-results-interpreter (result reading; peeking + guardrail methodology in its references/).
  • Operationalised: experiment-sdk-testing (Statsig / Optimizely / Split.io / Amplitude / VWO harnesses).

Related skills

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 - with the deep methodology in references/: the peeking problem and its corrections (fixed-horizon, alpha-spending, always-valid mSPRT) in references/peeking.md, and guardrail-metric methodology (taxonomy, OEC relationship, pre-commitment, thresholds) in references/guardrails.md. Use when a data scientist or PM is ready to draw conclusions from an experiment, when designing a stop-early policy, or when declaring an experiment's guardrail set. Distinct from ab-test-validity-checklist (harness setup and SRM detection).

experiment-sdk-testing

Umbrella for experimentation-SDK test harnesses: the shared offline-datafile / hermetic-init pattern (commit a point-in-time flag/experiment config fixture, initialize the SDK with no network, pin arms per test, assert assignment integrity), with per-vendor references for Statsig (localMode + overrideGate), Optimizely (datafile + forced decisions), Split.io / Harness FME (localhost mode + features map or YAML fixture), Amplitude Experiment (local evaluation + bootstrap), and VWO (settings file + deterministic bucketing). Use when writing tests for application code instrumented with any of these five experimentation SDKs; for experiment DESIGN gates use ab-test-validity-checklist, and to read results use experiment-results-interpreter.

feature-flag-test-matrix-reference

Feature-flag test matrix design: the flag-state combinatorics problem (N flags × M variants × K user-segments = N×M×K test cases), the canonical coverage strategies (pairwise interaction coverage; default-only smoke; full matrix; risk-driven matrix), the workflow for building the coverage suite from a flag inventory (grep-based inventory, per-flag classification, PICT pairwise generation, per-cell test skeletons), the dedicated kill-switch test categories (references/killswitch.md: graceful degradation, fail-static default, kill latency, mid-flight consistency), and the flags-vs-experiments distinction. Use when designing the flag-test surface for a new project, building or auditing flag-test coverage, or authoring kill-switch tests.

launchdarkly-testing

Wraps LaunchDarkly server-side SDK testing patterns: TestData data source for hermetic tests (no network), file-based data source for fixture-driven tests, flag override patterns (TestData.update for per-test flag values), and assignment-integrity tests. Use when writing tests for code that uses LaunchDarkly flags; to decide which flag combinations those tests should cover in the first place, see feature-flag-test-matrix-reference.

openfeature-sdk-testing

Wraps OpenFeature (CNCF vendor-neutral SDK abstraction) testing patterns: the InMemoryProvider for hermetic tests without network calls, provider registration via OpenFeature.setProvider, the getBooleanValue/getBooleanDetails evaluation API with EvaluationDetails (value, variant, reason, errorCode), hooks for evaluation side-effects, and evaluation context for targeting-rule tests. Covers TypeScript, Java, and Python SDKs, plus per-vendor hermetic-bootstrap references for Unleash (bootstrap toggles), Flagsmith (offline LocalFileHandler), and GrowthBook (initSync payload). Use when writing tests for code that resolves feature flags through the OpenFeature SDK or the Unleash / Flagsmith / GrowthBook native SDKs; LaunchDarkly has its own skill (launchdarkly-testing).