- Зачем:
- зафиксировать результат кросс-прохода другой родословной по
c672ed0..ec815ce для передачи в багфикс-цепочку.
- Что:
- отчёт: 1 critical, 5 high, 10 medium, 4 low; четыре сквозных семейства
(смешение миров, стенд без live, ложнозелёные проверки, чистый клон).
- маршрутизация находок и предложение порядка багфикс-цепочки.
- Проверка:
- находки доказаны исполнением: мутационные тесты, compose-эксперимент,
зонды на сиде, Context7 по Airflow 2.10.5.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
14 KiB
Кросс-линейное ревью цепочки генератора 12 -> 14 -> 09 -> 10 -> 08
Дата: 2026-07-05 00:02.
Жанр: одноразовый handoff по ADR-0003; отчёт кросс-прохода другой родословной
(Claude) по диапазону c672ed0..ec815ce. Бриф — из
.scratch/handoffs/2026-07-04-generator-chain-review.md.
Метод: четыре параллельных адверсарных ревьюера с исполняемыми доказательствами
(мутационные тесты на копии, эксперимент с compose-профилем на реальной версии
Compose, зонды на реальном сиде, сверка Airflow API через Context7). Репозиторий
не менялся.
Вердикт
CHANGES_REQUESTED. Счёт: 1 critical, 5 high, 10 medium, 4 low — после
APPROVED финального ревью той же линии. Третье подтверждение находки о
родословной: внутренние ревью закрыли локальные дефекты честно, кросс-линия
нашла сквозные сценарии.
Сквозные семейства (главная ценность прохода)
- «Смешение миров» возвращается тремя дорогами. Инвариант задачи 07
(«чистый стенд, громкий отказ») пробит: (а) state v2 после обновления кода
классифицируется как «повреждённый» → тихий чистый старт нового мира поверх
истории; (б) live-генератор ушёл в compose-профиль, и
make clean/downего больше не убивают — осиротевший генератор старого мира пишет в чистые топики и переживает перезагрузку (restart: unless-stopped); (в) консольные пути (make generator-backfill,startup-history-import) остались без предпроверок, которые пульту сочли обязательными. - Последствия «make up больше не стартует live» не выметены. Алерт
Kafka No Messages Producedгорит весь курс на здоровом стенде; уроки 0/5 ожидают поток;sleep 5в документированной проверке шва меньше времени старта генератора — проверка стала пустышкой. - Ложнозелёные проверки. Superset-тесты пропускают дрейф параметров (top-15 → 500 строк — 5 тестов зелёные); стыковая проверка сверяет шов там, куда указал env, а не где он по манифесту; ODS-блок проходит на пустом ODS.
- Чистый клон/свежий стенд никто не прошёл.
uvне заявлен в пререквизитах; README-быстрый старт падает безddl_init; пульт вечно висит на запаusedetl_pipeline; послеgit pullобраз Airflow не пересобирается (DAG красный); центральное упражнение урока 1 физически невоспроизводимо. Всё это лежало ровно в вынесенной в риски HITL-приёмке.
Индекс находок по issue
Issue 08 (курс) — CHANGES_REQUESTED
- CRITICAL
docs/course/lessons/01_kafka_to_clickhouse.md:192-239— упражнение сkafka_msg_tsневоспроизводимо: «перезаливка среза» заменена наmake generated-history-analytics && make up, который делаетdown -vи накатывает эталонный DDL — добавленная менти колонка уничтожается, финальный SELECT падает; в тексте остался висящийTRUNCATE(след нестыковки). Нужен путь перезаливки без сброса схемы (сменаkafka_group_name/CLEAN_START=0+ повторный backfill) и проверка на стенде. - HIGH
docs/course/README.md:19-34,README.md:43-47— первая команда курса требуетuvна хосте; ни пререквизиты, ни quick start его не называют. - HIGH
docs/course/lessons/05_monitoring.md:254,259-262,339— на штатном пути (без live)Kafka No Messages Producedгорит постоянно; урок обещает «алерты не шумят»; панели описаны для потока, которого нет. - MEDIUM
00_kafka_intro.md:56-65— служебные топикиgenerator_stateиgenerator_startup_history_manifestне объяснены (урок построен на разглядывании списка топиков). - MEDIUM
00_kafka_intro.md:117-122vs05_monitoring.md:156-161— взаимоисключающие утверждения о видимости consumer lag; проверить на стенде. - MEDIUM
README.md:64-68,docs/OPERATIONS.md:175-199—make generated-history-checkпослеPROFILE=daily-waveпадает: в check зашит диапазон ci, PROFILE не передаётся. - MEDIUM
docs/OPERATIONS.md:95— источником STG первым назван архивныйmake data.
Issue 12/14 (пульт, профиль) — CHANGES_REQUESTED
- HIGH
airflow/dags/generator_control_dag.py:227-235+etl_pipeline_dag.py:263—etl_pipelineсоздаётся на паузе;trigger_etl(wait_for_completion, безexecution_timeout) виснет навсегда,max_active_runs=1блокирует повторные запуски. В Airflow 2.10 нетfail_when_dag_is_paused(Context7). Нужна предпроверка «etl_pipeline не на паузе» + шаг unpause в README/runbook. - HIGH
docker-compose.yml:293-294,334, Makefile (down,clean) — профильныйlive-generatorне удаляетсяdown -v(доказано экспериментом, Compose v5.1.3);restart: unless-stoppedвоскрешает его после перезагрузки. Вdown/clean/CLEAN_START нужен--profile live-generator. - MEDIUM
README.md:32-40— быстрый старт безddl_init: precheck падает сырымUNKNOWN_TABLE; добавить шаг и человекочитаемую подсказку. - MEDIUM
airflow/requirements.txt:9-10, Makefileup— послеgit pullобраз Airflow не пересобирается →ModuleNotFoundError: prometheus_client, DAG красный. Нужен--buildили инструкция. - MEDIUM
docs/OPERATIONS.md:237-241vskafka_io.py:161,253—sleep 5меньше времени старта continue (≥10 с): live-строк ноль,CHECK_LIVE_SEAM=autoмолча пропускает шов. Былоsleep 130при тике 60 с. - MEDIUM
airflow_control.py:102-141vsrun_generator.sh:56-77,import_startup_history_artifact.sh— предпроверки только в DAG; консольные пути тихо смешивают миры. Вынестиassert_stand_cleanв общую точку входа. - LOW
service.py:203-215— простой стенда ×60: ночь = +30 модельных суток дыры; предупредить в runbook, советовать reset/повторный импорт. - LOW — фиксация Context7-проверки Airflow API только в
.scratch/, не в коде/доках (AGENTS.md требует); сами вызовы для 2.10.5 корректны.
Issue 09 (state v3, фактура) — CHANGES_REQUESTED
- HIGH
state.py:236-241→kafka_io.py:181→service.py:100-102— поднятие STATE_VERSION молча превращает живой стенд во «второй мир»: v2 — читаемый, несовместимый state, но version-гейт убивает его до семантики,from_dict_safeдаётNone, сервис тихо стартует новый мир сmodel_t0поверх истории. Сверкаmanifest.state_version != state.version(service.py:246) недостижима. Спека (строки 198-204, 245-247) требует громкий отказ;IncompatibleStateErrorуже существует — использовать его при известной старой версии иGEN_STATE_RESET=false; миграционной заметки в доках нет. - MEDIUM
check_generated_analytics.sh:13,273-289,342,387-393— проверка стыка сверяет шов по env-дефолту (2026-01-01T06:00), не по манифесту: послеdaily-waveголыйmake generated-history-check«доказывает» однородность фальшивого шва посреди backfill. LEFT JOINdds.clickструктурно пуст; ODS-блок проходит на пустом ODS. Братьmodel_t_endиз манифеста, требовать ненулевые ODS-строки. - MEDIUM
generation.py:196-209— предпосылка issue «fallback не срабатывает» неверна: срабатывает у ~8% визитов (зонд, seed=4242, N=20000); выпуск не изменился только потому, что у всех доноров сида строки внутри click_id идентичны — свойство нигде не зафиксировано; при регенерации сида с вариативностью ~8% визитов поедет. Зафиксировать свойство сида или ограничитьGEN_MAX_SESSION_EVENTSдлиной максимального донора. - Ядро фикса крепкое (проверено исполнением): инвариант «рождение ==
восстановление» держится, RNG не потребляется при restore, микросекунды
чинятся честно, форма распределений не сместилась (сверка с
e2d0684^).
Issue 10 (Superset) — CHANGES_REQUESTED
- MEDIUM
tests/test_superset_dashboard_config.py:64-76— тесты сверяют подмножество параметров: мутация «top-15 по убыванию» в экспорте (row_limit 15→500, order_desc→false и др.) проходит все 5 тестов. Нужно полное сравнениеparamsconfig-vs-export. Классы «возврат world_map» и «рассинхрон layout» закрыты честно (мутации падают). - MEDIUM issue
10-*:51-68,create_dashboard.py:158-185— приёмка «по кадру» выполнена декларативно, чарт никем не отрисован; порядок столбцов после pivot не гарантирован — задатьx_axis_sort: "Events, pcs",x_axis_sort_asc: false; снять кадр при HITL. - MEDIUM
create_dashboard.py:505-520— удаление дублей по глобальному совпадению имени: повторный прогон молча удалит одноимённый чарт менти; сузить поdatasource_id, задокументировать деструктивность. - LOW
create_dashboard.py:176—tooltipTimeFormatбессмыслен для категориальной оси; легенда дублирует ось при единственной серии. - LOW
docs/SUPERSET_DASHBOARD.md:205-211— путь ручного импорта экспорта (legacy v0) ничем не проверяется.
Маршрутизация (предложение)
- Багфикс-цепочка Codex (кандидат-порядок по риску): (1) семейство «смешение миров» — 09-HIGH + 12-HIGH-clean + разъезд предпроверок одним issue; (2) 12-HIGH-паузы + README/ddl_init/build — «свежий стенд» одним issue; (3) 08-CRITICAL урок 1 + uv + алерт урока 5 — «курс на чистом клоне»; (4) ложнозелёные проверки (09-MEDIUM-шов, 10-MEDIUM-тесты); (5) остальное.
- HITL остаётся HITL (кадры Superset, живой проход Airflow UI, проход по урокам) — но пункты 08-CRITICAL и 12-HIGH показывают, что часть HITL дешевле заменить проверками на чистом клоне в CI-манере.
- Отдельно: третий случай подтверждения находки о родословной — кандидат на
датированную поправку в
references/rationale.mdскилла coordinator-loop.
Что подтверждено как корректное
Стыковка env DAG→генератор; ветвление DAG; отсутствие потребности в Docker изнутри Airflow; make-цели/имена DAG/DDL-колонки/числа профилей в уроках; ядро state v3; замена карты в обоих источниках; 172 unit-теста зелёные.