Цели make смешивают два уровня: корень репозитория и генератор #65

Closed
opened 2026-08-07 19:00:04 +03:00 by ddmitry · 1 comment
Owner

Развилка пройдена 9 августа 2026 года, тикет готов к исполнению.
Решение, доводы и отклонённые варианты — в комментарии ниже; он источник
истины для работы. Ниже по телу остались находка и веер: находка — материал
и доказательства, веер — история выбора (принят вариант B).

Цель

Привести имена и охват целей make в соответствие с принятым решением:
корень — про стенд, генератор — за своей дверью.

Находка

В корневом Makefile 16 целей, и 5 из них начинаются с cd generator:
lint, typecheck, test, docs, inventory. Корневой Makefile смешивает
два уровня — стенд целиком и один его компонент, — и имена об этом молчат.

Это не только про слова. Питона в репозитории 34 файла, из них 31 в
generator/
, а три лежат снаружи:

dags/test_clickhouse.py
dags/test_kafka.py
infra/superset/superset_config.py

make lint и make typecheck не видят ни одного из них: ruff запускается
из generator/ и дальше своего pyproject.toml не смотрит (проверено
ruff check --show-files, 7 августа 2026 года). То есть цель, названная
общерепозиторной, охватывает 31 файл из 34 и молча пропускает ровно те,
которые на машине никто не запускает: даги проверяет только make config-test,
и то лишь на разбор.

Почему это не косметика

Три довода, по возрастанию цены.

  1. Дыра существует сегодня. Три файла вне линта и типов — не будущая
    проблема, а нынешняя.
  2. make test обещает категорию, а отдаёт компонент. Сегодня это почти
    правда — генератор единственный носитель тестов. С этапа 3 придут
    трансформации и даги, и человек, набравший make test и увидевший
    зелёное, поверит в больше, чем случилось. Молча.
  3. Карта проверок строит имена по оси «кого спрашивают»
    (docs/architecture/testing.md). lint, typecheck и test из этой оси
    выпадают: они названы по инструменту, а охвачены по каталогу — и два
    основания расходятся.

Повод нашёлся при исполнении #42: цель make test выросла с 58 до 71 секунды,
разговор пошёл о её имени и упёрся в это.

Веер вариантов (пройдено)

Оставлен историей: принят B, достроенный корневым lint по коду стенда.
Почему именно так и что отклонено — в комментарии с решением.

A. Корневая цель означает репозиторий и дорастает до него.
make lint линтует и generator/, и dags/, и infra/. make test либо
переименовывается в test-generator, либо ждёт вторых тестов.
За: совпадает с осью карты проверок, дыру закрывает по-настоящему.
Против: ty на дагах требует Airflow (from airflow.sdk import ...), а его в
окружении генератора нет и быть не должно — понадобится второе окружение либо
честная оговорка «типы проверяются только у генератора».

B. Корень — про стенд, у генератора свой Makefile.
Корень делегирует: make -C generator lint. Стендовые цели остаются в корне.
За: отражает настоящее устройство — генератор отдельный переносимый пакет со
своим pyproject, локом и README.
Против: две входные двери вместо одной; дыра с дагами при этом не
закрывается сама, ей всё равно нужен адрес.

C. Имена честно сужаются.
lint-generator, typecheck-generator, test-generator; общие заводятся,
когда появится второй компонент с тестами.
За: самый дешёвый и ничего не ломает; враньё исчезает сразу.
Против: лечит имя, а не охват — три файла как были непокрытыми, так и
останутся.

Границы

  • Содержание проверок не трогать: вопрос про охват и имена, а не про то, что
    утверждает ruff или ty.
  • make smoke, check-clickhouse, check-services не переименовывать —
    их имена уже стоят на оси «кого спрашивают».
  • Не заводить агрегат «прогнать всё»: карта проверок прямо против
    («деление целей ценно ровно до тех пор, пока оно не превратилось в „гонять
    всегда всё"»).
  • Окружение для дагов на машине не заводить и находки ty не чинить — довод
    в решении. Их называют в теле PR и оставляют как есть.
  • Развилку не переоткрывать: check-generator, суффикс lint-stand и отказ
    от generator/Makefile рассмотрены и отклонены.

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

  • Комментарий с решением в этом тикете — источник истины, включая список
    мест, которые легко пропустить.
  • docs/architecture/testing.md — карта целей, ось «кого спрашивают»,
    правило про цену как замер.
  • Makefile и generator/pyproject.toml — нынешние цели и настройка ruff.
  • #60 — соседний тикет того же рода: параметризация, которой нечего
    параметризовать.

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

  • Корневой Makefile: осталось 12 целей, сгруппированы по использованию;
    lint зовёт ruff по явным путям dags и infra/superset.
  • Заведён generator/Makefile с целями lint, typecheck, test,
    docs, inventory; из корня они убраны.
  • Корневой конфиг ruff: список правил тот же, что у генератора; версия
    закреплена той же, что в generator/uv.lock.
  • Четыре находки ruff в dags/ починены.
  • Карта целей обновлена тем же PR: таблица, счёт целей, довод об
    отсутствии корневого typecheck с условием возврата, сказано вслух про
    два разных make lint; цена корневого lint замерена.
  • Адреса целей поправлены всюду, где живут: оба README, спека генератора,
    AGENTS.md, schema_doc.py с пересобранным описанием выгрузки,
    inventory.py, тексты ошибок в тестах свежести.

Проверка

  • В корне: make config-test и make lint — зелёные.
  • Из generator/: make lint, make typecheck, make test — зелёные.
  • ruff check --show-files из корня перечисляет ровно три файла стенда, из
    generator/ — только файлы генератора.
  • Цена корневого lint замерена и вписана в карту проверок.
> **Развилка пройдена 9 августа 2026 года, тикет готов к исполнению.** > Решение, доводы и отклонённые варианты — в комментарии ниже; он источник > истины для работы. Ниже по телу остались находка и веер: находка — материал > и доказательства, веер — история выбора (принят вариант B). ## Цель Привести имена и охват целей `make` в соответствие с принятым решением: корень — про стенд, генератор — за своей дверью. ## Находка В корневом `Makefile` **16 целей, и 5 из них начинаются с `cd generator`**: `lint`, `typecheck`, `test`, `docs`, `inventory`. Корневой Makefile смешивает два уровня — стенд целиком и один его компонент, — и имена об этом молчат. Это не только про слова. Питона в репозитории **34 файла, из них 31 в `generator/`**, а три лежат снаружи: ``` dags/test_clickhouse.py dags/test_kafka.py infra/superset/superset_config.py ``` `make lint` и `make typecheck` не видят ни одного из них: `ruff` запускается из `generator/` и дальше своего `pyproject.toml` не смотрит (проверено `ruff check --show-files`, 7 августа 2026 года). То есть цель, названная общерепозиторной, охватывает 31 файл из 34 и молча пропускает ровно те, которые на машине никто не запускает: даги проверяет только `make config-test`, и то лишь на разбор. ## Почему это не косметика Три довода, по возрастанию цены. 1. **Дыра существует сегодня.** Три файла вне линта и типов — не будущая проблема, а нынешняя. 2. **`make test` обещает категорию, а отдаёт компонент.** Сегодня это почти правда — генератор единственный носитель тестов. С этапа 3 придут трансформации и даги, и человек, набравший `make test` и увидевший зелёное, поверит в больше, чем случилось. Молча. 3. **Карта проверок строит имена по оси «кого спрашивают»** (`docs/architecture/testing.md`). `lint`, `typecheck` и `test` из этой оси выпадают: они названы по инструменту, а охвачены по каталогу — и два основания расходятся. Повод нашёлся при исполнении #42: цель `make test` выросла с 58 до 71 секунды, разговор пошёл о её имени и упёрся в это. ## Веер вариантов (пройдено) Оставлен историей: принят **B**, достроенный корневым `lint` по коду стенда. Почему именно так и что отклонено — в комментарии с решением. **A. Корневая цель означает репозиторий и дорастает до него.** `make lint` линтует и `generator/`, и `dags/`, и `infra/`. `make test` либо переименовывается в `test-generator`, либо ждёт вторых тестов. За: совпадает с осью карты проверок, дыру закрывает по-настоящему. Против: `ty` на дагах требует Airflow (`from airflow.sdk import ...`), а его в окружении генератора нет и быть не должно — понадобится второе окружение либо честная оговорка «типы проверяются только у генератора». **B. Корень — про стенд, у генератора свой `Makefile`.** Корень делегирует: `make -C generator lint`. Стендовые цели остаются в корне. За: отражает настоящее устройство — генератор отдельный переносимый пакет со своим `pyproject`, локом и README. Против: две входные двери вместо одной; дыра с дагами при этом не закрывается сама, ей всё равно нужен адрес. **C. Имена честно сужаются.** `lint-generator`, `typecheck-generator`, `test-generator`; общие заводятся, когда появится второй компонент с тестами. За: самый дешёвый и ничего не ломает; враньё исчезает сразу. Против: лечит имя, а не охват — три файла как были непокрытыми, так и останутся. ## Границы - Содержание проверок не трогать: вопрос про охват и имена, а не про то, что утверждает `ruff` или `ty`. - `make smoke`, `check-clickhouse`, `check-services` не переименовывать — их имена уже стоят на оси «кого спрашивают». - Не заводить агрегат «прогнать всё»: карта проверок прямо против («деление целей ценно ровно до тех пор, пока оно не превратилось в „гонять всегда всё"»). - Окружение для дагов на машине не заводить и находки `ty` не чинить — довод в решении. Их называют в теле PR и оставляют как есть. - Развилку не переоткрывать: `check-generator`, суффикс `lint-stand` и отказ от `generator/Makefile` рассмотрены и отклонены. ## Сначала прочитать - **Комментарий с решением в этом тикете** — источник истины, включая список мест, которые легко пропустить. - `docs/architecture/testing.md` — карта целей, ось «кого спрашивают», правило про цену как замер. - `Makefile` и `generator/pyproject.toml` — нынешние цели и настройка `ruff`. - #60 — соседний тикет того же рода: параметризация, которой нечего параметризовать. ## Критерии приёмки - [x] Корневой `Makefile`: осталось 12 целей, сгруппированы по использованию; `lint` зовёт `ruff` по явным путям `dags` и `infra/superset`. - [x] Заведён `generator/Makefile` с целями `lint`, `typecheck`, `test`, `docs`, `inventory`; из корня они убраны. - [x] Корневой конфиг `ruff`: список правил тот же, что у генератора; версия закреплена той же, что в `generator/uv.lock`. - [x] Четыре находки `ruff` в `dags/` починены. - [x] Карта целей обновлена тем же PR: таблица, счёт целей, довод об отсутствии корневого `typecheck` с условием возврата, сказано вслух про два разных `make lint`; цена корневого `lint` замерена. - [x] Адреса целей поправлены всюду, где живут: оба README, спека генератора, `AGENTS.md`, `schema_doc.py` с пересобранным описанием выгрузки, `inventory.py`, тексты ошибок в тестах свежести. ## Проверка - В корне: `make config-test` и `make lint` — зелёные. - Из `generator/`: `make lint`, `make typecheck`, `make test` — зелёные. - `ruff check --show-files` из корня перечисляет ровно три файла стенда, из `generator/` — только файлы генератора. - Цена корневого `lint` замерена и вписана в карту проверок.
ddmitry added the ready-for-human label 2026-08-07 19:00:04 +03:00
Author
Owner

Решение

Развилка пройдена в грилинге 9 августа 2026 года. Из трёх вариантов тикета
принят B с достроенной второй половиной. Запись правлена после двух
холодных ревью — их находки учтены ниже.

Корень — про стенд, генератор — за своей дверью. Цели lint, typecheck,
test, docs, inventory уезжают из корня в новый generator/Makefile и
сохраняют там короткие имена: дверь уже сказала, о ком речь, суффикс ей не
нужен. Различие «стенд или генератор» несёт каталог, а не приставка в имени.

Основание не только вкусовое: генератор и так отдельная сущность по всем
внешним признакам — свой pyproject.toml, uv.lock, Dockerfile, README, — а
спека генератора утверждает это словами: «генератор — отдельная и заменяемая
сущность».

Побочно этим снимается пункт 2 находки: make test в корне не переименовывается,
а исчезает. Стенд как единую сущность спрашивают config-test, smoke,
check-clickhouse и check-services. Тикет решается вычитанием — из корня
уходят пять целей, приходит одна.

Корневой lint берёт под себя код стендаdags/ и infra/superset/.
Иначе «корень про стенд» оказалось бы тем же враньём в новой одежде: цель
названа по стенду и не трогает ни одного его файла. Стоит это дёшево: ruff
окружения не требует, венв в корне не нужен.

Три условия, без которых эта цель не работает как задумано:

  • Пути называются явноdags и infra/superset. ruff, запущенный из
    корня без путей, видит все 34 файла репозитория, включая генератор, и две
    двери перекрываются в первый же день.
  • Конфиг в корне свойruff.toml, потому что пакета в корне нет и
    настраивать ruff больше неоткуда. Но список правил берётся тот же, что у генератора
    E, F, I, UP, B. Замер холодного ревью: этот список проходит по dags/ и
    infra/superset/ без единой претензии к идиомам Airflow, то есть расхождения
    правил сегодня нет. Разойдутся — тогда и разойдутся, с настоящим поводом.
  • Версия ruff в корне закрепляется той же, что в локе генератора (0.16.1).
    У генератора её держит лок, в корне лока нет, а форматтер между версиями
    меняет вывод — иначе корневая проверка однажды покраснеет сама, без единой
    правки в репозитории. Держит закрепление сам вызов: uvx ruff@0.16.1.
    Равенство двух версий не сторожит никто — обновится лок генератора, версию
    правят и здесь; сказать это вслух место в карте проверок.

Проверено и рисков не несёт: иерархия конфигов ruff работает как задумано —
корневой конфиг правила генератору не подменит.

Корневого typecheck не будет, и это записывается доводом. Проверке типов
мало прочитать файл: чтобы понять from airflow.sdk import dag, ей нужен
установленный Airflow, а он живёт в образе, не на машине. Замер 9 августа
2026 года: apache-airflow-task-sdk тянет apache-airflow-core и дальше
полный apache-airflow==3.3.0132 пакета ради двух файлов пробников,
и это вместе с clickhouse-connect и confluent-kafka, которые образ ставит
сверх ядра. Документация Airflow обещает обратное («import only the classes you
need, without installing the full Airflow core»), но метаданные пакета этого не
подтверждают — проверено uv pip compile.

Цена решения называется честно: две настоящие находки ty в test_kafka.py
постоянного сторожа не получают. Вопрос вернётся на этапе 5, когда придут
настоящие даги и цена окружения станет оправданной; условию возврата место
в карте проверок рядом с доводом, а не в этом тикете — он после слияния
закроется.

Цели корневого Makefile группируются по использованию, менти сверху вниз:
жизнь стенда (up, down, clean, ps, logs) — проверки стенда (smoke,
check-clickhouse, check-services) — проверки без стенда (config-test,
lint) — наполнение миром (generate-batch, generate-live).

Отклонено

  • check-generator по образцу check-clickhouse. Приставка check- стоит
    на целях, спрашивающих работающий стенд; генератор так не спросить — его
    образ собирается с --no-dev, ни pytest, ни ruff, ни ty в него не едут, а
    тесты не копируются вовсе. Второй довод жёстче и записан в карте проверок:
    агрегат из трёх проверок — это «гонять всегда всё», и цена подтверждает
    (0,4 с + 0,5 с + 71 с), а check-generator только для pytest врал бы в
    другую сторону — линт и типы тоже проверки генератора.
  • Второе окружение на машине ради ty для дагов — 132 пакета, которые
    обязаны повторять версии образа и разъезжаются с ним молча.
  • Алиас в корне, делегирующий генератору (test: make -C generator test) —
    граница нарисована и тут же стёрта. Корень про генератор молчит, адрес
    называет README.
  • Разные списки правил ruff у корня и генератора — обосновывались бы
    расхождением, которого замер не показывает.
  • Цель help — дублирует README и разъезжается с ним молча.
  • Окружение в корне (pyproject.toml, лок, .venv) ради удобства менти
    не отклонено, а вынесено за границы тикета; вопрос открыт. Разбор 9 августа
    2026 года: конфиг ruff ищется вверх по дереву, поэтому редактору ruff.toml
    и pyproject.toml дают одни и те же правила — формат файла тут не решает
    ничего (проверено по докам Astral через Context7). Настоящую пользу —
    подсветку и переходы по airflow.sdk — даёт не файл, а установленный Airflow,
    и повторять в корневом локе версии образа сегодня не с чего: Python образа
    в репозитории нигде не записан, он приезжает с тегом apache/airflow:3.3.0.
    Вдобавок одно окружение на две нужды ставит самую дешёвую проверку за
    шлагбаум тяжёлого uv sync. Обратно решение стоит три строки: конфиг
    переезжает из ruff.toml в [tool.ruff].

Что делать при исполнении

Помимо очевидного (Makefile, новый generator/Makefile, корневой конфиг
ruff, таблица целей и цены в docs/architecture/testing.md, README.md) —
места, которые легко пропустить:

  1. generator/README.md: список команд стоит под заголовком «Из корня
    репозитория» — меняется заголовок, а не только строки. В списке к тому же
    не хватает make inventory.
  2. Адрес make docs живёт в трёх местах: докстринг schema_doc.py, текст
    преамбулы, который модуль печатает внутрь docs/formats/clickstream-event.md,
    и сообщение об ошибке в tests/test_schema_doc.py. Адрес меняется — документ
    пересобирается; не пересоберёшь, покраснеет test_schema_doc.
  3. Адрес make inventory — такая же связка, но без сторожа. Живёт в
    inventory.py, в сообщении об ошибке tests/test_inventory.py и в
    generator/README.md. Сама опись текста команды не содержит, поэтому
    протухнет молча — в отличие от описания выгрузки, которое краснеет само.
  4. README.md упоминает переезжающие цели в трёх разных местах: список
    требований, раздел про опись мира, раздел про описание выгрузки.
  5. docs/specs/2026-08-01-generator.md называет хостовый uv для
    make test, make lint, make typecheck.
  6. AGENTS.md ссылается на make lint как на проверку Python — теперь
    это две разные цели с разным охватом.
  7. docs/architecture/testing.md, строка 32: «стенд нужен трём целям из
    семи» — целей станет восемь (пять корневых и три за дверью генератора).
  8. Четыре находки ruff в дагах (UP017 в обоих файлах и два файла под
    переформат) чинятся обязательно, иначе новый корневой lint красный с
    рождения. Находки эти следуют из выбранного списка правил: в наборе ruff
    по умолчанию UP017 нет, и без select проверка зелёная. Формат при этом
    склеит три руками перенесённые строки в двух пробниках — ожидаемо, ширину
    они не превышают.
  9. Находки ty в test_kafka.py не чинятся, а называются в теле PR:
    адрес записи едет через XCom словарём dict[str, str | int], а
    TopicPartition ждёт int. На исполнении безвредно — JSON возвращает
    целые, — а править аннотацию ради проверки, которую решение сознательно
    выключило, значит оставить читателю конструкцию без объяснимого повода.

Карта целей остаётся картой всего репозитория, а не одного корня. Цели
генератора из таблицы не уходят — восемь строк, и у каждой видно, откуда её
звать. Довод простой: карта и есть то место, куда за проверкой идут; выкинув
оттуда цели за второй дверью, мы прячем их и от человека, и от агента — он
их просто не найдёт. Заодно в таблице остаётся цена 71 с, на которую
ссылается правило про быстрый смоук.

Отсюда мелочь, о которой таблица обязана позаботиться: строк с именем
make lint теперь две, и различает их не имя, а дверь.

Карта проверок обязана сказать вслух и то, что схема иначе скроет: make lint есть за обеими дверями, с разным охватом. Человек в корне видит
зелёное и может решить, что зелёный весь репозиторий.

Цену корневого lint замерить: охват новый.

ADR работа не заводит — решение обратимо переименованием, а его законный дом
карта проверок. Нового термина в CONTEXT.md тоже нет: «дверь» здесь фигура
речи, а не понятие мира.

## Решение Развилка пройдена в грилинге 9 августа 2026 года. Из трёх вариантов тикета принят **B** с достроенной второй половиной. Запись правлена после двух холодных ревью — их находки учтены ниже. **Корень — про стенд, генератор — за своей дверью.** Цели `lint`, `typecheck`, `test`, `docs`, `inventory` уезжают из корня в новый `generator/Makefile` и сохраняют там короткие имена: дверь уже сказала, о ком речь, суффикс ей не нужен. Различие «стенд или генератор» несёт каталог, а не приставка в имени. Основание не только вкусовое: генератор и так отдельная сущность по всем внешним признакам — свой `pyproject.toml`, `uv.lock`, `Dockerfile`, README, — а спека генератора утверждает это словами: «генератор — отдельная и заменяемая сущность». Побочно этим снимается пункт 2 находки: `make test` в корне не переименовывается, а исчезает. Стенд как единую сущность спрашивают `config-test`, `smoke`, `check-clickhouse` и `check-services`. Тикет решается вычитанием — из корня уходят пять целей, приходит одна. **Корневой `lint` берёт под себя код стенда** — `dags/` и `infra/superset/`. Иначе «корень про стенд» оказалось бы тем же враньём в новой одежде: цель названа по стенду и не трогает ни одного его файла. Стоит это дёшево: `ruff` окружения не требует, венв в корне не нужен. Три условия, без которых эта цель не работает как задумано: - **Пути называются явно** — `dags` и `infra/superset`. `ruff`, запущенный из корня без путей, видит все 34 файла репозитория, включая генератор, и две двери перекрываются в первый же день. - **Конфиг в корне свой** — `ruff.toml`, потому что пакета в корне нет и настраивать `ruff` больше неоткуда. Но **список правил берётся тот же, что у генератора** — `E, F, I, UP, B`. Замер холодного ревью: этот список проходит по `dags/` и `infra/superset/` без единой претензии к идиомам Airflow, то есть расхождения правил сегодня нет. Разойдутся — тогда и разойдутся, с настоящим поводом. - **Версия `ruff` в корне закрепляется той же, что в локе генератора** (0.16.1). У генератора её держит лок, в корне лока нет, а форматтер между версиями меняет вывод — иначе корневая проверка однажды покраснеет сама, без единой правки в репозитории. Держит закрепление сам вызов: `uvx ruff@0.16.1`. Равенство двух версий не сторожит никто — обновится лок генератора, версию правят и здесь; сказать это вслух место в карте проверок. Проверено и рисков не несёт: иерархия конфигов `ruff` работает как задумано — корневой конфиг правила генератору не подменит. **Корневого `typecheck` не будет, и это записывается доводом.** Проверке типов мало прочитать файл: чтобы понять `from airflow.sdk import dag`, ей нужен установленный Airflow, а он живёт в образе, не на машине. Замер 9 августа 2026 года: `apache-airflow-task-sdk` тянет `apache-airflow-core` и дальше полный `apache-airflow==3.3.0` — **132 пакета** ради двух файлов пробников, и это вместе с `clickhouse-connect` и `confluent-kafka`, которые образ ставит сверх ядра. Документация Airflow обещает обратное («import only the classes you need, without installing the full Airflow core»), но метаданные пакета этого не подтверждают — проверено `uv pip compile`. Цена решения называется честно: две настоящие находки `ty` в `test_kafka.py` постоянного сторожа не получают. Вопрос вернётся на этапе 5, когда придут настоящие даги и цена окружения станет оправданной; условию возврата место в карте проверок рядом с доводом, а не в этом тикете — он после слияния закроется. **Цели корневого Makefile группируются по использованию**, менти сверху вниз: жизнь стенда (`up`, `down`, `clean`, `ps`, `logs`) — проверки стенда (`smoke`, `check-clickhouse`, `check-services`) — проверки без стенда (`config-test`, `lint`) — наполнение миром (`generate-batch`, `generate-live`). ## Отклонено - **`check-generator` по образцу `check-clickhouse`.** Приставка `check-` стоит на целях, спрашивающих работающий стенд; генератор так не спросить — его образ собирается с `--no-dev`, ни pytest, ни ruff, ни ty в него не едут, а тесты не копируются вовсе. Второй довод жёстче и записан в карте проверок: агрегат из трёх проверок — это «гонять всегда всё», и цена подтверждает (0,4 с + 0,5 с + 71 с), а `check-generator` только для pytest врал бы в другую сторону — линт и типы тоже проверки генератора. - **Второе окружение на машине ради `ty` для дагов** — 132 пакета, которые обязаны повторять версии образа и разъезжаются с ним молча. - **Алиас в корне, делегирующий генератору** (`test: make -C generator test`) — граница нарисована и тут же стёрта. Корень про генератор молчит, адрес называет README. - **Разные списки правил `ruff` у корня и генератора** — обосновывались бы расхождением, которого замер не показывает. - **Цель `help`** — дублирует README и разъезжается с ним молча. - **Окружение в корне (`pyproject.toml`, лок, `.venv`) ради удобства менти** — не отклонено, а вынесено за границы тикета; вопрос открыт. Разбор 9 августа 2026 года: конфиг `ruff` ищется вверх по дереву, поэтому редактору `ruff.toml` и `pyproject.toml` дают одни и те же правила — формат файла тут не решает ничего (проверено по докам Astral через Context7). Настоящую пользу — подсветку и переходы по `airflow.sdk` — даёт не файл, а установленный Airflow, и повторять в корневом локе версии образа сегодня не с чего: Python образа в репозитории нигде не записан, он приезжает с тегом `apache/airflow:3.3.0`. Вдобавок одно окружение на две нужды ставит самую дешёвую проверку за шлагбаум тяжёлого `uv sync`. Обратно решение стоит три строки: конфиг переезжает из `ruff.toml` в `[tool.ruff]`. ## Что делать при исполнении Помимо очевидного (`Makefile`, новый `generator/Makefile`, корневой конфиг `ruff`, таблица целей и цены в `docs/architecture/testing.md`, `README.md`) — места, которые легко пропустить: 1. **`generator/README.md`**: список команд стоит под заголовком «Из корня репозитория» — меняется заголовок, а не только строки. В списке к тому же не хватает `make inventory`. 2. **Адрес `make docs` живёт в трёх местах**: докстринг `schema_doc.py`, текст преамбулы, который модуль печатает внутрь `docs/formats/clickstream-event.md`, и сообщение об ошибке в `tests/test_schema_doc.py`. Адрес меняется — документ пересобирается; не пересоберёшь, покраснеет `test_schema_doc`. 3. **Адрес `make inventory` — такая же связка, но без сторожа.** Живёт в `inventory.py`, в сообщении об ошибке `tests/test_inventory.py` и в `generator/README.md`. Сама опись текста команды не содержит, поэтому протухнет молча — в отличие от описания выгрузки, которое краснеет само. 4. **`README.md` упоминает переезжающие цели в трёх разных местах**: список требований, раздел про опись мира, раздел про описание выгрузки. 5. **`docs/specs/2026-08-01-generator.md`** называет хостовый `uv` для `make test`, `make lint`, `make typecheck`. 6. **`AGENTS.md`** ссылается на `make lint` как на проверку Python — теперь это две разные цели с разным охватом. 7. **`docs/architecture/testing.md`, строка 32**: «стенд нужен трём целям из семи» — целей станет восемь (пять корневых и три за дверью генератора). 8. **Четыре находки `ruff` в дагах** (`UP017` в обоих файлах и два файла под переформат) чинятся обязательно, иначе новый корневой `lint` красный с рождения. Находки эти следуют из выбранного списка правил: в наборе `ruff` по умолчанию `UP017` нет, и без `select` проверка зелёная. Формат при этом склеит три руками перенесённые строки в двух пробниках — ожидаемо, ширину они не превышают. 9. **Находки `ty` в `test_kafka.py` не чинятся**, а называются в теле PR: адрес записи едет через XCom словарём `dict[str, str | int]`, а `TopicPartition` ждёт `int`. На исполнении безвредно — JSON возвращает целые, — а править аннотацию ради проверки, которую решение сознательно выключило, значит оставить читателю конструкцию без объяснимого повода. **Карта целей остаётся картой всего репозитория, а не одного корня.** Цели генератора из таблицы не уходят — восемь строк, и у каждой видно, откуда её звать. Довод простой: карта и есть то место, куда за проверкой идут; выкинув оттуда цели за второй дверью, мы прячем их и от человека, и от агента — он их просто не найдёт. Заодно в таблице остаётся цена 71 с, на которую ссылается правило про быстрый смоук. Отсюда мелочь, о которой таблица обязана позаботиться: строк с именем `make lint` теперь две, и различает их не имя, а дверь. Карта проверок обязана сказать вслух и то, что схема иначе скроет: **`make lint` есть за обеими дверями, с разным охватом.** Человек в корне видит зелёное и может решить, что зелёный весь репозиторий. Цену корневого `lint` замерить: охват новый. ADR работа не заводит — решение обратимо переименованием, а его законный дом карта проверок. Нового термина в `CONTEXT.md` тоже нет: «дверь» здесь фигура речи, а не понятие мира.
ddmitry added ready-for-agent and removed ready-for-human labels 2026-08-09 20:57:12 +03:00
ddmitry self-assigned this 2026-08-09 21:20:10 +03:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: ddmitry/clickstream-data-platform#65