Контекст
Обнаружено в cycle-review PR #21 (issue #6, фаза 2), поднималось в раундах 1 (C1), 2 (C2) и 3 (C3, CONFLICTING) — три раунда подряд, один и тот же корень.
_assert_contiguous_dynamics_rows в src/wordstat/collector.py проверяет вложенность экспортированных строк в запрошенное окно (date_from/date_to) для дневной и недельной гранулярности динамики, но исключает месячную (if granularity is Granularity.MONTHLY: return). Причина исключения: поле периода при месячной гранулярности хранит не DD.MM.YYYY, а строку вида "январь 2024" (номинативный русский месяц + год), для которой отдельного парсера не было.
Итог: месячный экспорт динамики fail-open — если Wordstat вернёт устаревшее/усечённое/не соответствующее запросу окно (тот же класс проблемы, что containment-проверка ловит для daily/weekly), это будет записано в parquet и манифест как complete, без ошибки.
Почему раунд 2 отклонил фикс, и почему это стоит пересмотреть
В раунде 2 обоснование было «нужен отдельный парсер, это отдельная работа» — оценка делалась в момент, когда путь --granularity monthly с явными датами был фактически недостижим: ломался всегда из-за .capitalize()-бага в клике по названию месяца и лишнего клика по попапу диапазона дат (оба исправлены в 6468e25 тем же PR). После фикса путь стал реально рабочим и был подтверждён живым CDP-прогоном: формат "январь 2024", нижний регистр, именительный падеж — ровно то, что уже хранит константа RUSSIAN_MONTHS в collector.py.
Предлагаемое решение
Добавить парсер "{месяц} {год}" → date через обратный поиск по RUSSIAN_MONTHS (индекс месяца = позиция в списке + 1, первый день месяца), и убрать monthly из исключения в _assert_contiguous_dynamics_rows — распространить containment-проверку на него тем же способом, что и для daily/weekly, сравнивая первый/последний месяц экспорта с date_from/date_to, приведёнными к границам месяца.
Объём
Небольшой — оценочно ~4 строки парсера + снятие раннего return для monthly + тесты по аналогии с test_dynamics_series_rejects_a_stale_window_that_predates_the_request и test_weekly_containment_uses_the_aligned_week_start_not_the_raw_request.
Текущее состояние (принятое решение)
До закрытия этого issue месячный экспорт динамики официально остаётся fail-open — задокументированный, осознанный компромисс (не забытый пробел), см. описание PR #21.
Контекст
Обнаружено в cycle-review PR #21 (issue #6, фаза 2), поднималось в раундах 1 (C1), 2 (C2) и 3 (C3, CONFLICTING) — три раунда подряд, один и тот же корень.
_assert_contiguous_dynamics_rowsвsrc/wordstat/collector.pyпроверяет вложенность экспортированных строк в запрошенное окно (date_from/date_to) для дневной и недельной гранулярности динамики, но исключает месячную (if granularity is Granularity.MONTHLY: return). Причина исключения: поле периода при месячной гранулярности хранит неDD.MM.YYYY, а строку вида"январь 2024"(номинативный русский месяц + год), для которой отдельного парсера не было.Итог: месячный экспорт динамики fail-open — если Wordstat вернёт устаревшее/усечённое/не соответствующее запросу окно (тот же класс проблемы, что containment-проверка ловит для daily/weekly), это будет записано в parquet и манифест как
complete, без ошибки.Почему раунд 2 отклонил фикс, и почему это стоит пересмотреть
В раунде 2 обоснование было «нужен отдельный парсер, это отдельная работа» — оценка делалась в момент, когда путь
--granularity monthlyс явными датами был фактически недостижим: ломался всегда из-за.capitalize()-бага в клике по названию месяца и лишнего клика по попапу диапазона дат (оба исправлены в6468e25тем же PR). После фикса путь стал реально рабочим и был подтверждён живым CDP-прогоном: формат"январь 2024", нижний регистр, именительный падеж — ровно то, что уже хранит константаRUSSIAN_MONTHSвcollector.py.Предлагаемое решение
Добавить парсер
"{месяц} {год}"→dateчерез обратный поиск поRUSSIAN_MONTHS(индекс месяца = позиция в списке + 1, первый день месяца), и убрать monthly из исключения в_assert_contiguous_dynamics_rows— распространить containment-проверку на него тем же способом, что и для daily/weekly, сравнивая первый/последний месяц экспорта сdate_from/date_to, приведёнными к границам месяца.Объём
Небольшой — оценочно ~4 строки парсера + снятие раннего
returnдля monthly + тесты по аналогии сtest_dynamics_series_rejects_a_stale_window_that_predates_the_requestиtest_weekly_containment_uses_the_aligned_week_start_not_the_raw_request.Текущее состояние (принятое решение)
До закрытия этого issue месячный экспорт динамики официально остаётся fail-open — задокументированный, осознанный компромисс (не забытый пробел), см. описание PR #21.