Зерновой мир: мини-манифест и заливка при make up #42

Closed
opened 2026-08-01 21:19:42 +03:00 by ddmitry · 4 comments
Owner

Part of #4.

Цель

Зафиксировать «зерновой» мир конца этапа 2 — маленький срез эталонной оси
для стабильных приёмок следующих этапов — и замкнуть этап: заливка при
make up и проверка на настоящих данных.

Что войдёт

  • Каноническое зерно уже константа репозитория (seeds.py, CANONICAL_SEED,
    заведено в #38) — здесь оно только попадает в паспорт мини-манифеста.
  • Мини-манифест зернового мира: паспорт (зерно, версия генератора),
    счётчики, хеши по дням. Форма решается здесь — с прицелом на полный
    манифест этапа 7: мини-манифест — его младший брат, не вторая правда.
    Срез решён владельцем при нарезке (2026-08-01): первые 8 модельных
    дней оси
    , понедельник–понедельник. Полная неделя с выходными плюс
    первый замкнутый цикл окна K = 7: день D0 успевает замёрзнуть — этапам
    3–4 есть на чём принимать и «дыхание» выручки, и заморозку. Полный
    снимок 14 дней — этап 7.
  • make up заливает зерновой мир через Kafka пакетным режимом
    проигрывателя; счётчики против мини-манифеста идут отдельной проверкой
    в make check-clickhouse. В смоук их класть не надо: разметка целей
    решена в #54, ось — кого спрашивают, а счётчики в ods.event считает сам
    сервер и отвечает сразу. Смоук остаётся быстрой проверкой «стенд собран».
  • Эти счётчики — единственный постоянный сторож цепочки
    Kafka → STG → ODS.
    #43 закрыл свои три утверждения разовыми опытами и
    назвал сторожем цепочки именно их (решение владельца 7 августа 2026 года).
    Отсюда требование к форме: они обязаны ловить поломку разбора — сломалась
    матвью, события уехали в брак, счёт разошёлся, — а значит смотрят и на
    ods.event, и на *_errors, и при расхождении показывают, где именно оно.
    Считать одни события мало: брак так и останется невидимым.
  • Чек-скрипт «пересгенерируй день N — сравни хеш с манифестом».

Что приходит готовым из #41

Тикет идёт третьим: #41#43#42, оба предшественника влиты. К его старту
на стенде стоят проигрыватель, настоящие события в топике и типизированный ODS.
Готовым приходит генератор в собственном образе, разовая служба compose на нём,
цели make generate-batch / generate-live, ограниченная пачка с печатью числа
отправленного, способ проиграть несколько дней подряд одним запуском и CLI без
состояния — всё это видно в compose.yaml и Makefile.

Отсюда работа этого тикета, которую больше некому сделать:

  • Включить службу в make up — она приходит под профилем generator и
    в make up не входит. Снять её из-под профиля и дать ей зависимого с
    service_completed_successfully. Без зависимого up --wait считает успешно
    отработавшую разовую службу упавшей; предупреждение об этом уже стоит в
    compose.yaml у clickhouse-init, и цепочка kafka-init
    clickhouse-initairflow-init держится ровно на нём. Заливка идёт
    последней в цепи, поэтому зависимого ей придётся назначить осознанно.
  • Проверить, что заливка встаёт после того, как ODS готов принимать:
    порядок применения DDL решён нумерацией файлов, и последней по построению
    создаётся матвью приёма (sql/ddl/40-stg-views.sql) — она включает чтение
    топика, и всё доехавшее до появления разбора (30) минует ODS молча.
    Нумерацию не «выправлять»: пропуск намеренный, объяснение — в шапке файла.
  • Дождаться доезда, а не завершения заливки. up --wait дожидается
    службы, а приём асинхронный: Kafka-движок копит блок и отдаёт его по
    размеру либо по stream_flush_interval_ms (умолчание 7,5 с), а зерновой
    мир — это около 400 тыс. сообщений. Ждать ограниченным циклом опроса с
    таймаутом, а не sleep наугад; образцы циклов — в
    scripts/stand-services.sh.

Решить и внести в спеку генератора (раздел 9) тем же PR

  • Форма мини-манифеста зернового мира. Вместе с ней закрывается и второй
    оставшийся за этим тикетом пункт раздела 9 — хеш каталога в паспорте
    мира
    : правка цены или уровня спроса в CSV сейчас меняет мир молча.
    Третий открытый пункт, интерфейс запуска, закрывает #41. После этого
    раздел закрыть: подзаголовок «Остаётся открытым, за тикетами:» (раздел 9
    спеки) переписать решениями или удалить.

Перф-порог снят

Решение владельца 7 августа 2026 года: автоматического порога не будет.
Спека назначила «день ≤ 30 с» до того, как генератор написали; замер 7 августа
на машине стенда — 1,7 секунды на день в 50 626 событий, в восемнадцать раз
ниже порога. Как здесь говорят о времени, решила карта целей: цена — замеренное
число с датой, а не назначенный предел (docs/architecture/testing.md).
Наблюдаемость остаётся: проигрыватель печатает тайминги генерации и доставки
раздельно, а make up после этого тикета гоняет генератор по восемь дней при
каждом подъёме стенда.

Снятие доводится до спеки тем же PR, иначе она продолжит обещать проверку,
которой нет: раздел 5 (абзац «Автоматический порог один…» целиком) и строка
в разделе «Числа». Соседний абзац раздела 5 — «Остальное — наблюдаемость без
порогов» — остаётся и становится всем ответом; вместо порога туда идёт
замеренное число с датой.

Критерии приёмки

  • make clean && make up с нуля приводит стенд к данным зернового
    мира в ods.event; make check-clickhouse зелёный и сверяет
    счётчики с мини-манифестом. Счёт обрамляется по EventDate
    зернового мира
    : мир растёт — менти переиграет день, этап 5 добавит
    следующий, — и голый счёт по таблице разойдётся с манифестом законно,
    без всякой поломки.
  • Счётчики видят поломку разбора: при расхождении названо, где именно —
    в событиях или в браке.
  • Хеш дня, пересчитанный чек-скриптом, сходится с манифестом в git;
    мини-манифест в git, снимок в git не попадает. Внутрипрогонный повтор
    проверять не надо — побайтовое совпадение двух прогонов уже держит
    generator/tests/test_player.py::test_two_runs_give_the_same_file.
  • Порог 30 с снят из спеки генератора в обоих местах; на его месте —
    замеренное число с датой.
  • Цена make up перезамерена и записана в карту целей
    (docs/architecture/testing.md): заливка зернового мира её меняет, а
    цена там — замер с датой.
  • Документация обновлена тем же PR: быстрый старт и описание
    зернового мира.
  • Раздел 9 спеки генератора закрыт: открытых вопросов «решается при
    нарезке» не осталось.
  • Словарь CONTEXT.md пополнен: «зерновой мир», «мини-манифест».

Границы

  • Полный эталонный мир (14 дней), пересборка манифеста, CI-генерация на
    amd64/arm64 — этап 7 (#9).
  • Числа объёмов решены спекой — не переоткрывать.
  • Корректность процессов хранилища проверяют отдельные даги DQ (планы
    владельца по следующим уровням хранилища), а не проверки стенда. Находку
    «это стоило бы проверять регулярно» нести туда, а не в
    make check-clickhouse.

Сначала прочитать

  • docs/specs/2026-08-01-generator.md — разделы 2, 5, 9.
  • docs/specs/2026-07-30-stand-v2-realism.md — раздел 8.
  • #54 и docs/architecture/testing.md — разметка целей проверки: что
    утверждает каждая и куда класть новую; там же правило про цену как замер.
  • #41 целиком, с комментариями: там решения про размещение генератора,
    профиль разовой службы и интерфейс запуска, на которых стоит раздел «Что
    приходит готовым».
  • #43 с комментариями: асинхронность приёма, дисциплина ожидания
    ограниченным циклом и довод, по которому постоянных проверок цепочки там
    не осталось ни одной.

Проверка

  • make clean && make up && make check-clickhouse && make smoke
  • чек-скрипт хеша дня против манифеста
Part of #4. ## Цель Зафиксировать «зерновой» мир конца этапа 2 — маленький срез эталонной оси для стабильных приёмок следующих этапов — и замкнуть этап: заливка при `make up` и проверка на настоящих данных. ## Что войдёт - Каноническое зерно уже константа репозитория (`seeds.py`, `CANONICAL_SEED`, заведено в #38) — здесь оно только попадает в паспорт мини-манифеста. - Мини-манифест зернового мира: паспорт (зерно, версия генератора), счётчики, хеши по дням. Форма решается здесь — с прицелом на полный манифест этапа 7: мини-манифест — его младший брат, не вторая правда. Срез решён владельцем при нарезке (2026-08-01): **первые 8 модельных дней оси**, понедельник–понедельник. Полная неделя с выходными плюс первый замкнутый цикл окна K = 7: день D0 успевает замёрзнуть — этапам 3–4 есть на чём принимать и «дыхание» выручки, и заморозку. Полный снимок 14 дней — этап 7. - `make up` заливает зерновой мир через Kafka пакетным режимом проигрывателя; счётчики против мини-манифеста идут отдельной проверкой в `make check-clickhouse`. В смоук их класть не надо: разметка целей решена в #54, ось — кого спрашивают, а счётчики в `ods.event` считает сам сервер и отвечает сразу. Смоук остаётся быстрой проверкой «стенд собран». - **Эти счётчики — единственный постоянный сторож цепочки `Kafka → STG → ODS`.** #43 закрыл свои три утверждения разовыми опытами и назвал сторожем цепочки именно их (решение владельца 7 августа 2026 года). Отсюда требование к форме: они обязаны ловить поломку разбора — сломалась матвью, события уехали в брак, счёт разошёлся, — а значит смотрят и на `ods.event`, и на `*_errors`, и при расхождении показывают, где именно оно. Считать одни события мало: брак так и останется невидимым. - Чек-скрипт «пересгенерируй день N — сравни хеш с манифестом». ## Что приходит готовым из #41 Тикет идёт третьим: #41 → #43 → #42, оба предшественника влиты. К его старту на стенде стоят проигрыватель, настоящие события в топике и типизированный ODS. Готовым приходит генератор в собственном образе, разовая служба compose на нём, цели `make generate-batch` / `generate-live`, ограниченная пачка с печатью числа отправленного, способ проиграть несколько дней подряд одним запуском и CLI без состояния — всё это видно в `compose.yaml` и `Makefile`. Отсюда работа этого тикета, которую больше некому сделать: - **Включить службу в `make up`** — она приходит **под профилем** `generator` и в `make up` не входит. Снять её из-под профиля и **дать ей зависимого** с `service_completed_successfully`. Без зависимого `up --wait` считает успешно отработавшую разовую службу упавшей; предупреждение об этом уже стоит в `compose.yaml` у `clickhouse-init`, и цепочка `kafka-init` → `clickhouse-init` → `airflow-init` держится ровно на нём. Заливка идёт последней в цепи, поэтому зависимого ей придётся назначить осознанно. - Проверить, что заливка встаёт **после того, как ODS готов принимать**: порядок применения DDL решён нумерацией файлов, и последней по построению создаётся матвью приёма (`sql/ddl/40-stg-views.sql`) — она включает чтение топика, и всё доехавшее до появления разбора (30) минует ODS молча. Нумерацию не «выправлять»: пропуск намеренный, объяснение — в шапке файла. - **Дождаться доезда, а не завершения заливки.** `up --wait` дожидается службы, а приём асинхронный: Kafka-движок копит блок и отдаёт его по размеру либо по `stream_flush_interval_ms` (умолчание 7,5 с), а зерновой мир — это около 400 тыс. сообщений. Ждать ограниченным циклом опроса с таймаутом, а не `sleep` наугад; образцы циклов — в `scripts/stand-services.sh`. ## Решить и внести в спеку генератора (раздел 9) тем же PR - Форма мини-манифеста зернового мира. Вместе с ней закрывается и второй оставшийся за этим тикетом пункт раздела 9 — **хеш каталога в паспорте мира**: правка цены или уровня спроса в CSV сейчас меняет мир молча. Третий открытый пункт, интерфейс запуска, закрывает #41. После этого раздел закрыть: подзаголовок «Остаётся открытым, за тикетами:» (раздел 9 спеки) переписать решениями или удалить. ## Перф-порог снят **Решение владельца 7 августа 2026 года: автоматического порога не будет.** Спека назначила «день ≤ 30 с» до того, как генератор написали; замер 7 августа на машине стенда — **1,7 секунды** на день в 50 626 событий, в восемнадцать раз ниже порога. Как здесь говорят о времени, решила карта целей: цена — замеренное число с датой, а не назначенный предел (`docs/architecture/testing.md`). Наблюдаемость остаётся: проигрыватель печатает тайминги генерации и доставки раздельно, а `make up` после этого тикета гоняет генератор по восемь дней при каждом подъёме стенда. Снятие доводится до спеки тем же PR, иначе она продолжит обещать проверку, которой нет: раздел 5 (абзац «Автоматический порог один…» целиком) и строка в разделе «Числа». Соседний абзац раздела 5 — «Остальное — наблюдаемость без порогов» — остаётся и становится всем ответом; вместо порога туда идёт замеренное число с датой. ## Критерии приёмки - [x] `make clean && make up` с нуля приводит стенд к данным зернового мира в `ods.event`; `make check-clickhouse` зелёный и сверяет счётчики с мини-манифестом. **Счёт обрамляется по `EventDate` зернового мира**: мир растёт — менти переиграет день, этап 5 добавит следующий, — и голый счёт по таблице разойдётся с манифестом законно, без всякой поломки. - [x] Счётчики видят поломку разбора: при расхождении названо, где именно — в событиях или в браке. - [x] Хеш дня, пересчитанный чек-скриптом, сходится с манифестом в git; мини-манифест в git, снимок в git не попадает. Внутрипрогонный повтор проверять не надо — побайтовое совпадение двух прогонов уже держит `generator/tests/test_player.py::test_two_runs_give_the_same_file`. - [x] Порог 30 с снят из спеки генератора в обоих местах; на его месте — замеренное число с датой. - [x] Цена `make up` перезамерена и записана в карту целей (`docs/architecture/testing.md`): заливка зернового мира её меняет, а цена там — замер с датой. - [x] Документация обновлена тем же PR: быстрый старт и описание зернового мира. - [x] Раздел 9 спеки генератора закрыт: открытых вопросов «решается при нарезке» не осталось. - [x] Словарь CONTEXT.md пополнен: «зерновой мир», «мини-манифест». ## Границы - Полный эталонный мир (14 дней), пересборка манифеста, CI-генерация на amd64/arm64 — этап 7 (#9). - Числа объёмов решены спекой — не переоткрывать. - Корректность процессов хранилища проверяют отдельные даги DQ (планы владельца по следующим уровням хранилища), а не проверки стенда. Находку «это стоило бы проверять регулярно» нести туда, а не в `make check-clickhouse`. ## Сначала прочитать - docs/specs/2026-08-01-generator.md — разделы 2, 5, 9. - docs/specs/2026-07-30-stand-v2-realism.md — раздел 8. - #54 и `docs/architecture/testing.md` — разметка целей проверки: что утверждает каждая и куда класть новую; там же правило про цену как замер. - #41 целиком, **с комментариями**: там решения про размещение генератора, профиль разовой службы и интерфейс запуска, на которых стоит раздел «Что приходит готовым». - #43 **с комментариями**: асинхронность приёма, дисциплина ожидания ограниченным циклом и довод, по которому постоянных проверок цепочки там не осталось ни одной. ## Проверка - `make clean && make up && make check-clickhouse && make smoke` - чек-скрипт хеша дня против манифеста
ddmitry added the ready-for-agent label 2026-08-01 21:20:04 +03:00
Author
Owner

Правка тела по решению из #54: счётчики против мини-манифеста уходят из смоука в цель проверки ClickHouse.

Разметка целей в #54 идёт по оси «кого спрашивают»: смоук отвечает «стенд собран» и обязан оставаться быстрым, а счётчики в ods.event считает сам сервер и отвечает сразу — им место рядом с договором со схемой из #43. Заодно там же smoke-cluster переименовывается в check-clickhouse; до слияния #54 цель зовётся прежним именем, так что порядок работ этот тикет не связывает.

Тронуты: «Что войдёт», первый критерий приёмки, «Сначала прочитать», «Проверка».

Правка тела по решению из #54: счётчики против мини-манифеста уходят из смоука в цель проверки ClickHouse. Разметка целей в #54 идёт по оси «кого спрашивают»: смоук отвечает «стенд собран» и обязан оставаться быстрым, а счётчики в `ods.event` считает сам сервер и отвечает сразу — им место рядом с договором со схемой из #43. Заодно там же `smoke-cluster` переименовывается в `check-clickhouse`; до слияния #54 цель зовётся прежним именем, так что порядок работ этот тикет не связывает. Тронуты: «Что войдёт», первый критерий приёмки, «Сначала прочитать», «Проверка».
Author
Owner

Хэндовер из #41 дописан (грилинг постановки #41, 7 августа 2026 года).

Тикет получил раздел «Что приходит готовым из #41» и работу, которая из этого
следует. Главное, чего в теле не было и обо что исполнитель упёрся бы на первой
минуте: разовая служба заливки приходит под профилем и в make up не
входит — включить её и дать ей зависимого с service_completed_successfully
предстоит здесь. Без зависимого up --wait считает успешно отработавшую
разовую службу упавшей; предупреждение об этом стоит в compose.yaml у
clickhouse-init, а заливка идёт последней в цепи, так что зависимого ей
придётся назначить осознанно.

Там же названы остальные подарки #41: генератор живёт в образе Airflow на базе
apache/airflow:3.3.0-python3.14 (штатный образ несёт 3.13, и лок генератора в
него не встанет), контекст сборки образа перенесён в корень репозитория,
зависимости ставятся из uv.lock, клиент Kafka объявлен группой зависимостей
генератора, CLI без состояния, ограниченная пачка печатает число отправленного.

Заодно две правки по мелочи. Форма мини-манифеста названа не «последним»
открытым вопросом раздела 9, а одним из двух, оставшихся за этим тикетом: рядом
стоит хеш каталога в паспорте мира — правка цены или уровня спроса в CSV сейчас
меняет мир молча. Третий пункт, интерфейс запуска, закрывает #41. И снята
устаревшая оговорка «до #54 эта цель зовётся make smoke-cluster»:
переименование уже случилось.

**Хэндовер из #41 дописан** (грилинг постановки #41, 7 августа 2026 года). Тикет получил раздел «Что приходит готовым из #41» и работу, которая из этого следует. Главное, чего в теле не было и обо что исполнитель упёрся бы на первой минуте: разовая служба заливки приходит **под профилем** и в `make up` не входит — включить её и **дать ей зависимого** с `service_completed_successfully` предстоит здесь. Без зависимого `up --wait` считает успешно отработавшую разовую службу упавшей; предупреждение об этом стоит в `compose.yaml` у `clickhouse-init`, а заливка идёт последней в цепи, так что зависимого ей придётся назначить осознанно. Там же названы остальные подарки #41: генератор живёт в образе Airflow на базе `apache/airflow:3.3.0-python3.14` (штатный образ несёт 3.13, и лок генератора в него не встанет), контекст сборки образа перенесён в корень репозитория, зависимости ставятся из `uv.lock`, клиент Kafka объявлен группой зависимостей генератора, CLI без состояния, ограниченная пачка печатает число отправленного. Заодно две правки по мелочи. Форма мини-манифеста названа не «последним» открытым вопросом раздела 9, а одним из двух, оставшихся за этим тикетом: рядом стоит хеш каталога в паспорте мира — правка цены или уровня спроса в CSV сейчас меняет мир молча. Третий пункт, интерфейс запуска, закрывает #41. И снята устаревшая оговорка «до #54 эта цель зовётся `make smoke-cluster`»: переименование уже случилось.
Author
Owner

Хэндовер переписан под контейнер; из холодного ревью связки легли четыре
правки.

#41 переиграл размещение: у генератора теперь свой образ (python:3.14,
зависимости uv sync --frozen из лока, каталог товаров внутри), а образ
Airflow не трогается — ни база, ни контекст сборки, ни список пакетов. Раздел
«Что приходит готовым» переписан под это; заодно оттуда приходит способ
проиграть несколько дней подряд одним запуском — зерновой мир это восемь дней,
и восемь стартов службы внутри make up были бы плохим ответом.

Исправлена ошибка вчерашнего хэндовера. Было сказано, что последней
создаётся матвью разбора, — наоборот: последней по построению создаётся матвью
приёма (sql/ddl/40-stg-views.sql), а разбор идёт под номером 30. Вывод
про порядок заливки уцелел, но по названной причине исполнитель мог полезть
«выправлять нумерацию», от чего прямо предостерегает шапка файла.

Ожидание доезда названо отдельно. up --wait дожидается завершения
службы-заливки, а приём асинхронный: Kafka-движок отдаёт блок по размеру либо
по stream_flush_interval_ms (умолчание 7,5 с), а зерновой мир — около
400 тыс. сообщений. Без ограниченного цикла опроса первый критерий тикета
красен по устройству, а не по поломке. Образцы циклов — в
scripts/stand-services.sh; #43 добавлен в «сначала прочитать», потому что
дисциплина ожидания записана там.

Счёт против мини-манифеста обрамляется по EventDate зернового мира. В том
же make check-clickhouse живёт проверка инварианта слоёв из #43, а она сама
вставляет управляемую пачку — голый счёт по таблице разошёлся бы с манифестом
без всякой поломки.

Мелочи: пункт «каноническое зерно — константа репозитория» был холостым, зерно
заведено ещё в #38 (seeds.py, CANONICAL_SEED) — переформулирован в «попадает
в паспорт мини-манифеста». Заголовок, который тикет велел снять из раздела 9
спеки, назывался иначе; поправлено на существующий подзаголовок «Остаётся
открытым, за тикетами:».

**Хэндовер переписан под контейнер; из холодного ревью связки легли четыре правки.** #41 переиграл размещение: у генератора теперь свой образ (`python:3.14`, зависимости `uv sync --frozen` из лока, каталог товаров внутри), а образ Airflow не трогается — ни база, ни контекст сборки, ни список пакетов. Раздел «Что приходит готовым» переписан под это; заодно оттуда приходит способ проиграть несколько дней подряд одним запуском — зерновой мир это восемь дней, и восемь стартов службы внутри `make up` были бы плохим ответом. **Исправлена ошибка вчерашнего хэндовера.** Было сказано, что последней создаётся матвью разбора, — наоборот: последней по построению создаётся матвью **приёма** (`sql/ddl/40-stg-views.sql`), а разбор идёт под номером 30. Вывод про порядок заливки уцелел, но по названной причине исполнитель мог полезть «выправлять нумерацию», от чего прямо предостерегает шапка файла. **Ожидание доезда названо отдельно.** `up --wait` дожидается завершения службы-заливки, а приём асинхронный: Kafka-движок отдаёт блок по размеру либо по `stream_flush_interval_ms` (умолчание 7,5 с), а зерновой мир — около 400 тыс. сообщений. Без ограниченного цикла опроса первый критерий тикета красен по устройству, а не по поломке. Образцы циклов — в `scripts/stand-services.sh`; #43 добавлен в «сначала прочитать», потому что дисциплина ожидания записана там. **Счёт против мини-манифеста обрамляется по `EventDate` зернового мира.** В том же `make check-clickhouse` живёт проверка инварианта слоёв из #43, а она сама вставляет управляемую пачку — голый счёт по таблице разошёлся бы с манифестом без всякой поломки. Мелочи: пункт «каноническое зерно — константа репозитория» был холостым, зерно заведено ещё в #38 (`seeds.py`, `CANONICAL_SEED`) — переформулирован в «попадает в паспорт мини-манифеста». Заголовок, который тикет велел снять из раздела 9 спеки, назывался иначе; поправлено на существующий подзаголовок «Остаётся открытым, за тикетами:».
ddmitry changed title from Зерновой мир: мини-манифест, заливка при make up, перф-порог to Зерновой мир: мини-манифест и заливка при make up 2026-08-07 17:34:18 +03:00
Author
Owner

Проход той же линзой, что и по #43, 7 августа 2026 года. Тело правилось в
09:12 — до слияния #41 (14:37) и #43 (16:52), и часть его доводов за это время
умерла. Что изменилось.

Перф-порог снят целиком — решение владельца. Спека назначила «день ≤ 30 с»
до того, как генератор написали. Замер сегодня на машине стенда: 1,7 секунды
на день в 50 626 событий, файл 56 МБ. Порог в восемнадцать раз выше факта зелен
при любой правдоподобной регрессии, а карта целей уже решила, как здесь говорят
о времени: цена — замеренное число с датой, а не назначенный предел. Перф-тест
вносил ровно то, что карта отвергла. Наблюдаемость остаётся и без него:
проигрыватель печатает тайминги генерации и доставки раздельно, а make up
после этого тикета гоняет генератор по восемь дней при каждом подъёме стенда.
Снятие доведено до спеки мандатом в критериях — два места, раздел 5 и список
чисел, — иначе спека продолжит обещать проверку, которой нет. Заголовок тикета
поправлен.

Сказано, что счётчики унаследовали роль сторожа. После #43 они —
единственный постоянный сторож цепочки Kafka → STG → ODS; в теле это не
стояло, и исполнитель написал бы счёт по ods.event, формально не ошибившись.
Теперь названо, что они обязаны ловить: сломалась матвью разбора, события
уехали в брак, счёт разошёлся, — значит смотреть надо и на брак, и при
расхождении показывать, где оно.

Критерий про хеши переписан. «Чек-скрипт дважды подряд даёт те же хеши» уже
держит юнит-тест из #41
generator/tests/test_player.py::test_two_runs_give_the_same_file, он сравнивает
целые хеши двух прогонов. Ценное утверждение другое и в критерий не попадало:
хеш дня сходится с манифестом, лежащим в git, то есть мир не дрейфует между
коммитами.

Добавлен критерий на цену make up. Заливка зернового мира её заметно
меняет, а в карте целей цена — замер с датой. Без этого замер 6 августа станет
неправдой молча.

Хэндовер из #41 ужат. Описательная половина («свой образ», «зависимости из
лока», «CLI без состояния») теперь проверяется взглядом в compose.yaml и
Makefile — оба влиты. Действенная половина осталась дословно: служба приходит
под профилем generator, включить её в make up и дать зависимого с
service_completed_successfully.

Границы пополнились одной строкой: корректность процессов хранилища заберут
отдельные даги DQ (планы владельца по следующим уровням), а не проверки стенда.
Находку «это стоило бы проверять регулярно» нести туда.

Два довода в комментариях выше умерли — не следуйте им. Обрамление счёта по
EventDate объяснялось тем, что «в том же make check-clickhouse живёт
проверка инварианта слоёв из #43, а она сама вставляет управляемую пачку»:
такой проверки нет, #43 не добавил в скрипт ни одной. Обрамление всё равно
нужно, и тело даёт свой довод — мир растёт. Там же счётчикам обещано место
«рядом с договором со схемой из #43»: contract-тест снят 6 августа.

Тело было 121 строку, стало 143. Выросло на две вещи, которых не хватало
(роль сторожа и цена make up), и на объяснение реза; работы в PR при этом
стало меньше — перф-тест, маркер и отдельная make-цель не пишутся.

**Проход той же линзой, что и по #43, 7 августа 2026 года.** Тело правилось в 09:12 — до слияния #41 (14:37) и #43 (16:52), и часть его доводов за это время умерла. Что изменилось. **Перф-порог снят целиком — решение владельца.** Спека назначила «день ≤ 30 с» до того, как генератор написали. Замер сегодня на машине стенда: **1,7 секунды** на день в 50 626 событий, файл 56 МБ. Порог в восемнадцать раз выше факта зелен при любой правдоподобной регрессии, а карта целей уже решила, как здесь говорят о времени: цена — замеренное число с датой, а не назначенный предел. Перф-тест вносил ровно то, что карта отвергла. Наблюдаемость остаётся и без него: проигрыватель печатает тайминги генерации и доставки раздельно, а `make up` после этого тикета гоняет генератор по восемь дней при каждом подъёме стенда. Снятие доведено до спеки мандатом в критериях — два места, раздел 5 и список чисел, — иначе спека продолжит обещать проверку, которой нет. Заголовок тикета поправлен. **Сказано, что счётчики унаследовали роль сторожа.** После #43 они — единственный постоянный сторож цепочки `Kafka → STG → ODS`; в теле это не стояло, и исполнитель написал бы счёт по `ods.event`, формально не ошибившись. Теперь названо, что они обязаны ловить: сломалась матвью разбора, события уехали в брак, счёт разошёлся, — значит смотреть надо и на брак, и при расхождении показывать, где оно. **Критерий про хеши переписан.** «Чек-скрипт дважды подряд даёт те же хеши» уже держит юнит-тест из #41 — `generator/tests/test_player.py::test_two_runs_give_the_same_file`, он сравнивает целые хеши двух прогонов. Ценное утверждение другое и в критерий не попадало: хеш дня сходится с **манифестом, лежащим в git**, то есть мир не дрейфует между коммитами. **Добавлен критерий на цену `make up`.** Заливка зернового мира её заметно меняет, а в карте целей цена — замер с датой. Без этого замер 6 августа станет неправдой молча. **Хэндовер из #41 ужат.** Описательная половина («свой образ», «зависимости из лока», «CLI без состояния») теперь проверяется взглядом в `compose.yaml` и `Makefile` — оба влиты. Действенная половина осталась дословно: служба приходит под профилем `generator`, включить её в `make up` и дать зависимого с `service_completed_successfully`. **Границы пополнились одной строкой:** корректность процессов хранилища заберут отдельные даги DQ (планы владельца по следующим уровням), а не проверки стенда. Находку «это стоило бы проверять регулярно» нести туда. **Два довода в комментариях выше умерли — не следуйте им.** Обрамление счёта по `EventDate` объяснялось тем, что «в том же `make check-clickhouse` живёт проверка инварианта слоёв из #43, а она сама вставляет управляемую пачку»: такой проверки нет, #43 не добавил в скрипт ни одной. Обрамление всё равно нужно, и тело даёт свой довод — мир растёт. Там же счётчикам обещано место «рядом с договором со схемой из #43»: contract-тест снят 6 августа. Тело было 121 строку, стало 143. Выросло на две вещи, которых не хватало (роль сторожа и цена `make up`), и на объяснение реза; работы в PR при этом стало меньше — перф-тест, маркер и отдельная make-цель не пишутся.
Sign in to join this conversation.