功能标志实验验证器

testland2026-10-25查看 1762复制 1486

验证 A/B / 功能开关实验结果的统计显著性——计算每项指标的效应量 + p 值(比例指标用卡方检验,连续指标用 Welch t 检验),当指标数 N>1 时应用多重比较校正(Bonferroni / Benjamini-Hochberg),揭示实际显著性与统计显著性的区别,并针对每项指标输出发布/不发布判定。适用于实验已结束、有人即将依据仪表盘结果发布获胜变体……

Download (.md)

📘如何使用这个技能

  1. 1
    复制技能内容·点击上方「Copy SKILL.md」复制全部内容,或 Download 下载到本地
  2. 2
    打开你的 AI 客户端·支持 Claude Code、Trae、Cursor、ChatGPT、DeepSeek、Kimi 等任意 AI 助手
  3. 3
    粘贴为系统提示/知识文件·Claude Code:放入 .claude/skills/ 目录;普通对话:作为首条消息发送并说「请严格按这份技能文档执行」
  4. 4
    直接提出你的需求·AI 会按技能定义的工作流、格式和约束来处理,无需再解释背景

💡 提示:技能生效后,每次对话只需一句需求,AI 会按 SKILL.md 的流程执行。

SKILL.md9089 chars
---
name: feature-flag-experiment-validator
description: "Validates the statistical significance of an A/B / feature-flag experiment result - computes per-metric effect size + p-value (chi-square for proportions, Welch's t-test for continuous metrics), applies a multiple-comparison correction (Bonferroni / Benjamini-Hochberg) when N>1 metric, surfaces practical-vs-statistical-significance distinction, and emits a ship/don't-ship verdict per metric. Use when an experiment has finished and someone is about to ship the winning variant off a dashboard readout, when a result rests on a small sample, or when more than one metric was compared - the rigorous version of \"the variant looks better in the dashboard.\""
---

# feature-flag-experiment-validator

## Overview

An **experiment toggle** A/B test routes each user into a cohort,
measures behavior per cohort, and ships the winning variant. A/B
tests are "sensitive to variance; they require a large sample size
in order to reduce standard error and produce a statistically
significant result" ([ab-test-wiki][ab]; per-cohort toggle routing
per [feature-toggles][toggles]). Without proper analysis, teams ship
variants that "look better" but aren't actually better. This skill
validates the analysis.

[ab]: https://en.wikipedia.org/wiki/A/B_testing
[toggles]: https://martinfowler.com/articles/feature-toggles.html

## When to use

- An A/B test has run for some time and the team wants the verdict.
- The team's analytics tool (Mixpanel, Amplitude, Statsig) reports
  a winner but the team wants an independent statistical check.
- A multi-metric experiment needs multiple-comparisons correction
  before a ship decision.
- A close-call experiment (treatment 2.1% better; p=0.06) needs
  rigorous interpretation.

## Step 1 - Inputs

The validator needs, per variant:

```yaml
# experiment-data.yml
experiment_id: checkout-promo-banner-v2
running_since: 2026-04-15
running_until: 2026-05-05    # 21 days
hypothesis: "Promo banner increases checkout completion."

variants:
  - name: control
    cohort_size: 12450
    metrics:
      checkout_completion_count: 8523
      avg_session_duration_sec: [...samples...]   # raw samples for continuous metrics
      avg_revenue_per_user: [...samples...]

  - name: treatment_a
    cohort_size: 12380
    metrics:
      checkout_completion_count: 8755
      avg_session_duration_sec: [...samples...]
      avg_revenue_per_user: [...samples...]
```

Per-metric, identify whether it's:

- **Proportion** (count / total - e.g. completion rate, sign-up
  rate, click-through rate).
- **Continuous** (latency, revenue per user, session duration,
  page count).

Different statistical tests apply.

## Step 2 - Test per metric type

### Proportions: chi-square or Fisher's exact

For "did the user convert? yes/no":

```python
from scipy.stats import chi2_contingency

def proportion_test(c_success, c_total, t_success, t_total):
    """Returns (p_value, effect_size_pct)."""
    table = [[c_success, c_total - c_success],
             [t_success, t_total - t_success]]
    chi2, p, dof, _ = chi2_contingency(table)
    c_rate = c_success / c_total
    t_rate = t_success / t_total
    effect = (t_rate - c_rate) / c_rate * 100   # relative lift in %
    return p, effect
```

For very small cells (< 5 expected per cell), Fisher's exact is
more accurate; chi-square otherwise.

### Continuous: Welch's t-test or Mann-Whitney U

For "what's the average revenue per user?":

```python
from scipy.stats import ttest_ind, mannwhitneyu

def continuous_test(c_samples, t_samples, parametric=True):
    """Welch's t-test (parametric) or Mann-Whitney U (non-parametric)."""
    if parametric:
        t, p = ttest_ind(c_samples, t_samples, equal_var=False)
    else:
        u, p = mannwhitneyu(c_samples, t_samples, alternative='two-sided')
    c_mean = sum(c_samples) / len(c_samples)
    t_mean = sum(t_samples) / len(t_samples)
    effect = (t_mean - c_mean) / c_mean * 100
    return p, effect
```

Use **Mann-Whitney U** when the metric isn't normally distributed
(revenue per user - heavy right tail; latency - log-normal).
Welch's t-test for approximately-normal metrics.

## Step 3 - Multiple-comparisons correction

Per [ab-test-wiki][ab]'s "challenges" framing: testing many metrics
inflates the false-positive rate. With α=0.05 and 10 independent
metrics, P(at least one false positive) ≈ 1 - 0.95^10 = 40%.

**Default: Benjamini-Hochberg FDR control** - balances false-positive
vs false-negative rates; controls the proportion of "wins" that are
actually noise. Use Bonferroni when the cost of any false positive is
catastrophic (regulatory / safety contexts) and over-conservatism is
acceptable.

### Benjamini-Hochberg (FDR control)

```python
from statsmodels.stats.multitest import multipletests

reject, p_adj, _, _ = multipletests(p_values, alpha=0.05, method='fdr_bh')
# `reject[i]` is True when metric i is significant after FDR control.
```

### Bonferroni (escape hatch - conservative)

```python
adjusted_alpha = alpha / n_metrics    # e.g. 0.05 / 10 = 0.005
# Each metric must have p < 0.005 to be significant.
```

Over-conservative - increases false negatives.

For pre-registered single-primary-metric experiments, no correction
needed for the primary; correction applies to secondary metrics.

## Step 4 - Power analysis (was the experiment big enough?)

A non-significant result might mean "no effect" or "experiment too
small." Compute post-hoc power:

```python
from statsmodels.stats.power import NormalIndPower

def required_sample(effect_size, alpha=0.05, power=0.8):
    """How many users per variant to detect this effect with this power?"""
    analysis = NormalIndPower()
    return analysis.solve_power(effect_size=effect_size, alpha=alpha, power=power)
```

If the observed effect (e.g., 0.5% relative lift) requires N=50,000
users per variant for 80% power and the experiment had N=12,000,
the experiment was under-powered. The verdict shouldn't be "no
effect"; it should be "inconclusive - re-run at higher N or accept
that we can't detect effects this small."

## Step 5 - Practical vs statistical significance

A 0.1% lift can be statistically significant at N=10M; that doesn't
mean the team should ship.

Define **minimum detectable effect (MDE)** per metric:

```yaml
# mde.yml
checkout_completion_rate:
  mde_relative: 1.0   # 1% relative lift to be worth shipping
  mde_absolute: 0.5   # OR a 0.5pp absolute lift

avg_revenue_per_user:
  mde_absolute: 0.50  # $0.50/user; below this, ship cost > revenue
```

The verdict requires **both** statistical significance AND practical
significance (effect ≥ MDE).

## Step 6 - Output

Emit a per-metric results table (type, control, treatment, relative
effect, raw and adjusted p-value, MDE met, verdict), then a verdict
explanation, a ship/pause recommendation, and a power-analysis note.
Full worked report:
[references/output-example.md](references/output-example.md).

## Step 7 - Recommended cadence

Validate the experiment:

- **At pre-defined stop date** (preferred - pre-registered).
- **At minimum required sample** (per Step 4 power analysis).
- **NOT at "first day of significance"** - peeking at running
  experiments inflates false positives (the "early stopping"
  problem).

If continuous monitoring is required (e.g. a regression-detection
A/B test), use a **sequential testing** framework (`statsmodels`'
sequential probability ratio test) instead of repeated significance
tests.

## Anti-patterns

Seven analysis mistakes and their fixes:
[references/anti-patterns.md](references/anti-patterns.md).

## Limitations

- **Causal inference assumes proper randomization.** If users
  self-select into variants (geography, plan tier), bias is
  uncorrected.
- **No defense against contamination.** Users that switch variants
  mid-experiment violate randomization; flag and exclude.
- **Power analysis is parametric.** Real distributions deviate;
  use bootstrap for non-parametric power estimation.
- **Network effects unmeasured.** A user-level test may underestimate
  effects when treatment users influence control users (social
  features, marketplaces).
- **Doesn't replace product judgment.** A statistically significant
  win that contradicts brand strategy isn't auto-ship.

## References

- [ab-test-wiki][ab] - A/B testing definition; "A/B tests are
  sensitive to variance; they require a large sample size in order
  to reduce standard error and produce a statistically significant
  result"; statistical hypothesis testing framing.
- [feature-toggles][toggles] - experiment toggles: per-cohort
  routing; "highly dynamic ... requires sufficient runtime to
  generate statistically valid results."
- `feature-flag-test-harness` (in the qa-test-environment plugin) - harness that runs the experiment IN test (this skill
  validates the experiment IN production).
- `prod-canary-validator` - 
  sibling: same statistical framework, different application
  (canary verdict vs experiment verdict).
- `synthetic-monitor-author` - sibling: production-side verification, different role.
来源:skillsdirectory

评论0

登录后参与评论

还没有评论,来抢沙发吧