Перейти к основному содержимому

Платформа экспериментов и A/B-тестирования

Версия: 1.0 Дата: 26.04.2026 Статус: Готов к обсуждению

Назначение документа

Документ определяет платформу экспериментов и A/B-тестирования (experimentation framework) Vitiana — стандартизированную инфраструктуру для проведения экспериментов над любыми компонентами платформы. Включает:

  • Каноничную модель эксперимента (Experiment), варианта (ExperimentVariant), назначения (ExperimentAssignment), события воздействия (ExposureEvent).
  • Управление флагами возможностей (feature flags) — включение и выключение возможностей для конкретных когорт.
  • Распределение трафика и сегментацию (traffic allocation, segmentation).
  • Учёт воздействия (exposure tracking) — кто получил какой вариант и при каких условиях.
  • Статистику экспериментов — преднамеренные метрики, расчёт значимости, контроль доли ложных открытий (false discovery rate).
  • Защиту от пересечения экспериментов (experiment interference).
  • Интеграцию с ML-платформой для экспериментов над моделями.
  • Защиту от типичных подводных камней A/B-тестирования.
  • Фазы развёртывания.

Документ читается после:

В корневых документах зафиксировано что платформа экспериментов делает и где применяется. Этот документ описывает как — каноничные сущности, поток назначения, статистику, защиту, фазы.

A/B-тестирование — общая инфраструктура продукта, не отдельный проект и не «фича на потом». Каждое существенное изменение поверхности взаимодействия, каждая новая ML-модель, каждое изменение коммерческих правил — проходит через эксперимент перед полным rollout. Это закон современных лучших практик платформ верхнего уровня.

Правило 00000 (платформа главенствует над поставщиками) применяется здесь напрямую: эксперименты ставятся над каноничными решениями платформы, не над особенностями интеграций конкретных поставщиков. Поставщик не может «отказаться» от участия в эксперименте платформы — он либо принимает каноничный поток, либо отключается.

Главное решение

Эксперимент — продуктовая способность платформы, а не ad-hoc хак в коде.

Это означает:

  • Эксперименты — структурированные сущности в каноничной модели, не флаги в коде.
  • Флаги возможностей и эксперименты — единая платформа, не два разных инструмента. Простое включение возможности — это эксперимент с одним вариантом и 100% трафика; A/B-сравнение — эксперимент с двумя вариантами и распределением трафика; постепенный rollout (canary) — эксперимент с увеличивающимся процентом трафика.
  • Назначение — детерминированное и стабильное — конкретный субъект эксперимента (актёр, тенант, сессия) попадает в один и тот же вариант на всём протяжении эксперимента, не перепрыгивает.
  • Воздействие фиксируется — каждое решение «показать вариант X субъекту Y» порождает событие воздействия, попадающее в платформу данных.
  • Статистика встроена — расчёт значимости, доверительных интервалов, контроля доли ложных открытий — не «руками в Excel», а часть платформы.
  • Защита от пересечения — эксперименты, которые могут влиять друг на друга, либо разносятся по непересекающимся когортам, либо стратифицируются.
  • Аудит и compliance — каждый эксперимент журналируется, имеет ответственного, имеет связь с бизнес-метрикой.

Каноничная модель экспериментов

Главные сущности

Experiment — эксперимент

Сущность, представляющая один эксперимент платформы.

{
experiment_id: UUID,
experiment_key: string,
experiment_name: string,
experiment_namespace: string,
experiment_class: enum,
hypothesis: string,
primary_metric: string,
secondary_metrics: array,
guardrail_metrics: array,
applicable_surfaces: array,
applicable_tenants: array,
segmentation_rules: object,
exclusion_rules: array,
randomization_unit: enum,
total_variants: integer,
state: enum,
duration_target: object,
significance_threshold: numeric,
power_target: numeric,
minimum_detectable_effect: numeric,
experiment_owner: string,
approving_role: string,
approved_at: timestamp,
started_at: timestamp,
ended_at: timestamp,
conclusion: object,
tags: array
}

Поля:

  • experiment_key — короткий уникальный ключ для использования в коде и в флагах.
  • experiment_class — класс эксперимента: feature_rollout (постепенное включение возможности) / ab_comparison (сравнение двух или более вариантов) / multivariate (несколько факторов одновременно) / holdback (временное удержание группы без новой возможности для долгосрочного измерения) / kill_switch (мгновенное выключение возможности при проблеме).
  • primary_metric — главная метрика, по которой принимается решение.
  • secondary_metrics — дополнительные метрики для контекста.
  • guardrail_metrics — защитные метрики, ухудшение которых блокирует объявление эксперимента успешным даже при росте главной метрики.
  • randomization_unit — единица рандомизации: actor / session / tenant / device / request. Выбор зависит от характера эксперимента.
  • segmentation_rules — правила, кому показывать эксперимент (например, только тенантам тарифа Professional, только из географии PL).
  • exclusion_rules — правила исключения (например, исключить корпоративных партнёров из экспериментов над ранжированием).
  • significance_threshold — порог значимости (типично 0.05).
  • power_target — целевая мощность (типично 0.8).
  • minimum_detectable_effect — минимальный обнаруживаемый эффект, на который рассчитан эксперимент (нужен для расчёта размера выборки).
  • approving_role — роль, обязанная одобрить эксперимент перед запуском (для критичных экспериментов в платежах — финансовая команда; для ранжирования поиска — продуктовая).
  • state — состояние (draft / pending_approval / approved / running / paused / concluded / rolled_back).

ExperimentVariant — вариант эксперимента

Каждый эксперимент имеет от одного до нескольких вариантов.

{
variant_id: UUID,
experiment_id: UUID,
variant_key: string,
variant_label: string,
is_control: boolean,
configuration: object,
traffic_share: numeric,
ml_model_version: string,
feature_flag_values: object,
sticky: boolean
}

Поля:

  • variant_key — уникальный ключ (типично control, treatment_a, treatment_b).
  • is_control — отметка контрольного варианта (один на эксперимент).
  • configuration — конкретная конфигурация варианта (для эксперимента с ранжированием — какая RankingPolicy; для эксперимента с тарифами — какая структура цены).
  • traffic_share — доля трафика этого варианта (от 0 до 1, сумма по всем вариантам = 1).
  • ml_model_version — для ML-экспериментов: версия модели в этом варианте.
  • feature_flag_values — значения флагов возможностей в этом варианте.
  • sticky — должно ли назначение варианта оставаться при повторных запросах того же субъекта (типично true для пользовательских экспериментов).

ExperimentAssignment — назначение в эксперимент

Сущность, представляющая факт того, что конкретный субъект назначен в конкретный вариант эксперимента.

{
assignment_id: UUID,
experiment_id: UUID,
variant_id: UUID,
subject_type: enum,
subject_hash: string,
assigned_at: timestamp,
expires_at: timestamp,
assignment_reason: enum,
override_source: string
}

Поля:

  • subject_type — тип субъекта (actor / session / tenant / device).
  • subject_hash — анонимизированный идентификатор субъекта (хеш для согласования с правилами приватности).
  • assignment_reason — почему именно этот вариант (hash_based_random — детерминированно по хешу; forced_override — ручная установка для отладки; segmentation_match — попадание в сегмент с определённым вариантом).
  • override_source — если назначение принудительное, кто его установил (для журнала).

ExposureEvent — событие воздействия

Каноничное аналитическое событие, фиксирующее момент показа варианта эксперимента субъекту.

{
exposure_id: UUID,
assignment_id: UUID,
experiment_id: UUID,
variant_id: UUID,
exposed_at: timestamp,
exposure_context: object,
exposed_value: object
}

Каждое решение «показать пользователю результат экспериментального ранжирования» / «применить экспериментальный тариф» / «использовать экспериментальную модель» — порождает ExposureEvent. Это критическая сущность для последующего анализа: только субъекты с ExposureEvent входят в анализ эксперимента.

Без события воздействия пользователь, назначенный в вариант, но не получивший воздействия (например, не открывший страницу), не считается экспонированным. Это правильная модель — иначе эксперимент мерил бы эффект на не получивших воздействия пользователях, что некорректно статистически.

FeatureFlag — флаг возможности

Сущность, представляющая управляемую переменную в коде, значение которой зависит от субъекта.

{
flag_id: UUID,
flag_key: string,
flag_name: string,
flag_namespace: string,
flag_type: enum,
default_value: any,
current_rollout: object,
used_in_experiments: array,
owners: array,
schema_version: string,
created_at: timestamp,
updated_at: timestamp
}

Поля:

  • flag_type — тип значения (boolean / string / numeric / json).
  • default_value — значение по умолчанию для субъектов, не попадающих в эксперимент.
  • current_rollout — текущее правило раскатки (может быть привязано к эксперименту или быть статическим).
  • used_in_experiments — список экспериментов, использующих этот флаг.

Флаги возможностей и эксперименты — связанные сущности одной платформы. Простой флаг возможности (без эксперимента) — это вырожденный эксперимент с одним вариантом и 100% трафика, для администрирования флагов используется тот же интерфейс.

Связь с другими каноничными сущностями

  • MlExperiment из Платформа машинного обучения — реализуется как Experiment с experiment_class: ab_comparison и randomization_unit: actor, где варианты содержат разные ml_model_version.
  • RankingPolicy.experiment_id из Поиск и обнаружение — ссылка на эксперимент, определяющий стратегию ранжирования для конкретной сессии.
  • ExposureEvent — попадает в Платформа данных и захват событий как поведенческое событие класса experiment_exposure.
  • Tenant определяет, к каким экспериментам тенант присоединяется (через applicable_tenants и segmentation_rules).
  • Actor определяет, в какой вариант попадает субъект (через randomization_unit и хеширование).

Поток назначения и фиксации воздействия

Запрос на поверхности взаимодействия

Идентификация субъекта (actor_hash / session_id / tenant_id)

Получение списка активных экспериментов, применимых к субъекту

Для каждого применимого эксперимента:

├── Применение правил сегментации (только если попадает)
├── Применение правил исключения (если попадает — пропуск)
├── Детерминированный хеш subject_id + experiment_id
├── Назначение варианта по traffic_share

Возврат назначений как набор {experiment_key: variant_key}

Получение значений флагов возможностей из назначенных вариантов

Применение значений флагов в логике обработки запроса

В момент использования флага — публикация ExposureEvent

Возврат результата запроса

Детерминированное назначение

Назначение варианта детерминировано по формуле:

hash_value = stable_hash(subject_id + experiment_id + experiment_seed)
variant = bucket_lookup(hash_value, variant_traffic_shares)

Свойства:

  • Стабильность — один и тот же субъект всегда получает один и тот же вариант (пока эксперимент активен).
  • Независимость от других экспериментовexperiment_seed гарантирует, что разные эксперименты дают независимые назначения для одного субъекта (защита от пересечения).
  • Возможность ручного override — для отладки роль может принудительно назначить конкретный вариант конкретному субъекту через forced_override.

Запрет вычисления назначения «налету» в каждом сервисе

Назначение рассчитывается в централизованном сервисе экспериментов, не в каждом потребляющем сервисе. Это даёт:

  • Единую логику применения правил сегментации.
  • Единый журнал назначений.
  • Защиту от рассинхронизации (если разные сервисы реализуют логику немного по-разному, субъект может попасть в разные варианты в разных сервисах).
  • Возможность изменения правил без релизов потребляющих сервисов.

Кэширование назначений

Назначения кэшируются на стороне потребляющих сервисов:

  • Срок жизни кэша — порядка минут.
  • Инвалидация — при изменении эксперимента (старт, пауза, остановка, изменение трафика).
  • Кэш не хранит чувствительных данных — только хеш субъекта и назначенный вариант.

Управление флагами возможностей

Жизненный цикл флага

Создание флага в реестре

Default value = безопасное «выключено»

Развёртывание кода, использующего флаг

Тестовая активация для команды (через override)

Эксперимент с постепенным rollout

├── Эксперимент успешен — повышение default value
│ ↓
│ Удаление кода с флагом (cleanup) — обязательно

├── Эксперимент неуспешен — флаг остаётся выключен

Удаление кода с флагом (cleanup) — обязательно

Запрет «вечных флагов»

Флаги — временное средство, не постоянная архитектура. После завершения эксперимента и принятия решения код, использующий флаг, удаляется. Если флаг остаётся на продолжительное время — это архитектурный долг.

Платформа поддерживает отчёт о застрявших флагах (stale flags report) — флаги, не использовавшиеся в активных экспериментах последние N месяцев. Этот отчёт раз в квартал передаётся командам для очистки.

Исключения (вечные флаги, осознанно):

  • kill_switch-флаги для аварийного отключения возможностей. Остаются всегда.
  • Тенантные конфигурации, которые правомерно различаются между тенантами (например, какие провайдеры платёжных услуг доступны конкретному тенанту). Это не A/B-эксперимент, а конфигурация — реализована через tenant_configuration (см. Тенантная настройка), не через флаги.

Распределение трафика и сегментация

Базовое распределение

Каждый вариант эксперимента имеет traffic_share от 0 до 1. Сумма по всем вариантам = 1. Распределение — равномерное по детерминированному хешу.

Постепенный rollout

Для класса feature_rollout доли трафика меняются со временем по расписанию:

День 0: control 95% / treatment 5%
День 3: control 90% / treatment 10%
День 7: control 75% / treatment 25%
День 14: control 50% / treatment 50%
День 21: control 0% / treatment 100% (полный rollout)

Это даёт постепенное снижение риска при отключении возможности.

Сегментация

Применение к подмножеству трафика по правилам:

  • По тенанту — только определённые тенанты, классы тенантов, тарифы.
  • По поверхности — только потребительская витрина, только партнёрский интерфейс, и так далее.
  • По географии — только определённые регионы или страны.
  • По языку — только определённые языки интерфейса.
  • По платформе — desktop / mobile / SDK partner.
  • По характеристикам сессии — только новые пользователи, только повторные.

Стратифицированная рандомизация

Когда характеристики субъекта (например, размер партнёра по объёму запросов) могут влиять на исход, применяется стратифицированная рандомизация: субъекты сначала разбиваются на страты, внутри каждой страты — независимая рандомизация. Это снижает дисперсию результата и повышает мощность эксперимента.

Защита от пересечения экспериментов

Проблема

Когда несколько экспериментов работают одновременно над пересекающимся трафиком, они могут влиять друг на друга:

  • Эксперимент над ранжированием поиска влияет на конверсию, что искажает измерение эксперимента над ценообразованием.
  • Эксперимент над уведомлениями влияет на возврат пользователей, что искажает измерение эксперимента над пользовательским интерфейсом.

Это называется interference between experiments.

Решения

Решение 1. Layered experimentation

Эксперименты разделяются на слои (layers). Внутри одного слоя одновременно работает максимум один эксперимент над одним субъектом. Между слоями назначения независимы. Слои выбираются так, чтобы эксперименты в одном слое теоретически могли влиять друг на друга, а в разных — нет.

Пример слоёв:

  • Слой ранжирования поиска — эксперименты над RankingPolicy.
  • Слой ценообразования — эксперименты над динамическим ценообразованием платформенных услуг.
  • Слой пользовательского интерфейса B2C — визуальные эксперименты на потребительской витрине.
  • Слой коммуникаций — эксперименты над уведомлениями.

Один субъект может быть одновременно в эксперименте слоя ранжирования и слоя коммуникаций — они не пересекаются.

Решение 2. Mutual exclusion для критических экспериментов

Для критических экспериментов (например, два разных подхода к динамическому ценообразованию) может быть явное правило взаимного исключения: «Если субъект в эксперименте A, не назначается в эксперимент B».

Решение 3. Анализ пересечений

При анализе результатов эксперимента учитывается, в каких других экспериментах был субъект, и эффект пересечения отдельно оценивается.

Запрет одновременного эксперимента над одной поверхностью

Запрещено: запуск двух экспериментов, одновременно меняющих один и тот же элемент (например, два эксперимента над текстом одной кнопки). Это блокируется на уровне регистрации эксперимента — система проверяет, не пересекается ли новый эксперимент с активными по правилам сегментации и применимым флагам.

Учёт воздействия (exposure tracking)

Главное правило: только экспонированные субъекты учитываются

Только субъекты, для которых зафиксировано событие воздействия (ExposureEvent), входят в анализ эксперимента. Субъекты, назначенные в вариант, но не получившие воздействия, исключаются.

Пример: эксперимент над модальным окном на странице оплаты. Субъект назначен в экспериментальный вариант, но не дошёл до страницы оплаты — он не получил воздействия и в анализе не учитывается. Это правильно — иначе эксперимент мерил бы эффект на не дошедших до страницы пользователях.

Триггеры публикации события воздействия

ExposureEvent публикуется в момент использования значения флага возможности в логике, влияющей на ответ пользователю:

  • При показе ранжированной выдачи поиска — для эксперимента ранжирования.
  • При расчёте цены при коммерческой фиксации — для эксперимента ценообразования.
  • При отправке уведомления — для эксперимента коммуникаций.
  • При показе версии пользовательского интерфейса — для визуального эксперимента.

Идемпотентность

Несколько последовательных вызовов одного и того же значения флага для одного субъекта в рамках одного запроса — публикуют одно событие воздействия. Это контролируется на стороне сервиса экспериментов через локальный кэш в рамках запроса.

Защита от ложных событий воздействия

Невозможно сфабриковать ExposureEvent без реального назначения. Платформа проверяет:

  • assignment_id существует в журнале назначений.
  • subject_hash соответствует субъекту, инициировавшему событие.
  • Окно времени между назначением и воздействием — разумное.

Статистика экспериментов

Преднамеренные метрики

Каждый эксперимент имеет:

  • Главную метрику (primary metric) — одну, по которой принимается решение.
  • Вторичные метрики (secondary metrics) — для контекста, не для решения.
  • Защитные метрики (guardrail metrics) — метрики, ухудшение которых блокирует объявление эксперимента успешным даже при росте главной.

Пример эксперимента над ML-ранжированием поиска:

  • Главная: конверсия поиск → коммерческая фиксация.
  • Вторичные: глубина просмотра, доля отказов, время на странице.
  • Защитные: средняя задержка отклика поиска, процент ошибок поиска.

Расчёт значимости

Платформа рассчитывает:

  • p-value для основной метрики (типично через t-test или Mann-Whitney U).
  • Доверительный интервал для эффекта (типично 95%).
  • Размер эффекта (effect size) — relative и absolute.
  • Мощность эксперимента (achieved power) — фактически достигнутая мощность с учётом полученной выборки.

Контроль доли ложных открытий (false discovery rate, FDR)

Когда в эксперименте измеряется множество метрик одновременно, доля ложных открытий растёт. Платформа применяет коррекцию Бенджамини-Хохберга (Benjamini-Hochberg) для контроля FDR — вместо простого порога значимости.

Sequential testing

Стандартный t-test предполагает фиксированный размер выборки. Если эксперимент анализируется многократно по ходу (peeking), частота ложных срабатываний растёт. Платформа применяет методы последовательного тестирования (sequential testing) — например, mSPRT (Mixture Sequential Probability Ratio Test) или Bayesian методы — для корректного многократного анализа.

Запрет ручного «p-hacking»

Запрещено:

  • Изменение определения главной метрики после старта эксперимента.
  • Изменение правил сегментации после старта.
  • Анализ десятков подгрупп до получения «значимого» результата (multiple hypothesis without correction).
  • Раннее завершение эксперимента «потому что результат значим» без учёта sequential testing.

Платформа фиксирует определение метрик и правила в момент запуска, и любое изменение требует повторного одобрения и сброса собранных данных.

Минимальный размер выборки

При запуске эксперимента платформа рассчитывает необходимый размер выборки на основе:

  • minimum_detectable_effect — минимальный обнаруживаемый эффект.
  • significance_threshold (типично 0.05).
  • power_target (типично 0.8).
  • Базовой дисперсии главной метрики.

Эксперимент не может быть завершён успешным до достижения этого размера выборки (за исключением случаев очевидной деградации защитных метрик — тогда эксперимент останавливается как неуспешный).

Защита от типичных подводных камней

1. Загрязнение выборки (sample contamination)

Проблема: субъект попал в обе группы (control и treatment) из-за бага.

Защита:

  • Проверка: каждый subject_hash имеет максимум одно назначение в активном эксперименте.
  • Алерт: если в журнале назначений один субъект встречается в обеих группах.

2. Неконсистентное назначение (inconsistent assignment)

Проблема: один и тот же субъект получил разные назначения в разных запросах.

Защита:

  • Детерминированное назначение по хешу.
  • Журнал назначений с возможностью аудита.
  • Алерт при обнаружении неконсистентности.

3. Корреляция назначения с влиятельными ковариатами

Проблема: случайная неравномерность распределения создаёт впечатление эффекта эксперимента.

Защита:

  • Стратифицированная рандомизация по ключевым ковариатам.
  • Анализ ковариатного баланса (covariate balance check) до начала анализа эффекта.

4. Эффект новизны (novelty effect)

Проблема: пользователи иначе реагируют на новый вариант просто потому, что он новый, а не из-за самого изменения. Через время эффект исчезает.

Защита:

  • Долгие эксперименты (минимум 14 дней).
  • Holdback-эксперименты для долгосрочного измерения.

5. Сетевой эффект (network effects)

Проблема: эксперимент над одним пользователем влияет на других пользователей (например, эксперимент над уведомлениями партнёра влияет на конечных клиентов партнёра).

Защита:

  • Рандомизация на уровне сети, а не индивидуума (например, по тенанту, не по конечному клиенту).
  • Кластерная рандомизация (cluster randomization).

6. Отзыв и compliance

Проблема: эксперимент над персонализацией ранжирования может попасть под Закон о цифровых услугах и требовать прозрачности.

Защита:

  • Документация всех экспериментов с участием рекомендательных систем.
  • Возможность пользователя отказаться от участия в экспериментах с персонализацией (opt-out).

Интеграция с ML-платформой

Эксперименты над ML-моделями

MlExperiment из Платформа машинного обучения реализуется как Experiment платформы экспериментов:

  • experiment_class: ab_comparison.
  • randomization_unit: actor (типично).
  • Каждый ExperimentVariant содержит ссылку на ml_model_version.
  • В момент инференса (MlInferenceRequest) платформа экспериментов возвращает назначение, и сервис обслуживания моделей вызывает соответствующую версию.
  • ExposureEvent публикуется в момент применения результата инференса.

Shadow mode

Для критических ML-моделей применяется shadow mode: новая версия модели работает параллельно со старой, не влияя на боевые ответы. Это эксперимент с одним вариантом в ExperimentVariant.is_shadow: true.

В shadow mode:

  • Каждый запрос обрабатывают обе версии модели.
  • Боевой ответ возвращается из старой версии.
  • Результаты новой версии сравниваются с старой и логируются для анализа.
  • Воздействие новой версией на пользователя — нулевое.

Это даёт максимально безопасную проверку модели перед реальным A/B.

Bandit алгоритмы (фаза 4)

Для динамической оптимизации (например, ценообразования) рассматриваются многорукие бандиты (multi-armed bandits) — алгоритмы, балансирующие исследование (exploration) новых вариантов и эксплуатацию (exploitation) лучших. Это эволюция классического A/B и реализуется как расширение платформы.

Интеграция с платформой данных

Канал событий воздействия

Все ExposureEvent попадают в Платформа данных и захват событий через tracking pipeline в класс experiment_exposure. В DWH доступны таблицы:

  • fact_experiment_exposures — все события воздействия.
  • dim_experiment — описание экспериментов.
  • dim_experiment_variant — описание вариантов.

Аналитический пайплайн

Анализ эксперимента — стандартный поток в gold layer DWH:

  1. Связывание событий воздействия с метриками за период наблюдения.
  2. Расчёт средних, дисперсий, p-value, доверительных интервалов.
  3. Применение sequential testing коррекций.
  4. Контроль защитных метрик.
  5. Готовая витрина результатов экспериментов в дашборде.

Real-time мониторинг во время эксперимента

Помимо итогового анализа платформа предоставляет real-time мониторинг:

  • Текущее распределение трафика по вариантам (для проверки корректности назначения).
  • Текущие значения защитных метрик (для возможности досрочной остановки при деградации).
  • Текущие значения главной метрики (для информации, но не для решения — решение принимается по итогу с учётом sequential testing).

События платформы экспериментов

СобытиеКогдаГлавные потребители
experiment.createdСоздание эксперимента в реестреКонтур аудита, документация
experiment.approvedОдобрение эксперимента к запускуКонтур экспериментов
experiment.startedНачало экспериментаСервис назначений, контур наблюдаемости
experiment.pausedПриостановкаКонтур наблюдаемости, оперативная команда
experiment.concludedЗавершение с выводомКонтур аналитики, контур аудита
experiment.assignment.createdНазначение субъекта в вариантПлатформа данных
experiment.exposure.recordedФиксация воздействияПлатформа данных, gold layer
experiment.guardrail.violatedНарушение защитной метрикиКонтур наблюдаемости, оперативная команда (auto-pause или alert)
feature_flag.createdРегистрация нового флагаКонтур документации
feature_flag.cleanup.requiredФлаг устарел и требует удаленияКоманда-владелец, контур технического долга

Полная таксономия — в Первоначальная таксономия событий.

Технологический выбор по фазам

ФазаСервис экспериментовХранение назначений и флаговАналитика результатов
Bootstrap(нет — ручные feature flags в коде)Файл конфигурации в репозиторииБазовый SQL по логам
2 (Production)Unleash open-source self-hostedPostgreSQL для конфига, Redis для назначенийСтандартный анализ через DWH
3 (Scale)Расширенный Unleash или собственный сервисРаспределённое хранилище назначенийРасширенный анализ с sequential testing, FDR
4 (Multi-region)Multi-region сервис экспериментовMulti-region назначения с локальной инвалидациейFederated анализ, bandits

Конкретный выбор технологий — Развилка 3 «A/B testing framework — собственный или внешний» из оси данных и интеллекта. Решение этого документа: на фазе 2 — Unleash open-source self-hosted как baseline (консистентно с остальной open-source архитектурой). LaunchDarkly как commercial альтернатива остаётся возможной, но имеет vendor lock-in и стоимость по числу субъектов, что плохо масштабируется на маркетплейс программных интерфейсов.

Учёт расходов на эксперименты

Эксперименты — дешёвый компонент платформы (легковесный сервис назначений). Учёт минимальный:

  • Все эксперименты атрибутируются командам-владельцам для отчётности по продуктовому развитию.
  • Защитные метрики защищают от случайных операционных расходов (эксперимент, ухудшающий конверсию, останавливается до накопления больших потерь).

Фазы развёртывания

Фаза Bootstrap (0–6 месяцев)

Что разворачивается:

  • Каноничная модель (Experiment, ExperimentVariant, ExperimentAssignment, ExposureEvent, FeatureFlag) зафиксирована.
  • Простые feature flags в файле конфигурации репозитория для прототипирования.
  • Базовое логирование воздействий в общий лог.

Триггер выхода:

  • Первый партнёр в боевом режиме — нужна возможность безопасного rollout новых возможностей.

Фаза 2 — Базовая платформа экспериментов (6–18 месяцев)

Что разворачивается:

  • Unleash self-hosted как сервис экспериментов и флагов.
  • Детерминированное назначение по хешу.
  • Сегментация по тенанту, поверхности, географии.
  • Постепенный rollout (canary).
  • Базовый exposure tracking через платформу данных.
  • Базовый анализ экспериментов через дашборды Grafana поверх DWH.
  • Холдбек-эксперименты для долгосрочного измерения.

Триггер выхода:

  • Появление первых ML-экспериментов — нужна интеграция с ML-платформой.
  • Появление десятков параллельных экспериментов — нужна layered experimentation.

Фаза 3 — Зрелая платформа экспериментов (18–30 месяцев)

Что разворачивается:

  • Layered experimentation для защиты от пересечения.
  • Стратифицированная рандомизация.
  • Sequential testing для корректного многократного анализа.
  • Контроль доли ложных открытий (FDR).
  • Интеграция с ML-платформой (shadow mode, A/B над моделями).
  • Real-time мониторинг защитных метрик с автоматической паузой при нарушении.
  • Расширенный анализ с расчётом мощности и минимального размера выборки.

Фаза 4 — Расширенные эксперименты (30+ месяцев)

Что разворачивается:

  • Multi-armed bandits для динамической оптимизации.
  • Кластерная рандомизация для защиты от сетевых эффектов.
  • Multi-region инфраструктура экспериментов.
  • Прозрачность для регулятора по Закону о цифровых услугах (отчёты о персонализирующих экспериментах).
  • Возможность opt-out пользователя из экспериментов с персонализацией.

Архитектурные решения с тезисным обоснованием

Решение 1. Эксперименты — структурированные сущности, не флаги в коде

Цель: обеспечить аудит, статистическую корректность и compliance каждого эксперимента.

Тезисы:

  1. Без структурированной модели эксперименты разбросаны по коду в виде флагов. Невозможно ответить на вопрос «что мы тестировали в марте».
  2. Структурированная модель даёт автоматический аудит, журнал, сравнение результатов между экспериментами.
  3. Современные платформы (Stripe, Airbnb, Booking.com, Netflix) — все построены на структурированных платформах экспериментов. Это база.

Решение 2. Флаги возможностей и эксперименты — единая платформа

Цель: избежать двух разных систем с разной семантикой и возможной рассинхронизацией.

Тезисы:

  1. Флаг возможности — это вырожденный эксперимент с одним вариантом и 100% трафика. Семантически они одно и то же.
  2. Унификация даёт единый интерфейс администрирования.
  3. Унификация даёт защиту от пересечения (флаги в одном слое не пересекаются с экспериментами того же слоя).

Альтернатива: разные системы для флагов (например, для оперативного управления) и для экспериментов (для статистического анализа). Отклонено: дублирование, сложность поддержки.

Решение 3. Только экспонированные субъекты в анализе

Цель: обеспечить статистическую корректность результатов.

Тезисы:

  1. Если включать в анализ субъектов, назначенных, но не получивших воздействия — измеряется не эффект изменения, а смесь.
  2. Это самая частая методологическая ошибка в индустрии. Stripe, Airbnb, Microsoft публиковали разборы инцидентов на эту тему.
  3. Архитектурное решение (ExposureEvent как обязательный фильтр) защищает от ошибки независимо от добросовестности аналитика.

Решение 4. Sequential testing вместо фиксированного размера выборки

Цель: позволить досрочную остановку успешных экспериментов и снизить расходы на длинные эксперименты при сохранении корректности.

Тезисы:

  1. Классический t-test с peeking даёт ложные срабатывания. Это известная проблема.
  2. Sequential testing методы (mSPRT, Bayesian) — стандарт индустрии для платформ масштаба.
  3. Дополнительные расходы на реализацию окупаются возможностью досрочной остановки.

Решение 5. Layered experimentation для защиты от пересечения

Цель: позволить запуск десятков параллельных экспериментов без взаимного загрязнения.

Тезисы:

  1. На масштабе платформы одновременно идут десятки экспериментов. Без layered experimentation либо они мешают друг другу, либо приходится ждать в очереди.
  2. Это паттерн крупных платформ (Booking.com сообщал о тысячах одновременных экспериментов).
  3. Архитектурное разделение слоёв даёт инженеру возможность создавать эксперименты без необходимости анализа конфликтов с десятками других.

Открытые развилки

Развилка 1. Конкретный движок экспериментов — Unleash vs LaunchDarkly vs собственный

Решено в этом документе на фазе 2: Unleash open-source self-hosted. На фазе 3+ может потребоваться расширение или замена. LaunchDarkly остаётся как commercial альтернатива при достижении определённого порога возможностей и операционных расходов.

Эскалируется: при выходе на масштаб, когда возможностей Unleash недостаточно.

Развилка 2. Формальный язык определения метрик

Метрики экспериментов (главная, вторичные, защитные) могут быть определены либо через декларативный язык в реестре, либо через ad-hoc SQL для каждого эксперимента. Декларативный — лучше для переиспользования и валидации, ad-hoc — гибче.

Эскалируется: при выходе на десятки одновременных экспериментов.

Развилка 3. Bandit-алгоритмы — приоритет внедрения

В каких применениях многорукие бандиты приоритетны: динамическое ценообразование? Ранжирование поиска? Рекомендации? Зависит от бизнес-приоритетов.

Эскалируется: в фазе 4 при создании плана развития платформы экспериментов.

Развилка 4. Подход к compliance Закона о цифровых услугах

Закон о цифровых услугах требует прозрачности рекомендательных систем и возможности opt-out для конечных пользователей. Конкретная реализация (где показывать, как описывать) — открытая развилка.

Эскалируется: при детальной проработке с командой compliance.

Развилка 5. Платформа экспериментов для тенантов как продукт

В фазе 4 возможна экспозиция платформы экспериментов для крупных корпоративных тенантов как часть тарифа Enterprise — возможность тенанту проводить собственные A/B-эксперименты в своей области взаимодействия с платформой. Это коммерческая возможность, расширяющая аналитический продукт.

Эскалируется: при создании Аналитика и BI и при появлении партнёрских запросов.

Связанная документация

Корневые архитектурные документы

Связанные доменные документы

Документы развития

Операционная сторона

Архитектурные правила

Уточнение под Фазы 5–6 (28.04.2026) — связь с capability set, isolation, security

Документ опубликован 26.04.2026 в Фазе 4. После Фаз 5–7 платформа A/B testing интегрирована с дополнительными доменами; эта секция фиксирует обязательные связи.

Связь с capability-aware UI

reference/clients.md (Фаза 7) фиксирует canonical capability_set resolver через GET /capability/me. Каноничные capabilities A/B platform:

  • experiment.assign — присвоение subject к variant;
  • experiment.exposure — захват exposure event;
  • experiment.metrics.read — чтение experiment metrics (для analysts);
  • experiment.create (admin) — создание experiment;
  • experiment.publish (admin) — переход experiment в production;
  • feature_flag.evaluate — evaluation flag для subject;
  • feature_flag.create, feature_flag.modify (admin).

Эти capabilities — часть общей capability matrix (см. clients.md).

Связь с уровнями тенантной изоляции

reference/multi-tenant-isolation-strength.md (Фаза 5) определяет:

Tenant-scoped vs platform-wide эксперименты:

  • Platform-wide — для собственных surfaces (vitrip.store B2C, agency UI), tenant boundary не применяется;
  • Tenant-scoped — partner-specific эксперименты (по запросу Enterprise tenant), не должны влиять на других tenants;
  • Cross-tenant эксперименты — запрещены без явного opt-in каждого tenant и compliance review.

Cohort assignment правила:

  • assignment per (experiment_id, subject_id) пара — детерминирован, hash-based;
  • subject_id — anonymized (hashed user_id или session_id), не PII;
  • tenant_id — обязательный component cohort key для tenant-scoped экспериментов;
  • assignment не пересекает tenant boundary (subject из tenant A не получает variant из experiment tenant B).

Связь со security архитектурой

reference/security-architecture.md (Фаза 10) — A/B platform threats:

  • Manipulation of cohort assignment — атакующий пытается попасть в специфический variant → детерминированный hash-based assignment, не overrideable;
  • Exposure event manipulation — false exposure events для skewing experiment results → server-side validation, audit log;
  • Feature flag bypass — обход feature flag для unauthorized access → flags как defence in depth, не primary security control;
  • Cross-tenant exposure — leak experiment configuration или results между tenants → tenant boundary в каждом запросе.

A/B platform события (experiment.assigned, experiment.exposure, experiment.completed) — analytical events с anonymized subject_id; не audit log.

reference/compliance-and-legal.md (Фаза 4) определяет:

  • GDPR consent — для B2C surfaces (vitrip.store) cookies для cohort assignment требуют explicit consent (analytics category);
  • если subject отказался от analytics consent — exposure events не fire, subject не assigned to non-essential experiments (только critical UX experiments через legitimate interests basis);
  • Right to opt-out из automated decision-making — subject может отказаться от participation в experiments через privacy settings;
  • Data minimization — exposure events содержат минимум информации (subject_id_hash, experiment_id, variant_id, timestamp);
  • Retention — experiment data удаляется после analysis_window + 30 дней (типично 90 дней).

Связь с ML-платформой

reference/ml-platform.md (Фаза 4) — A/B platform для ML model deployment:

  • Shadow deployment — новая модель работает параллельно с production, predictions не используются в decisions, но логируются для сравнения;
  • Canary deployment — % трафика на новую модель (например, 1% → 10% → 50% → 100%);
  • Multi-armed bandit — для optimization use cases где applicable;
  • Guardrail metrics — критические метрики, при ухудшении которых experiment автоматически останавливается.

ML model deployment обязательно через A/B platform для critical use cases (search ranking, dynamic pricing, recommendation, fraud detection).

Связь со SLA-моделью

operations/sla-and-on-call-model.md (Фаза 6) — A/B platform имеет internal SLA:

  • assignment latency p95 — менее 10мс (критично для search/ranking flow);
  • exposure event delivery — at-least-once с допустимой задержкой;
  • experiment configuration sync — менее 60 секунд от создания до effectivity.

Каноничный итог уточнения

A/B platform интегрирована с:

  • Capability-aware через clients.md;
  • Tenant-scoped vs platform-wide через multi-tenant-isolation-strength;
  • GDPR consent через compliance-and-legal;
  • Security threats через security-architecture;
  • ML deployment через ml-platform;
  • Internal SLA через sla-and-on-call-model.

Уточнение выполнено через no-destruction.