Ликвидность классифайда — аудит измеримости preview

Решение за кейсом

Ставка

Прокси ликвидности смещён не одинаково: если ошибка различается по категориям, единая поправка бесполезна, а платная видимость будет выглядеть выигрышной там, где продавец просто врёт о продаже.

Что считалось провалом

Поправка принимается, только если все пять категорий попадают в допуск 3 п.п. истины, а модули анализа физически не могут прочитать файл истины — это проверяет AST-тест, а не дисциплина.

После запуска

Гипотеза подтвердилась в части смещения и не подтвердилась в части выгоды: наивный прирост +113% оказался отбором, холдаут дал отрицательную точечную оценку с нулём внутри интервала.

Ситуация
Платформа не видит сделку: она закрывается вне платформы, поэтому ликвидность считается по самоотчёту продавца, а не по факту продажи
Задача
Мне нужно было измерить расхождение прокси с посаженной истиной по категориям и проверить, выдерживает ли решение о платной видимости такую поправку
Действия
Синтетический лог на 6 000 объявлений и 40 000 сессий с посаженной истиной, EM-смесь sold/unsold на наблюдаемых сигналах ответа, поправка по категориям, рандомизированный холдаут с гардрейлами
Результат
Прокси 0,2413 против истины 0,3070: ошибка −0,0657 (−21,4%); после поправки худшая категория ошибается на 1,61 п.п., а платная видимость даёт −2,47% контактов на сессию при p = 0,308
Стек
PythonpandasDuckDBSciPySQLpytestuv + ruff
Исходники Смотреть на GitHub → Обновлено: 1 нояб. 2026 г.
Содержание
  1. Ситуация
  2. Задача
  3. Действия
  4. Результат
  5. Ограничения
  6. Документация

Ликвидность классифайда — аудит измеримости

Ситуация

Классифайд, где сделка закрывается вне платформы. Платформа логирует поиски, показы, просмотры, контакты и снятия объявлений — но никогда не логирует саму продажу. Ликвидность считается по самоотчёту продавца: removal_reason == "sold".

Такой прокси выглядит разумно, пока его никто не проверял. Продавец может снять объявление из-за цены, конкурента или просто передумать, и метрика запишет это как продажу. Вопрос не в том, ошибается ли прокси, а в том, насколько и одинаково ли ошибается по категориям.

Задача

Мне нужно было измерить расхождение прокси с посаженной истиной по категориям и проверить, выдерживает ли решение о платной видимости такую поправку.

Действия

Синтетическая база с ответом. Сгенерировал 6 000 объявлений и 40 000 поисковых сессий за 90 дней: 6 регионов × 5 категорий, seed 42. Ответ — латентная продажа — записан в _truth/ground_truth.json и не участвует в анализе: AST-тест test_no_truth_leak.py статически запрещает модулям анализа импортировать или открывать этот файл.

Прокси и истина. Сравнил removal_reason == "sold" с латентной истиной на когорте из 1 956 объявлений, опубликованных в первые 30 дней. Прокси даёт 0,2413 против 0,3070 — ошибка −0,0657, относительная −21,4%.

Поправка. Разложил наблюдаемый отклик на две компоненты — проданное и непроданное — и оценил смесь EM по сигналам ответа и задержки. Поправка считается по категориям, а не одной константой: ошибка прокси различается между ними.

Проверка поправки. Оценил восстановление истины на отложенном сегменте с жёстким допуском 3 п.п. и прогнал тест чувствительности: если убрать сепаратор SOLD_REPLY_LAG_MAX = 4.5 или сдвинуть отсечку до 2 дней, восстановление обязано сломаться — иначе тест ничего не проверяет.

Платная видимость. Дал 10% объявлений случайный буст в пределах категории. Сравнил наивное «до/после» с контрастом против холдаута по контактам на сессию; отдельно посчитал гардрейлы — органические контакты и долю ответов.

Проверки. 61 тест: восстановление истины, чувствительность к сепаратору, обязательное падение наивной оценки, отсутствие утечки истины, идемпотентность генератора.

Результат

  • Ошибка прокси: 0,2413 против 0,3070, −0,0657 (−21,4%) на когорте из 1 956 объявлений.
  • После поправки: худшая категория ошибается на 1,61 п.п., все пять укладываются в допуск 3 п.п.
  • Наивная видимость: 0,4702 → 1,0027 контакта на объявление, +113% — но это отбор, а не эффект.
  • Причинный контраст: −0,0116 контакта на сессию (−2,47%), Welch p = 0,308, интервал (−0,0346; 0,0084) — ноль не исключён.
  • Гардрейлы: органические контакты −10,9%, доля ответов 56,6% против 64,4% у неплатных.
  • Отрицательный контроль: наивная оценка обязана «улучшиться» — тест падает, если этого не происходит.

Ограничения

Данные синтетические: это доказательство о механизме измерения, а не об Avito. Генератор задаёт мир, в котором смесь восстанавливается; поправка проверяет спецификацию, а не валидируется на независимом источнике.

Восстановление держится на сепараторе, который совпадает с генератором: без него худшая ошибка растёт до 12,1 п.п., при отсечке 2 дня — до 15,82 п.п.

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

Один seed, одно окно, нет валидации по отдельным объявлениям и нет проверки чувствительности к длине окна. Все десять ограничений перечислены в отчёте.

Документация

  • README.md — постановка, таблица прокси против истины и границы применимости.
  • docs/preregistration.md — знаки смещения по категориям, зафиксированные до прогона.
  • Быстрый старт: uv sync --all-groups → uv run python -m liquidity.generate → uv run pytest → uv run python -m liquidity.bias.
  • uv run python -m liquidity.monetization — холдаут платной видимости и гардрейлы.

Нужен такой же разбор на ваших данных?

Расскажите задачу — вернусь с планом: какие данные нужны, что проверяем и за какой срок. Отвечаю в течение дня.

Обсудить задачу →