- Зачем:
- у дней 8-13 описи не нашлось читателя: обещание эталона в 14 дней
снято решением владельца 2026-08-30 (#192, этап 7 — #9).
- Что:
- резолюция перенесена в обе спеки, докстринг описи и словарь CONTEXT.md;
- добавлен тест: проигранный через CLI день совпадает с хешем описи;
- сняты замеры: пересборка описи 20,5 с, снимок 460,7 МБ, make test
176,5 с — записаны в карту проверок и таблицу бюджетов.
- Проверка:
- cd generator && make lint && make typecheck && make test (437 passed);
- git diff по data/world-inventory.json пуст.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
41 KiB
Проверки: карта целей
Документ отвечает на два вопроса. Первый: что именно утверждает каждая цель
make и сколько стоит её прогон. Второй, ради которого документ и заведён:
куда положить новую проверку — так, чтобы это решалось по карте, а не чтением
скриптов.
Зона ответственности у документа одна — проверки. Что именно они стерегут, описано в других местах: устройство хранилища — в storage.md, замысел стенда — в спеке «Боевой реализм стенда (v2)».
Ось: кого спрашивают
Цели различаются не ценой, а тем, к кому обращён вопрос. ClickHouse отвечает сам и за миллисекунды. Airflow отвечает через такт планировщика. Superset — через сессию и обход метаданных. Быстрота выходит следствием этого различия, а не критерием деления.
Совпадение цены и назначения здесь побочное, и это видно по дырам, которые
каждая цель оставляет соседке. make smoke не заметит перепутанных местами
макросов shard: обе ноды здоровы и порты отвечают. make check-clickhouse не
заметит потерянного подключения Superset: он про ClickHouse и только.
Отсюда правило для новой проверки: спроси, кого она спрашивает. Счётчики
против описи — вопрос к ClickHouse: строки в ods.event считает сам
сервер и отвечает сразу, значит дом им в check-clickhouse, даже если по цене
они подошли бы смоуку.
Карта целей
Цели живут за двумя дверями. В корне — цели стенда; в generator/ — цели
генератора: он отдельный пакет со своим pyproject.toml, локом и образом, и
спрашивают его отдельно.
Стенд нужен трём целям из восьми. Цена — замер, см. «Что проверено».
make smoke и make check-services перемерены 28 августа 2026 года,
make config-test — 21 августа, make check-clickhouse — 19 августа,
корневой make lint — 9 августа, make test — 30 августа; остальные стоят с
замера 6 августа.
| Цель | Откуда | Что утверждает | Стенд | Цена |
|---|---|---|---|---|
make config-test |
корень | Compose разбирается, файлы DAG и дашборды Grafana синтаксически целы, в diff нет пробельных ошибок. О работоспособности не говорит ничего | не нужен | 1 с |
make lint |
корень | Код стенда — dags/ и infra/superset/ — отформатирован и проходит ruff |
не нужен | 0,4 с |
make smoke |
корень | Стенд собран: службы живы, порты отвечают, подключения настроены друг на друга. Вширь и по касательной к каждой службе. Единственная цель, которая здесь правда смоук | нужен | 25 с |
make check-clickhouse |
корень | Всё, что спрашивают у ClickHouse и он отвечает сам: макросы, шарды, реплики, путь в keeper, ключ шардирования, очередь распределённых DDL, ответ словаря товаров, счёт событий стартового мира против описи | нужен | 24 с |
make check-services |
корень | Службы работают: DAG запускается и доходит, топик создаётся и удаляется, Superset логинится и ходит в базу | нужен | 71 с |
make lint |
generator/ |
Код генератора отформатирован и проходит ruff | не нужен | 0,4 с |
make typecheck |
generator/ |
Типы генератора сходятся (ty) | не нужен | 0,5 с |
make test |
generator/ |
Генератор делает то, что обещает; схема события остаётся объявленным контрактом, а собранные из кода описание выгрузки и опись мира — свежими | не нужен | 176,5 с |
Строк с именем make lint две, и это не опечатка. Одноимённые цели за
разными дверями охватывают разное: корневая не видит ни одного файла
генератора, генераторная — ни одного файла стенда. Человек в корне видит
зелёное и может решить, что зелёный весь репозиторий.
Две тонкости, которых не видно из таблицы:
- Версия ruff у корневой цели закреплена в самом вызове (
uvx ruff@0.16.1) и равна той, что вgenerator/uv.lock. Равенство держится руками: обновили лок — поправьте и вызов, сверять их некому. - Охват держат аргументы вызова, а не устройство дерева. Python, положенный вне двух названных в таблице путей, не проверит ни одна из дверей.
Корневого typecheck нет, и это решение, а не пропуск. Проверке типов мало
прочитать файл: чтобы понять from airflow.sdk import dag, ей нужен
установленный Airflow, а он живёт в образе, не на машине — 132 пакета ради двух
файлов пробников (замер 9 августа 2026 года, uv pip compile). Цена решения
называется честно: две настоящие находки ty в dags/test_kafka.py постоянного
сторожа не получают. Вопрос вернётся на этапе 5, когда придут настоящие даги:
тогда окружение окупится, и условие возврата — именно это, а не «стало
неудобно».
Цена самого make up с пустых томов — 8 м 18 с до переезда жизненного цикла в
Airflow. В цену целей она не входит. На готовом мире подъём больше не
пересчитывает данные: world_initialize зеленеет без изменений.
make rebuild-storage тоже не проверка. Команда через Airflow удаляет
прикладные базы ClickHouse, топики и позиции групп Kafka, заново применяет DDL,
заливает стартовый мир и возвращает его пульт к концу стартовых дней. Службы и
их тома она сохраняет, поэтому возврат к каноническим данным не требует
холодного запуска всего стенда.
Правило: смоук обязан оставаться быстрым
make smoke — быстрая проверка для регулярного прогона: её гоняют не
задумываясь, и потому она обязана укладываться в секунды. Тяжёлые проверки в
неё включать не следует: тяжёлая — та, из-за которой смоук перестаёт быть
быстрым. Поодиночке это единицы и десятки секунд, вместе — минуты. Такие
проверки живут в make check-services.
На практике дорого обходится не работа, а ожидание службы: такт планировщика
Airflow, сессия Superset. make check-clickhouse создаёт таблицы, вставляет
строки и гоняет распределённые DDL — и укладывается в семь секунд, потому что
ClickHouse отвечает сразу.
Первый абзац — правило, второй — наблюдение, по которому тяжёлую проверку узнают заранее, не замеряя.
Какую проверку когда запускать
Деление целей ценно ровно до тех пор, пока оно не превратилось в «гонять всегда всё».
Состояние перед проверкой восстанавливается в самой узкой достаточной области:
сначала объект или партиция, затем база слоя. Если нужен целиком чистый
прикладной мир, make rebuild-storage пересобирает его базы, топики, позиции
потребителей и данные. make clean нужен, только когда меняется или сломано
постоянное состояние вне этих баз либо проверяется сам запуск с пустых томов.
Требование к обоснованию полного сброса задаёт AGENTS.md. Неизвестную поломку
сначала исследуют: полный сброс уничтожает её следы.
| Когда | Что гонять |
|---|---|
| Правка в работе | make config-test и make smoke |
| PR или задача | плюс цели, которых правка касалась: DAG-и, Superset или Kafka — check-services; DDL, кластер или данные — check-clickhouse |
| Приёмка этапа | все три цели на стенде; запуск с пустых томов — только для изменений начальной сборки или постоянного состояния служб |
Правки генератора добавляют к этому make lint, make typecheck и make test
из каталога generator/: стенд им не нужен, а make test из них самая
дорогая. Правки дагов и Superset — корневой make lint.
Двадцать секунд из ее ста семидесяти шести — пересборка восьми модельных дней для сверки с описью мира (20,5 с из 176,5). Дешевле хеши не сравнить: чтобы узнать, тот ли получается мир, его надо получить. Место выбрано по той же оси «кого спрашивают» — вопрос обращён к коду генератора, стенд ему не нужен, — и краснеет проверка там, где надо: сразу после правки генератора. Не будь её, расхождение всплыло бы получасом позже, на поднятом стенде, где выглядит поломкой хранилища, а не забытой пересборкой.
Порогов по времени здесь нет
Цена в таблице — замеренное число с датой замера, а не назначенный порог.
Автоматической проверки времени в репозитории нет и заводить её не следует.
Число, вписанное в проверку, становится законом, которого никто не выбирал:
ADR 0004 разбирает ровно этот случай — оценка
из спеки попала жёстким порогом в make smoke, make smoke стал критерием
приёмки каждого этапа, и дальше решения сверялись уже с порогом, а не с
исходным доводом. Спека генератора формулирует ту же позицию прямо:
«наблюдаемость без порогов».
Смотрит на время человек. make smoke и make check-services печатают его
сами — последней строкой ИТОГ: пройдено N, ошибок M, время T с. Замер при
приёмке делается руками и называется в теле PR.
Проверка, которая не умеет краснеть, бесполезна
Правило, которое стоит держать в голове, правя любую проверку. Проверка,
никогда не видевшая своей поломки, доказывает только то, что она умеет печатать
«ЗЕЛЁНО». Убедиться дешевле всего руками: сломайте то, что она стережёт —
остановите prometheus, удалите служебную таблицу пробника на второй ноде, — и
посмотрите, покраснеет ли прогон и назовёт ли виновника. Не покраснел —
проверка не работает, и чинить надо её, а не стенд.
Интеграционная проверка постоянной целью не становится
Проверка, которая не спрашивает стенд, а кормит его — шлёт сообщения,
вставляет строки, портит данные нарочно, — постоянной целью make не живёт.
Такую проверку гоняют один раз при исполнении, убеждаются, что механизм
работает, и оставляют след записью в теле PR. Регулярная жизнь стенда — это
жизнь с менти, а интеграционный прогон в неё не входит; самое большее, он
становится темой урока.
Довод не про цену прогона, а про данные. Вложенное остаётся: у сырья срок жизни трое суток, а ODS хранит всё, и события, которых мир не рождал, лягут в лабы менти неотличимо от настоящих — считая конверсию, он молча посчитает и их. Хуже явного мусора: явный видно.
Отсюда правило для того, что всё-таки вкладывает: прибираться за собой.
Дешевле всего это выходит партицией — опыт играет модельный день за границей
оси мира, его строки ложатся в собственную партицию EventDate, и она
сносится по окончании. Заодно менти видит партицию как единицу работы — тот
же механизм, на котором стоит переобработка дня X.
Что тогда стережёт цепочку постоянно — проверки на настоящих данных, тех,
что стенд произвёл сам: подневный счёт событий против описи мира ловит и
сломанный разбор (события уехали в брак — счёт разошёлся), и потерю по дороге,
ничего при этом не вкладывая. Это единственный постоянный сторож цепочки
Kafka → STG → ODS, и живёт он в make check-clickhouse.
Правило, которое такая проверка обязана выдержать и которое стоит держать в голове для следующей: на растущих данных утверждать можно только про зафиксированный кусок. Мир растёт — менти переиграет день, этап 5 добавит следующий, — и всякое утверждение про таблицу целиком однажды покраснеет законно, то есть впустую. Как это сделано здесь, написано в самом скрипте.
Корректность процессов живёт в дагах DQ, а не в целях make
Цели make отвечают на вопрос «стенд собран и работает». Вопрос «данные в нём
правильные» — работа отдельных дагов качества данных: они приходят вместе со
следующими уровнями хранилища и заберут многое из того, что просится проверкой
сейчас. Поэтому находка «это стоило бы проверять регулярно» сначала проверяется
вопросом, не туда ли ей: если она про свойства данных — про полноту дня, про
свежесть слоя, про сходимость витрины с источником, — её дом даг, а не
check-clickhouse.
Разница видна и менти, и она содержательная. Цель make он зовёт руками,
когда чинит стенд; даг DQ идёт по расписанию рядом с остальным конвейером,
пишет историю проверок и разбирается как обычная задача Airflow — то есть учит
тому, как качество данных устроено в бою.
Устройство скриптов
| Цель | Скрипт |
|---|---|
make config-test |
scripts/config-test.sh |
make smoke |
scripts/stand-smoke.sh |
make check-services |
scripts/stand-services.sh |
make check-clickhouse |
scripts/check-clickhouse.sh |
Особняком стоит scripts/run-dag.sh: это не проверка, а общий REST-переход от
make к Airflow. make up запускает через него world_initialize, а
make rebuild-storage — world_recreate; сценарий ждёт появления дага в API,
а затем до минуты повторяет только стартовый ответ Dag with dag_id not found.
Прочие ответы и сетевые ошибки он не повторяет: при потерянном ответе запуск мог
уже создаться. Сценарий печатает идентификаторы дага и прогона и возвращает
вызывающему его итог. Ожидание доставки событий и запуск orders_ingest теперь
видны задачами world_initialize, а не спрятаны в shell.
Общее у смоука и check-services — счёт проверок, обращение к Compose и две
проверки — вынесено в scripts/stand-common.sh; сам он не запускается.
Оттуда же приходят два решения, которые видно по счёту прогонов:
check_containers_survivedстоит в конце обеих целей. Убитый за память контейнер Docker поднимает сам, и проверка здоровья об этом промолчит (ADR 0004). Стенд нагружаетcheck-services, а увидеть последствия нужно и тому, кто гонял один смоук. Это единственная проверка, которая считается дважды: 21 у смоука плюс 7 уcheck-services— это 27 разных проверок.- Зависимости машины считает только смоук. «На машине есть Docker, curl и
jq» — вопрос к машине, а не к службам, и на оси он стоит рядом с «стенд
собран». Для
check-servicesэто условие запуска: без них он не начнёт работу и громко скажет об этом, но ЗЕЛЁНО за это не печатает.
Вход в Airflow check-services выполняет заново — общих переменных у двух
скриптов нет. Отдельной проверкой этот вход тоже не считается: то же самое
утверждает смоук.
Что проверено
Перезамер 30 августа 2026 года при исполнении #192. Команды запускались
из generator/:
time make inventory
uv run python -m clickstream_generator batch --day 0 --days 8 \
--file /tmp/stage7-events.jsonl
for snapshot_day in 1 2 3 4 5 6 7; do
uv run python -m clickstream_generator snapshot --day "$snapshot_day" \
--file "/tmp/stage7-snapshot-${snapshot_day}.jsonl"
done
wc -c /tmp/stage7-events.jsonl /tmp/stage7-snapshot-{1,2,3,4,5,6,7}.jsonl
time make test
Опись пересобралась за 20,515 с. Файловый приемник записал 460 731 812 байт:
458 478 771 байт событий и 2 253 041 байт слепков. make test прошел 437/0
за 176,476 с. Прежние 71 с (7 августа, #42) выросли по двум причинам: тестов
стало 437 против 407, и потяжелел сам мир — та же пересборка восьми дней
стоила 13 с, теперь 20,5. Эта правка добавила один тест — проигрыш дня.
Приемка #172 28 августа 2026 года. Холодный create_app() занимал
28,3-28,4 секунды, а чтение подключения после запуска - 0,07 секунды. Предел
30 секунд почти целиком уходил на запуск второго приложения. Увеличивать его
не стали: Superset не обещает постоянного времени create_app().
После входа проверка делает три GET-запроса к уже работающему Superset: находит
ClickHouse, сверяет UUID и безопасный URI, затем требует схему dm. Так без
второго запуска проверяются сохраненное подключение и хранилище пароля. Форму
API сверили через Context7 и с исходным кодом Superset 6.1.0. superset test-db
отклонен, потому что тоже запускает приложение; прямой SQL к dbs не проверяет
соединение.
Проверка больше не подтверждает, что сам Superset использует Postgres для
метаданных. Короткий запрос к Postgres показывает лишь готовность базы, а REST
API - подключение к ClickHouse. Для check-services этого достаточно.
После перезапуска Superset три прогона прошли 7/7 за 71, 67 и 70 секунд.
make config-test прошел. make smoke дал 21/21 за 25 секунд; его код не
менялся, прежний замер был 17 секунд. Неверный UUID дал 5/1: красной стала
только проверка метаданных, пароль в вывод не попал.
Приемка #156 27 августа 2026 года. make rebuild-storage занял 7 минут.
На чистом прикладном мире world_initialize сам довел позицию до 8, дождался
etl_pipeline и оставил заполненными DDS и обе витрины. После пересборки прошли
make smoke 21/21 и make check-clickhouse 10/10. Перед стендовыми сценариями
прошли make config-test и make lint.
Два прогона world_next_day не изменили слои; один ручной etl_pipeline без
параметров догнал оба дня. Полный прогон world_live_day занял 27 м 2 с и
завершился только после успешных DDS и DM.
Временная синтаксическая поломка sql/dm/daily_traffic_rebuild.sql дала
красную цепочку: DDS завершился успешно, а daily_traffic, DM, etl_pipeline
и world_live_day покраснели. После возврата исправного SQL ручной
etl_pipeline без параметров завершился успешно на позиции 12 и восстановил
слои.
Для проверки пакетного барьера stg.hits_raw_mv временно отсоединили командой
DETACH на обеих нодах. После world_next_day отставание Kafka составило
46 367 (19 128 + 27 239). Во время ожидания матвью вернули командой ATTACH.
Журнал готовности записал повторные опросы с отставанием 46 367, затем 27 239
и 0; после этого очередь ods.event_dist содержала 0 файлов на обеих нодах,
и ETL завершился успешно. Проверка EXISTS снова дала 1 на обеих нодах,
позиция равна 13.
После пересборки make check-services дважды дал 5/1: только импорт Superset
не уложился в существующий тайм-аут 30 с. Диагностический пробник импорта с
ожиданием 90 с прошел 3/0. Финальный штатный повтор прошел 7/7 за 129 с.
Перезамер 21 августа 2026 года при исполнении #124. Образ Airflow собран с
apache-airflow-providers-clickhousedb==1.0.0,
apache-airflow-providers-common-sql==2.0.1 и
clickhouse-connect==1.6.0; pip check не нашёл несовместимых зависимостей.
Адресная пересборка мира через make rebuild-storage заняла 3 м 5 с: все шесть
задач DDL, pull_batch и parse_batch завершились успешно. После неё прошли
смоук 21/21 за 17 с, проверка ClickHouse 10/10 и межсервисная проверка 7/7 за
100 с.
Первый make up после замены образа попал в короткий рассинхрон запуска
Airflow: API уже сообщил о здоровье и отдал world_initialize по GET, но POST
нового запуска ещё ответил Dag with dag_id not found. Ошибок импорта не было;
через несколько секунд повторный make up завершился успешно и не менял
готовый мир.
Перезамер 21 августа 2026 года при исполнении #114. После добавления
kafka-exporter и источника ClickHouse смоук прошёл 21/21 за 16–17 секунд,
check-services — 7/7 за 93 секунды. При остановленном экспортёре смоук дал
19/2: назвал нездоровый сервис и отсутствие одной из четырёх целей. После
возврата сервиса прогон снова дал 21/21.
После переноса #119 поверх этого состава повторный make up сохранил готовый
мир, смоук прошёл 21/21, проверка ClickHouse — 10/10, межсервисная — 7/7.
Приёмка логики #119 до переноса поверх мониторинга 21 августа 2026 года.
make rebuild-storage через Airflow прошёл за 3 м 9 с: позиция прошла задачи
-1 → 0 → 8, топики получили новые идентификаторы, группы дочитали новые
топики без отставания, а ODS принял 401 185 событий без брака и 2 851
актуальный заказ. Задача build_generator_image заняла по 1,5 с в двух
прогонах.
Повторный make up занял 2 м 41 с вместе со штатным повторным запуском служб
инициализации; world_initialize завершился за один цикл опроса и оставил
счётчики неизменными. Отдельно проверены красные отказы world_initialize при
-1 и world_next_day при отсутствующей позиции, 0 и -1; lifecycle
отказано в чтении system.users, но разрешено чтение system.settings.
Итоговый холодный make up из пустых томов занял 9 м 39 с после 25 с на
make clean. Даг создал отсутствующую позицию и закончил на 8; ODS снова
получил 401 185 событий без брака и 2 851 заказ. У hits два раздела, у
orders один, отставание обеих групп равно нулю. На тогдашнем составе стенда
прошли смоук 20/20, проверка ClickHouse 10/10 и межсервисная проверка 7/7.
Оборванную очистку проверили после записи world_position=-1: остановили
первую ноду ClickHouse, и world_recreate покраснел на удалении баз. Следующий
make up тоже покраснел и оставил -1. После возврата ноды повторный
make rebuild-storage восстановил мир.
Прототип 21 августа 2026 года при исследовании #110. Предшествующая shell-версия узкой пересборки за 2 м 25 с пересоздала прикладные базы, отправила 401 185 событий и 6 656 версий заказов и вернула позицию с 11 на 8. Замер оставлен как ориентир цены, но не подтверждает нынешнюю реализацию Airflow: тот вариант не очищал Kafka и был отклонён как второй оркестратор мира.
Перезамер 20 августа 2026 года при исполнении #96, до переезда в Airflow.
make up после make clean прошёл за 8 м 18 с, повтор на живом стенде — за
3 м 35 с. Отправка семи слепков заняла около 28 секунд.
Прежний замер ниже — 2 м 50 с и 1 м 5 с до появления приёма заказов и пульта
мира. Весь рост приписывать слепкам нельзя: на холодном прогоне основное время
ушло ещё до сценариев ожидания: airflow-init завершился примерно на 320-й
секунде, обработчик DAG стал здоров примерно на 458-й. Числа здесь называют
цену нынешнего стенда, а не выносят вердикт о регрессии.
Перезамер 19 августа 2026 года при исполнении #95. После добавления десятой
проверки словаря make check-clickhouse на чисто поднятом стенде прошёл за
24 секунды. Это цена всей цели, а не одной новой строки.
Замер 9 августа 2026 года при появлении корневого lint (#65). Три прогона
подряд — 0,39, 0,36 и 0,39 секунды на трёх файлах стенда; в таблице 0,4 с. На
машине с непрогретым кешем первый прогон дороже: uvx сначала скачивает ruff.
Тогда же снято, что двери не перекрываются: ruff check --show-files из корня
перечисляет ровно три файла стенда, из generator/ — только файлы генератора.
Корневой конфиг правила генератору не подменяет: конфиг ищется вверх по дереву
от файла, и ближний выигрывает.
Перезамер 7 августа 2026 года при исполнении #42. Подъём стенда с нуля
(make clean && make up) — 2 м 50 с, из них 22,5 с занимает сама заливка:
18,7 с генерация восьми дней и 3,8 с доставка 401 185 сообщений в Kafka.
Повторный make up на живом стенде — 1 м 5 с: мир заливается заново, и это
не оплошность — WatchID те же, повтор схлопнет ReplacingMergeTree.
Смоук — 9 с, check-clickhouse — 8 с с новой девятой проверкой. make test
вырос до 71 с: 58 с прежних тестов плюс 13 с на пересборку восьми дней для
сверки с описью. Прежние 40 с в таблице устарели ещё до #42 — тесты добавляли
#41 и #43.
Что новая проверка умеет краснеть, снято двумя поломками того же дня, и
проверялись обе ветви её диагноза. Снесли партицию 2026-06-03 в
ods.event_rep — проверка покраснела, показала недостающий день и назвала
адрес: «таблица брака пуста, события не доехали до ODS, начните с чтеца
топика». Затем положили в сырьё заведомо негодную строку — брак появился, и
диагноз сменился на второй, с признаком для различения: «сойдётся недостача с
числом брака — сломан разбор, не сойдётся — брак от прежних опытов». Строки
опыта убраны, день переигран make generate-batch GENERATOR_DAY=2; счёт
вернулся к 401 185, и это заодно показало дедупликацию: повтор дня не удвоил
счёт под FINAL.
Замеры 6 августа 2026 года, стенд поднят заранее. Время взято по time и
совпадает с тем, что цель печатает сама. Оно плавает от прогона к прогону:
смоук дал 8 секунд дважды (без проверки Kafka, до её появления, — 5 и 6),
check-services — 43 и 44. В таблице стоит большее из замеренных.
Перемер 7 августа 2026 года — приёмка этапа 2 целиком: make clean и make up
подряд заняли 2 м 58 с и залили стартовый мир, дальше по порядку все три цели
на стенде и три без него. Смоук дал 9 секунд, check-clickhouse — 8,
make test — 71. check-services — 59 и 48; в таблицу по прежнему правилу
пошло большее. Против 44 секунд накануне цель подорожала, и причину назвать
нечем: между замерами и стартовый мир в хранилище, и холодный подъём перед
первым прогоном. Число здесь — замер с датой, а не бюджет, и повод разбираться
появится, когда за него кто-нибудь начнёт держаться.
До деления scripts/stand-smoke.sh шёл 48 секунд на 25 проверок, из них
42 секунды съедали шесть: Kafka с машины, два запуска пробников Airflow и три
проверки Superset. После деления те же 25 проверок разошлись по двум целям:
19 в смоуке и 6 в check-services. Содержание ни одной из них не менялось.
Двадцатая проверка смоука — единственная новая: Kafka спрашивают с машины через
отображённый порт. Деление оставило дыру, которой раньше не было. Про Airflow,
Superset, Prometheus и Grafana смоук стучится с машины в отображённый порт, а
про Kafka после переезда знал только «контейнер здоров» — а это вердикт
проверки состояния из compose.yaml, и та спрашивает брокер изнутри по
внутреннему слушателю. Внешняя дверь оставалась непроверенной до
check-services с его минутой, хотя генератор пишет в Kafka именно с
машины. Стоит проверка 2,6 секунды, и почти всё это — старт JVM в разовом
контейнере; ожидание ответа ограничено пятнадцатью секундами, впятеро больше
замеренного.
Что обе разделённые цели умеют краснеть, проверено руками в тот же день. Со
снятым prometheus смоук дал три ошибки и ненулевой код возврата. С
подменённым ожидаемым UUID подключения Superset так же покраснел
check-services. Новую проверку Kafka проверили её собственной поломкой:
брокеру объявили адрес kafka-nowhere:29092, оставив внутренний слушатель
целым, — проверка состояния контейнера осталась зелёной, а смоук покраснел
именно на этой строке. Краснеют они и когда на машине не хватает команды из
списка зависимостей.
Семантика счётчиков Docker OOMKilled и RestartCount, на которой держится
check_containers_survived, снята отдельными контейнерами и записана в
ADR 0004, раздел «Что проверено».
Разбор Bash из make config-test срезан 6 августа 2026 года, и вместе с ним —
двенадцать строк обхода репозитория со списком файлов. Проверка была сломана
с рождения: bash -n со списком файлов разбирает только первый, остальные
уходят ему в аргументы, — то есть из пяти скриптов проверялся один, и за всё
время цели этого никто не заметил. Заводить её заново незачем: скрипты стенда
запускаются с той же машины, и синтаксическая ошибка вылезает при первом же
запуске с номером строки. Разбор файлов DAG остался и по другому основанию —
их на машине не запускает никто.