Кэш + A/B-тест: если ключ не знает про вариант, вы измеряете не эффект, а кашу.

Типичный сценарий: вы раскатили эксперимент, всё разметили, assignment есть, метрики считаются. А потом внезапно “варианты почти не отличаются”, “эффект прыгает по дням”, “в одном сегменте плюс, в другом минус”. И никто не подозревает кэш, потому что формально всё работает: страницы грузятся быстрее, ошибки не растут.

Механика простая: эксперимент живёт в мире “пользователь получил вариант и видел его в окне экспозиции”, а кэш живёт в мире “одинаковый запрос = одинаковый ответ”. Если кэш считает запросы одинаковыми, он начинает раздавать один и тот же ответ разным вариантам. Дальше вы либо смешиваете экспозиции, либо ломаете соответствие “assigned variant → actual experience”, а это убивает причинность.

6 мест, где кэш незаметно смешивает варианты:

  1. CDN/edge: HTML или API кэшируются без Vary по заголовку/куке/параметру, где зашит вариант, и один ответ улетает всем.
  2. Backend-кэш (Redis/memcached/in-memory): ключ строится из user_id/endpoint, но без experiment_id+variant, либо с “общим” ключом на сегмент.
  3. SSR/пререндер: шаблон/фрагменты страницы кэшируются как “страница /product”, хотя внутри есть блоки, зависящие от варианта.
  4. Feature flag/assignment cache: сам assignment кэшируется слишком агрессивно, и при смене условий/перезапуске теста часть пользователей остаётся на старом варианте.
  5. TTL против окна экспозиции: TTL больше, чем период, когда вы считаете экспозицию, и вы ловите “поздние” показы, которые уже не должны попадать в анализ.
  6. Кэширование на клиенте: service worker, HTTP cache, локальные стораджи. Вариант поменялся, а ассеты/ответы остались прежними, особенно на мобильных и в webview.

Минимальный стандарт, чтобы не самообмануться:

  • В ключе кэша явно есть experiment_id и variant (или стабильный флаг, который однозначно маппится на вариант).
  • Для CDN задан Vary по реальному носителю варианта (cookie/header/query), а не “на глаз”.
  • TTL согласован с анализом: вы знаете окно экспозиции и не позволяете кэшу жить дольше смысла измерения.
  • В логах ответов есть след: assigned_variant и served_variant, плюс признак cache hit/miss и ключ (или его хеш).
  • Регулярная проверка по логам: доля cache hit не должна “перекошиваться” между вариантами, и не должно быть кейсов assigned A, served B.

В правильной практике эксперимент проектируют вместе с кэш-стратегией: сначала решают, где вариант проявляется (HTML, API, конфиг, ассеты), потом выбирают, что можно кэшировать безопасно, и только потом запускают измерение. Граница применимости простая: если эксперимент чисто клиентский и сервер всегда отдаёт одинаковый payload, рисков меньше, но service worker и локальный кэш всё равно могут сделать вам сюрприз.