Skip to content

bug: скачанный CSV может принадлежать не тому виду — top_popular.csv с related-заголовком #41

Description

@axisrow

Симптом

Живой прогон на cc5ce70 (3 фразы, Россия, --keep-raw). Для фразы «подарки» сохранённый top_popular.csv содержит related-заголовок:

файл размер заголовок
CLI top_popular.csv 191 Б Запросы, похожие на "подарки"… ← related
CLI top_related.csv 191 Б Запросы, похожие на "подарки"…
ручной экспорт wordstat_top_queries.csv 198 Б Топ частотных запросов "подарки"… ← popular

Для фразы «новогодние подарки детям» оба файла — 223 Б с related-заголовком.
Для «новогодние подарки» заголовки правильные (219 Б popular / 212 Б related).

То есть <view>.parquet и <view>.csv могут описывать не тот отчёт, имя которого носят, и происходит это не всегда — зависит от фразы.

Почему это не «пустые топы»

Отдельно проверено и не является багом: топовые виды на живом Wordstat экспортируются header-only даже при непустом UI (200 строк в таблице «подарки»). Ручной экспорт даёт ровно то же самое. Это поведение Wordstat, оно уже задокументировано в collector.py (_is_untrustworthy_empty_export, «TOP_POPULAR … is always empty on live Wordstat»). Данная issue не про пустоту, а про подмену вида.

Механизм (гипотеза)

VIEW_SELECTORS (collector.py:57):

WordstatView.TOP_POPULAR: "label[for='table']",
WordstatView.TOP_RELATED: "label:has(#associations)",

Оба топовых вида живут в одной таблице. _select_view подтверждает переключение тремя признаками: input.checked, наличие кнопки скачивания и TABLE_ROW_SELECTOR.length > 0. Ни один из них не описывает содержимое будущего экспорта — только состояние контролов и наличие строк.

Проверка «текст таблицы изменился» существует, но она required=False и явно помечена в комментарии как corroborating evidence, а не гейт — потому что разные виды могут иметь одинаковую первую строку. В результате: radio уже переключён, строки в DOM есть, а blob экспорта всё ещё принадлежит предыдущему виду — скачивается related под именем popular.

Это тот же класс дефекта, что #3, #13, #21, #22, #26, #31 и три ревью в PR #39: проверяется соседний сигнал вместо искомого. Здесь искомое — принадлежность экспорта виду, а проверяется состояние переключателя.

Почему тесты молчат

row_count=0 у обоих топов одинаков независимо от того, какой заголовок попал в файл. Заголовки Wordstat локализованы и намеренно не валидируются по именам (csv_io.py) — так что подмена вида не отражается ни в одной проверке. Манифест показывает top_popular row_count 0 и выглядит нормально.

Что нужно

  1. Воспроизвести: несколько фраз подряд, --keep-raw, сверить заголовок каждого <view>.csv с ожидаемым видом. Зафиксировать, от чего зависит (порядок видов, скорость перерисовки, конкретная фраза).
  2. Найти признак, описывающий сам экспорт, а не контролы: заголовок скачанного CSV — первый кандидат, он приходит от Wordstat и прямо называет отчёт.
  3. Проверка принадлежности вида после скачивания, fail-closed: если заголовок не соответствует запрошенному виду — не записывать parquet под этим именем.
  4. Осторожно с п. 3: заголовки локализованы и Wordstat их меняет без предупреждения. Жёсткая привязка к строке — новый источник тихих поломок. Нужен признак, отличающий виды, но не ломающийся от переформулировки; варианты обсудить до реализации.

Данные прогона

Каталог: /tmp/wordstat-issue-38-one-1788155996, коммит cc5ce70, monthly, дефолтное окно UI, timeout 45.
UI на момент проверки: «подарки» → top_popular 200 строк (подарок 4 583 689), top_related 20 строк (подарить 3 586 247).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions