Commit Graph
155 Commits
Author SHA1 Message Date
ddadmin 8db1c58c12 feat(generator): добавлено опоздание заказов в слепках
- Зачем:
  - менти должен увидеть, как запоздавшая выгрузка меняет открытое окно, не подделывая аудит источника.
- Что:
  - заказам назначена задержка D, D+1 или D+2 последним броском подпотока ORDERS.
  - назначенный планом заказ приезжает сразу, а Woven передаёт эту гарантию именованным полем.
  - обновлены документы, проверки границ механики и эталонные хеши слепков.
- Проверка:
  - make lint, make typecheck и make test в generator: 436 тестов прошли.
  - make config-test: конфигурация прошла проверку.
  - world_live_day и следующий etl_pipeline перевели заказ 20260608-0001 из awaiting_order в match.
2026-08-28 17:30:55 -04:00
ddadminandClaude Fable 5 c28f724706 feat(generator): потеря и дубль purchase (B, D) и счетчики описи
- Зачем:
  - трекер стенда был полным, и правило «деньги — по бэкенду» держалось
    на слове; классы B и D делают недосчет и пересчет трекера
    наблюдаемыми (этап 6, #184).
- Что:
  - подпоток BEACONS: точечная потеря purchase (~3%) и сюжетный дубль
    (~2%) швом после _purchases, с гарантией моста идентичностей и
    условием допуска дубля по паузе до следующего визита;
  - опись считает пять классов по приоритету спеки; фильтр
    classes_vs_inventory расширен, нулевой класс читается нулем;
  - fate.md, seeds.md, dm.md и orders/README.md приведены к имени
    BEACONS и строгому правилу допуска.
- Проверка:
  - make lint, make typecheck, make test (433 passed) и make inventory
    из generator/ — хеши слепков не изменились;
  - на стенде: make smoke, make check-clickhouse, make check-services
    зеленые; в dq_summary classes_vs_inventory и sessions_vs_reference
    pass, витрина сверки показывает lost_event и duplicate_event.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 13:13:47 -04:00
ddadminandClaude Fable 5 6f18e9989c docs(generator): заморожена спека этапа 2, решения — в ADR 0015-0017
- Зачем:
  - спека разрослась до 1058 строк, а журнал решений в разделе 9 читался
    только целиком; агентам и людям нужен дешевый адресный заход к
    основаниям решений генератора.
- Что:
  - заведены ADR 0015 (пояс счетчика), 0016 (паспорт куки) и 0017 (номер
    заказа); четыре адресные ссылки на «раздел 9» перешиты на них.
  - раздел 9 пересобран в 11 тематических подразделов с датами и тикетами
    у каждого решения и закрыт пометкой о заморозке; устаревшие
    промежуточные замеры свернуты до указателей на актуальные.
  - строка статуса в шапке отмечает закрытие спеки как документа этапа 2.
- Проверка:
  - wc -l docs/specs/2026-08-01-generator.md (951, было 1058);
    rg -n 'раздел[а-яё]* 9|разделы 8 и 9' docs -g '*.md' — 18 попаданий,
    все классифицированы; разделы 1-8 нетронуты (сверка хешем).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 08:16:11 -04:00
ddadmin 74061aa499 Merge branch 'main' into 48-generator-guide 2026-08-28 06:06:19 -04:00
Dmitry Dementiev cd4f9c55f5 docs(compose): объяснение общей сборки сокращено
- Зачем:
  - ADR и комментарии повторяли устройство Compose и говорили о сборке безлично.
- Что:
  - в Compose оставлен один указатель на причину решения.
  - ADR хранит правило общей сборки и объясняет гонку Buildx.
- Проверка:
  - make config-test.
  - git diff --check.
2026-08-28 13:03:47 +03:00
ddadminandClaude Fable 5 0c466c082e docs(generator): путеводитель по генератору и живой проход make demo
- Зачем:
  - спека отвечает «почему», а жанра «как пройти устройство по коду»
    не было (#48); черновик в generator/README.md ждал выверки.
- Что:
  - новый набор docs/architecture/generator/: индекс с целевой картиной
    и mermaid-схемой плюс шесть поддокументов по темам тикета.
  - демо-модуль и цель make demo: канонический D0, все стадии цепочки
    на одном экране; тест-сторож проверяет стадии без прибитых чисел.
  - раздел «Как это работает» в generator/README.md сжат до ссылки
    на путеводитель, черновая врезка снята.
- Проверка:
  - из generator/: make lint, make typecheck, make test (430 passed),
    make demo; два слепых ревью и узкая перепроверка — находки закрыты.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 06:00:36 -04:00
Dmitry Dementiev 1f203c974d fix(compose): устранена гонка сборки общих образов
- Зачем:
  - make up иногда падал, когда несколько служб параллельно экспортировали один тег образа.
- Что:
  - сборка образов Airflow и Superset закреплена за службами инициализации.
  - зависимые службы только используют готовый образ, решение описано в ADR 0001.
- Проверка:
  - make config-test.
  - docker compose --progress plain build superset superset-init airflow-scheduler airflow-init.
  - два запуска make up прошли экспорт трёх уникальных тегов без image already exists.
2026-08-28 12:53:33 +03:00
ddmitry 5946175efa Merge pull request 'fix(grafana): исправлена загрузка плагина при сборке' (#177) from fix/grafana-plugin-download into main
Reviewed-on: #177
2026-08-28 12:42:27 +03:00
ddadmin cc836fc3c5 fix(superset): стабилизирована проверка рабочего контура
- Зачем:
  - холодный запуск второго приложения Superset давал ложный красный результат исправного стенда.
- Что:
  - тяжёлые `create_app()` и `superset test-db` заменены проверкой сохранённого подключения через REST API.
  - добавлены проверка схемы `dm`, безопасная диагностика и краткая запись приёмки с замерами.
- Проверка:
  - `make config-test`.
  - `make smoke`: 21/21 за 25 секунд.
  - три `make check-services` после перезапуска Superset: 7/7 за 71, 67 и 70 секунд; финальный прогон — 7/7 за 70 секунд.
  - контрольный неверный UUID: 5/1, красной стала проверка метаданных.
2026-08-28 12:38:54 +03:00
Dmitry Dementiev e422e6d1fa fix(grafana): исправлена загрузка плагина при сборке
- Зачем:
  - make up падал с HTTP 451 при загрузке плагина из каталога Grafana.
- Что:
  - закреплённый выпуск плагина загружается из официального GitHub Releases.
  - версия плагина вынесена в один аргумент сборки, причина выбора описана в справочнике мониторинга.
- Проверка:
  - docker build --progress=plain -t clickstream-grafana:local infra/grafana.
  - docker run --rm --entrypoint grafana clickstream-grafana:local cli --pluginsDir /usr/share/grafana/plugins plugins ls.
  - make config-test.
2026-08-28 12:31:48 +03:00
ddadminandClaude Fable 5 17995d4c5e fix(airflow): формулировки пульта переписаны живым русским
- Зачем:
  - владелец на ревью PR #175 отметил кальку в подсказках; читать их
    будет менти, и язык здесь — часть продукта.
- Что:
  - переписаны подсказка формы days, докстринги работников, строки
    журнала remember_played, абзац README и пункт в etl.md; смысл
    не менялся.
- Проверка:
  - make lint, make config-test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 05:14:51 -04:00
ddadminandClaude Fable 5 c2c4401a16 feat(airflow): пульт мира объясняет ось дней в форме и журнале
- Зачем:
  - оператор принимал служебную logical_date Airflow за дату мира (#111),
    а документацию читают реже, чем форму запуска.
- Что:
  - у параметра days появилась подсказка description_md, а в докстринги
    работников добавлена фраза: день определяет world_position, служебные
    поля Airflow к оси мира отношения не имеют.
  - remember_played пишет в журнал сыгранные дни и новую позицию.
  - README дополнен абзацем про служебные поля за «Advanced Options»;
    из etl.md сняты устаревшие стыки на закрытые #7 и #2.
- Проверка:
  - make lint, make config-test; ручной прогон world_next_day зелёный,
    позиция 9 -> 10, в журнале «сыграны дни 9–9, позиция теперь 10».

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 05:05:44 -04:00
ddadminandClaude Fable 5 f33d75113d feat(dm): добавлены учебные задания витрин и даг самопроверки
- Зачем:
  - менти строит витрины DM сам, от DDL по правилу зерна до задачи в
    конвейере; стенду нужны ТЗ с образцом и обратная связь по каждой
    витрине (#159, резолюция #135).
- Что:
  - docs/labs/: README и пять ТЗ — events_enriched_v, top_pages_daily,
    session_overview, dq_errors_daily, utm_effectiveness; каждое ТЗ
    называет урок, состав колонок, форму по зерну и самопроверку.
  - dags/homework_check.py: ручной даг, задача на витрину, красная без
    витрины или при расхождении; проверки — шесть файлов sql/dq/ с
    инвариантами против DDS и ODS, без золотых констант; в dq_summary
    не пишет.
  - docs: dm.md называет homework_check и снимает «Остается нарезке»,
    §7 и §10 мастер-спеки согласованы с лабами, dds/session.md указывает
    на ТЗ, AGENTS.md пополнен правилом имен docs/labs/.
- Проверка:
  - make lint; make smoke 21/21, make check-clickhouse 10/10,
    make check-services 7/7.
  - на свежем стенде все пять задач homework_check красные и называют
    ТЗ; черновик каждой витрины по тексту ТЗ зеленит свою задачу,
    после сноса — снова красная; строк от самопроверки в dq_summary нет.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 17:44:15 -04:00
ddadmin 54686651df fix(dq): устранено переполнение памяти проверок
- Зачем:
  - параллельный DQ выгружал деловые ключи в Python и исчерпывал 640 МиБ планировщика.
- Что:
  - четыре сверки агрегируют дневные итоги и ограниченную диагностику в ClickHouse.
  - коробка планировщика поднята до 1,5 ГиБ, локальные пределы задач удалены.
  - измерения и граница между SQL и Python записаны в документации.
- Проверка:
  - make lint, make config-test, make smoke, make check-clickhouse, make check-services.
  - полный etl_pipeline, красный и восстановительный прогоны dq_check.
2026-08-27 11:25:19 -04:00
ddadmin 26b2e5fea1 feat(dq): добавлен контроль качества конвейера
- Зачем:
  - конвейеру нужна публикуемая сводка текущего качества с красным завершением при нарушении договоров.
- Что:
  - добавлены DDL, публичное представление и пять сверок на естественном деловом зерне.
  - даг dq_check встроен после DM и публикует полные дневные партиции до именованных утверждений.
  - параллелизм DDS, DM и DQ приведён к измеренному лимиту памяти планировщика.
- Проверка:
  - make lint; make config-test; make rebuild-storage.
  - make smoke; make check-clickhouse; make check-services.
  - три семейства проверок покрашены искусственными расхождениями и восстановлены повторным полным прогоном.
2026-08-27 07:55:28 -04:00
ddadmin cec11edaf3 chore(repo): влиты изменения задачи 155
- Зачем:
  - ветка ETL должна учитывать новую витрину `purchase_vs_orders` из `main`.
- Что:
  - `origin/main` влит без переписывания истории опубликованного PR;
  - `dm_transform` теперь собирает третью витрину внутри общего конвейера.
- Проверка:
  - `make config-test`, `make lint`;
  - `generator`: `make lint`, `make typecheck`, `make test` — 429 тестов;
  - `make rebuild-storage`, `make smoke`, `make check-clickhouse`, `make check-services`;
  - импорт DAG без ошибок, `purchase_vs_orders` заполнена.
2026-08-27 12:23:02 +03:00
ddadmin 20071c565f feat(dm): добавлена сверка покупок с заказами
- Зачем:
  - показать расхождения трекера и бэкенда на зерне заказа
  - сохранить отложенные покупки наблюдаемыми до следующего слепка
- Что:
  - добавлены таблицы, представление и пересборка purchase_vs_orders
  - сумма покупки нормализована в Decimal на границе ODS
  - обновлены договоры и указатели на механику пересборки
- Проверка:
  - `make config-test`, `make lint`
  - `cd generator && make docs lint typecheck test`
  - `make rebuild-storage`, явные `dds_transform` и `dm_transform`
  - `make smoke`, `make check-clickhouse`, `make check-services`
2026-08-27 04:21:15 -04:00
ddadmin 61e662c19c refactor(etl): упрощена проверка готовности Kafka
- Зачем:
  - верхние смещения можно получить тем же административным клиентом без одноразового Consumer и фиктивной группы.
- Что:
  - чтение хвоста переведено на AdminClient.list_offsets с OffsetSpec.latest.
  - назначение system.one названо рядом с запросом, а документация и запись проверок сокращены и переставлены по смыслу.
- Проверка:
  - make config-test; make lint.
  - живые проверки готового и отсутствующего разделов Kafka; полный etl_pipeline.
2026-08-27 11:17:43 +03:00
ddadmin 12a5c109b2 feat(etl): добавлен дневной конвейер трансформаций
Зачем:
- Один запуск должен одинаково работать из жизненного цикла, вручную после разгона и повторно после отказа.

Что:
- Добавлена последовательная сцепка DDS и DM с ожиданием каждого слоя.
- DDS дожидается смещений Kafka и очереди доставки ClickHouse за общий срок.
- ETL встроен в создание мира и живой день; документация приведена к новому графу.

Проверка:
- make config-test; make lint.
- make smoke: 21/21; make check-clickhouse: 10/10; make check-services: 7/7.
- make rebuild-storage, живой и пакетный дни, искусственный отказ и ручное восстановление ETL.
2026-08-27 02:43:29 +03:00
ddadmin da0477f0f1 feat(dm): добавлены витрины выручки и трафика
Зачем:
- Показать два ритма пересборки агрегатов на готовых витринах DM.

Что:
- Добавлены физические модели и публичные договоры revenue_daily и daily_traffic.
- Добавлен dm_transform с оконной заменой выручки и полным пересчетом трафика.
- Отрицательный опыт локального соединения через публичные _v зафиксирован; выбран явный GLOBAL LEFT JOIN.
- Замены партиций сериализованы после подтвержденного OOM при трех одновременных задачах.
- Обновлены архитектурные документы и мастер-спека.

Проверка:
- make lint, make config-test, make smoke, make check-clickhouse, make check-services.
- Чистая сборка world_recreate, dds_transform и dm_transform; меры сверены с прямыми агрегатами.
2026-08-26 13:55:26 -04:00
ddadmin 39ff0b5bb4 feat(dds): добавлена карта идентичностей
- Зачем:
  - реализованы требования issue #153 к мосту между кукой и пользователем.
- Что:
  - добавлены физическая карта, точное представление и полный пересчёт через GLOBAL JOIN.
  - задача identity_map поставлена после сборки заказов в dds_transform.
  - устройство и живые проверки карты записаны в документации хранилища.
- Проверка:
  - make lint, make smoke, make check-clickhouse, make check-services.
  - три запуска dds_transform: 4770 физических строк и 1590 уникальных пар в _v.
2026-08-26 12:30:40 -04:00
ddadmin a9cead2974 docs(orders): документация перестроена вокруг текущей модели
- Зачем:
  - описание вело нового читателя через историю исправления вместо действующего
    контракта слоёв.
- Что:
  - прямо описаны версия заказа, границы пакетного приёма и расчёт окна DDS.
  - ответственность ODS, DDS и конвейера разделена без ссылок на прежние
    ошибки как на основной довод.
  - исторический вывод исследования помечен до устаревшего абзаца, а ссылки
    ведут к отдельным решениям и контрактам.
- Проверка:
  - make lint.
  - make config-test.
2026-08-26 18:47:22 +03:00
ddadminandClaude Opus 5 a82c75705d feat(ods): версией заказа стала дата слепка, окно DDS — из данных
- Зачем:
  - ярлык snapshot_date выжившей строки доставался жребием, а объём
    пересборки DDS держался на константе окна с двумя несверяемыми копиями
    (ADR 0014, развилка #163).
- Что:
  - ods.order_rep переведена на ReplacingMergeTree(snapshot_date): выживает
    строка позднейшего слепка, ярлык стал правдивым.
  - order_scope.sql выводит окно из дней последнего слепка; ORDER_WINDOW_DAYS
    и параметр window_days сняты со стенда, мёртвая защита краем источника
    убрана.
  - документы и комментарии SQL приведены к ADR 0014: роль ODS, условие
    «одна дата — один слепок», объём прогона и слепые пятна конвейера.
- Проверка:
  - make lint; make rebuild-storage, затем make smoke, make check-clickhouse,
    make check-services — зелёные.
  - после двух слепков snapshot_date всех 1917 строк ods.order_v равен
    последнему слепку заказа, расхождений ноль; деловые поля построчно
    совпали с эталоном argMax по updated_at из сырья.
  - dds_transform без K: первый прогон 06-01…06-07, после нового дня мира
    06-02…06-08, повтор прогона содержимого не изменил.

Closes #165

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 17:28:14 +03:00
ddadminandClaude Opus 5 176cf5520d feat(dds): добавлена модель сессии и нарезка визитов окнами
Зачем:
- Дать слою расчётную сущность, которой в потоке нет: стенд режет визиты сам,
  а VisitID генератора остаётся эталоном самопроверки.
- Отделить прожитый день от живого — иначе визит, начатый в 23:50, замёрз бы
  обрезанным навсегда: пересобирать замёрзший день слой не станет.

Что:
- Добавлены dds.session_rep/_dist, двойник-донор dds.session_stage_rep/_dist и
  публичный договор dds.session_v.
- Нарезка стоит на двух окнах: первое ставит шов там, где пауза длиннее
  тридцати минут, второе считает нарастающий итог швов — номер визита. Границу
  суток держит разбиение окна, отдельной проверки ей не нужно.
- Порядок в окнах полный, по метке времени и event_id: сортировок две, и при
  равных метках они разошлись бы, разорвав сессию надвое.
- Объём прогона считается от первой дыры в слое по последний прожитый день;
  прожитый день выводится из позиции мира и первого дня событий. Собирать
  нечего — группа задач пропускается, а не зеленеет впустую.
- В dds_transform появилась группа session рядом с заказом; зависимости по
  данным между ними нет.
- Потолок max_active_tasks: размноженная замена без него выносит планировщика
  за отведённые ему 640 МиБ.
- parallel_distributed_insert_select у сессий не назначается вслух — ключ
  шардирования у источника и цели один по контракту ко-локации.
- Записано, что позиция отвечает за «прожит», а не за «доехал»: сторож хвоста
  потока приезжает отдельным тикетом.

Проверка:
- make lint
- make smoke (21 проверка), make check-clickhouse (10), make check-services
- Стартовый мир, пересобранный с нуля: 79367 сессий за восемь дней;
  расхождение с uniqExact(VisitID) по паре «кука × день» — ноль; все 401185
  событий ровно в одной сессии; session_id уникальны.
- Ни одной паузы длиннее тридцати минут внутри сессии и ни одной пары соседних
  визитов куки, разделённой меньшим промежутком.
- Повтор после DROP PARTITION ALL: те же session_id и то же содержимое строк.
- Снесённая руками партиция 2026-06-04: следующий прогон взял хвост от неё,
  дни до дыры не тронуты.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 07:56:44 -04:00
ddadminandClaude Fable 5 c361c36e3d docs(adr): версия заказа в ODS пересмотрена на дату слепка
- Зачем:
  - лотерея ярлыков доставки при ничьей по updated_at делала слой
    недетерминированным и держала окно K двумя копиями без сверки (#163).
- Что:
  - добавлен ADR 0014: версия ods.order — snapshot_date, с ответом доводу
    ADR 0010, границами допущения и веером отклонённых вариантов.
  - в ADR 0010 помечен пересмотр колонки версии.
- Проверка:
  - реализация и замеры — тикет #165; решение кодом пока не применено.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 06:38:46 -04:00
ddadminandClaude Opus 5 1e8b83ffbb feat(dds): добавлена модель заказа и пересборка окна заменой партиций
Зачем:
- Дать слою первую физическую сущность и показать идемпотентность, устроенную
  иначе, чем в приёме: заменой партиции, а не колонкой версии.
- Родить механику дневной пересборки на кластере — образец для сессий и витрин.

Что:
- Добавлены dds.order_rep/_dist, двойник-донор dds.order_stage_rep/_dist и
  публичный договор dds.order_v с разбором позиций в три массива.
- Добавлены запросы объёма прогона, сборки в двойник и замены партиции по дню.
- Добавлен даг dds_transform: группа задач order, замена — размноженной задачей.
- Окно изменяемости K пришло на сторону стенда якорем compose; владелец числа
  остаётся у генератора.
- Объём считается от позднейшего дня заказа и первого недостающего дня: ярлыки
  доставки ODS для этого непригодны, а максимум собранного дня прячет дыры.
- Записано, чего конвейер о себе не знает, и адресовано контуру DQ.

Проверка:
- make lint
- make smoke, make check-clickhouse, make check-services
- Прогон по стартовому миру: 1917 заказов, счёт равен ods.order_v, каждый заказ
  на шарде своего cityHash64(order_id), сумма позиций равна items_total.
- Повтор без нового слепка: содержимое то же, _load_id новый; после слепка
  пересобрано окно, день за окном не тронут.
- Снесённая руками партиция 2026-06-01 восстановлена побайтово.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 05:20:39 -04:00
ddadmin ae5bd31dbd docs(dds): уточнён публичный контракт события
- Зачем:
  - Закрепить реалистичную границу доступа BI и убрать двусмысленность для неизвестных кодов.
- Что:
  - Пояснены доступ к ODS, пояс счётчика и порядок DDL.
  - Проверка равенства строк отделена от размера конкретной загрузки.
- Проверка:
  - `git diff --check`.
  - `make config-test` не стартовал: Snap требует работающий `snapd.apparmor`.
2026-08-25 17:53:22 -04:00
ddadmin 9ea361d199 feat(dds): добавлен публичный контракт события
Зачем:
- Показать слой DDS как договор данных, которому не нужна физическая копия.
- Сохранить простой учебный стенд без отдельного маршрута ради узких прав.

Что:
- Добавлено кластерное представление dds.event_v с явными 44 колонками.
- Роли bi_reader разрешено чтение ODS, DDS и DM при договоре чтения через _v.
- Согласованы мастер-спека, ADR, справочники архитектуры и живые тикеты этапа.
- Зафиксировано исследование поведения DEFINER поверх Distributed.

Проверка:
- make config-test
- make smoke
- make check-clickhouse
- Приёмочные запросы: равенство ODS/DDS, состав колонок, коды устройств и права bi.
2026-08-25 17:13:35 -04:00
ddadminandClaude Fable 5 f45ad53b7f docs(dq): classes_vs_inventory названа технической проверкой
- Зачем:
  - сверка с описью подглядывает внутрь генератора: у настоящего магазина
    такого оракула нет, и выдавать её за учебный урок DQ нельзя (развилка
    из комментария к #157).
- Что:
  - в dm.md проверка счётчиков классов помечена технической, её обещание
    сужено честно: до витрин доехал рождённый мир; верно ли мир рождён,
    проверка не видит — опись считает тот же генератор.
  - в §8 мастер-спеки читатель счётчиков «самопроверка лабы сверки»
    заменён на техническую проверку classes_vs_inventory звена DQ.
  - словарь: короткий термин «Техническая проверка» в CONTEXT.md — только
    язык, решение живёт в dm.md; та же формулировка читателя в inventory.md.
- Проверка:
  - grep -rn "лабы сверки" docs/ — упоминаний не осталось.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 12:47:48 -04:00
ddadmin 1267b45f47 feat(generator): добавлены счётчики классов заказов
Зачем:
- дать описи контрольные числа для закрытых дней заказного окна;
- зафиксировать словарь наблюдаемых классов без изменения самого мира.

Что:
- посчитаны match, cancelled и amount_delta с приоритетом отмены;
- счётчики добавлены только к дням с закрытым окном;
- опись, тесты и документация приведены к новому формату.

Проверка:
- make lint;
- make typecheck;
- make test — 429 passed;
- uv run pytest tests/test_inventory.py -q — 3 passed после ревью.
2026-08-25 11:35:31 -04:00
ddadminandClaude Fable 5 2f9a26eb0e docs(dm): вычитан слой витрин вторым горячим ревью
- Зачем:
  - после переписывания ритма пересборки в тексте остались швы прежних
    формулировок и один разрыв с докой конвейера.
- Что:
  - довод против дневных партиций daily_traffic заменён верным: партиция —
    единица замены, а витрина заменяется только целиком (число строк тут
    ни при чём, иначе довод бил бы и по dq_summary).
  - в etl.md к механике REPLACE PARTITION добавлена вторая идемпотентность
    конвейера — полная перезапись в ReplacingMergeTree.
  - правило ритмов говорит про день, а не партицию; поправлены переносы
    строк и обороты.
- Проверка:
  - make config-test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 06:37:09 -04:00
ddadminandClaude Fable 5 92d834761c docs(dm): ритм пересборки витрин выведен из подвижности источника
- Зачем:
  - обсуждение горячего ревью показало: «окно K для всех» — ритм заказов,
    натянутый на слой, а замерзание daily_traffic обесценивало витрину.
- Что:
  - раздел «Объём пересборки» заменён «Ритмом пересборки»: три ритма —
    хвост / окно K / целиком; daily_traffic наследует у карты полный
    пересчёт в ReplacingMergeTree, дневные партиции ей не положены.
  - в отклонённые добавлены замерзание за окном K и инкремент по
    first_matched_at; инкремент стал идеей лабы повышенной сложности #149.
- Проверка:
  - make config-test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 06:33:10 -04:00
ddadminandClaude Fable 5 99496971e2 docs(dm): вычитана дока слоя витрин
- Зачем:
  - горячее ревью развилки #135 нашло два незакрытых решения: объём
    пересборки витрин и судьба менти-витрины после постройки.
- Что:
  - добавлен раздел «Объём пересборки»: одно окно K для всех витрин,
    замерзание daily_traffic за окном названо решением с объяснением.
  - в ТЗ менти добавлен финальный пункт — встроить витрину в dm_transform.
  - поправлены мелочи: greenplum-стенд больше не зовётся предшественником,
    добавлены ссылки на спеку и карту идентичностей.
- Проверка:
  - make config-test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 04:57:17 -04:00
ddadminandClaude Fable 5 70a9aeddb7 docs(dm): спроектирован слой витрин DM
- Зачем:
  - развилка #135 карты #127 решена: форма и состав витрин DM,
    контур DQ этапа 4; резолюция переносится в доки architecture.
- Что:
  - создана docs/architecture/dm.md: форма по зерну, дележ витрин
    между стендом и заданиями менти, dq_summary с REPLACE PARTITION,
    звено DQ конвейера и даг самопроверки домашек.
  - ссылки на #135 в etl.md и dds/README.md заменены на доку слоя.
- Проверка:
  - make config-test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 04:40:30 -04:00
ddadminandClaude Fable 5 d1aad3b143 docs(etl): вычитан дневной конвейер
Зачем: горячее ревью доки перед слиянием PR #146.

Что: «единственный на стенде» больше не читается как «единственный даг
стенда»; в пункте про живой день причина порядка триггера названа один раз
и по делу; конвейер дёргает работник живого дня, а не работники; в
ретро-пометке ADR 0009 расставлены кто кого дёргает.

Проверка: перечитка диффа.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 03:25:08 -04:00
ddadminandClaude Fable 5 ebe3de4ae8 docs(etl): спроектирован дневной конвейер трансформаций
Зачем: развилка #134 карты #127 — чем и когда гоняются трансформации DDS
и витрины-таблицы, пока спека числила etl_pipeline за этапом 5.

Что: дока docs/architecture/etl.md — даг etl_pipeline рождается этапом 4:
дёргает dds_transform и dm_transform последовательно (DQ — будущее звено);
живой день зовёт его с ожиданием после установки позиции, после разгона
пачкой менти запускает рукой, world_initialize — последним шагом; параметров
нет, объём выводится из world_position и состояния слоёв; первый шаг —
ожидание хвоста hits; механика REPLACE PARTITION — этап 4, этапу 5 —
партиционная переобработка. Указатели в доках заказа, сессии, README слоя
и ретро-пометки в ADR 0008/0009 переведены на новую доку.

Проверка: вычитка; резолюция и доводы — в тикете #134.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 03:22:35 -04:00
ddadmin f0c4b4c627 docs(dds): зафиксирована физическая модель карты идентичностей
- Зачем:
  - согласованная модель нужна для пакетной реализации DDS и понятного публичного интерфейса слоя.
- Что:
  - описаны физическая карта идентичностей, полный пересчёт и отказ от first_matched_at.
  - унифицирован публичный контракт _v для событий, заказов, сессий и карты.
  - синхронизированы мастер-спека, имена объектов и граница доступа.
- Проверка:
  - git diff --cached --check.
2026-08-24 15:52:17 -04:00
ddadminandClaude Fable 5 7fc12fb8c9 docs(dds): вычитан контракт события
- Зачем:
  - горячее ревью резолюции #132 нашло шероховатости, мешающие читателю.
- Что:
  - срезан дубль про event_date из «Языка модели» — факт живёт в «Форме»,
    расхождений имён осталось два.
  - выровнены префиксы dm. в «Читателях», распутана фраза про два слоя
    DQ-сверки, ссылка на спеку — в домашнем стиле.
- Проверка:
  - вычитка.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 14:09:15 -04:00
ddadminandClaude Fable 5 92ed3011e6 docs(dds): спроектирован контракт dds.event_v — язык модели поверх ODS
- Зачем:
  - развилка #132 карты #127: витринам DM и сборке сессий нужен контракт
    события на языке бизнес-модели, первый пример правила «слой — это
    контракт, а не обязательно копия данных».
- Что:
  - создан docs/architecture/dds/event.md: представление над ods.event_v,
    имена модели (event_id, event_time в поясе счётчика, event_date
    переименованием), расшифровка device_category, скрыты VisitID, Sign,
    ecommerce и служебные колонки.
  - в README карта модели ведёт на event.md, развилка убрана из открытых
    решений; session.md ссылается на резолюцию судьбы VisitID.
- Проверка:
  - вычитка; относительные ссылки в docs/architecture/dds/ ведут на
    существующие файлы.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 14:04:51 -04:00
ddadminandClaude Fable 5 4d43b7badd docs(dds): дописаны следствия ключей сессии — локальность и судьба VisitID
Зачем: две находки горячего ревью #131 уровня решения, принятые владельцем.

Что: в «Движок и наполнение» — следствие совпадения ключа шардирования с
событиями: сессионизация локальна по природе, капкан смены ключа у сессий
не стреляет; в «Сверку с эталоном» — зацепка для развилки #132: VisitID
нужен сверке, но не сборке, его дом решает контракт dds.event_v.

Проверка: вычитка; утверждение о локальности сверено с разделом
«Раскладка по шардам» доки хранилища.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 13:40:45 -04:00
ddadminandClaude Fable 5 9237870ab5 docs(dds): вычитана модель сессии
Зачем: горячее ревью резолюции #131 перед мержем PR #142.

Что: поправлена фраза про торговые события (они держат сессию, а не
«рвут»), метка времени названа явно (UTCEventTime), убрано задвоение
про «цели» между составом строки и списком расхождений, у счётной
сверки честно назван предел — взаимная компенсация ошибок внутри
куки за день счёту не видна.

Проверка: повторная вычитка; утверждения сверены с CONTEXT.md, спекой
(разделы 1, 6, 7) и докой хранилища.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 13:37:14 -04:00
ddadminandClaude Fable 5 6f2692737b docs(dds): спроектирована модель сессии — нарезка стендом, эталон VisitID
Зачем: развилка #131 карты #127 — зерно и правила сборки dds.session;
резолюция переносится в доки слоя тем же PR.

Что: дока docs/architecture/dds/session.md — зерно «один визит», нарезка
по правилу визита самим стендом (стенд в роли сессионизатора), session_id
как детерминированный хеш, состав строки по образцу визита Метрики без
денег и целей, MergeTree с заменой дневной партиции, сборка одним дневным
батчем после слепка, счётная DQ-сверка с VisitID (кука × день); в README
слоя сессия переведена из открытых решений в карту модели.

Проверка: вычитка доки; ссылки на разделы спеки и соседние доки сверены
с текстом.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 13:32:49 -04:00
ddadminandClaude Fable 5 40de2e5c5f docs(dds): вычитаны модель заказа и карта слоя
- Зачем:
  - горячее ревью после написания: неточности формулировок и один пропуск
    в списке читаемых колонок.
- Что:
  - уточнено, что дом набора выбран развилкой #130, а не «первой развилкой
    карты» (первыми шли research-тикеты);
  - сверке добавлен order_date в перечень читаемых колонок (спека, §7:
    колонка order_day);
  - мастер-спека слинкована при первом упоминании; пояснена роль резолюции
    #128 в «Связанных решениях».
- Проверка:
  - только документы; ссылки сверены с деревом docs/.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 12:06:54 -04:00
ddadminandClaude Fable 5 7972847601 docs(dds): спроектирована модель заказа в DDS и заведён набор доков слоя
- Зачем:
  - развилка #130 карты #127: заказу нужен объект в DDS — зерно, состав,
    движок и судьба служебных колонок; резолюции этапа 4 нужен дом в git.
- Что:
  - создан набор docs/architecture/dds/ по ADR 0011: README с картой
    модели и правилами слоя, order.md с моделью заказа — зерно «заказ в
    текущем состоянии», позиции массивами, MergeTree с заменой партиций,
    свои _load_id/_load_ts вместо ярлыков ODS (закрывает наследство #85);
  - указатели на модель добавлены в orders/README.md, orders/ingestion.md
    и storage.md.
- Проверка:
  - только документы; относительные ссылки сверены с деревом docs/.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 12:03:26 -04:00
ddmitry 1adacc6d7c Merge pull request 'docs(research): соединение Distributed-таблиц на кластере' (#140) from research/distributed-join into main 2026-08-22 11:42:09 +03:00
ddmitry d359882e1d Merge pull request 'docs(research): проталкивание условий сквозь представления над FINAL' (#139) from research/view-predicate-pushdown into main 2026-08-22 11:42:05 +03:00
ddadminandClaude Opus 5 45360b6bcf docs(ods): вычитаны комментарии и документация починки раскладки
- Зачем:
  - правки #137 дважды рассказывали одно и то же: механика капкана жила и в
    storage.md, и у вставок, а цифры замеров — и в прозе, и в леджере;
    у читателя это спрашивает больше внимания, чем даёт.
- Что:
  - комментарии у вставок order_parse.sql сжаты до довода с указателем на
    storage.md; из капкана в storage.md цифры ушли в «Что проверено»;
    в ingestion.md замеры перенесены из прозы в свой раздел «Что проверено».
- Проверка:
  - рендер order_parse.sql по-прежнему делится ровно на два запроса
    (из комментария убрана точка с запятой, по которой оператор делит файл).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 04:35:41 -04:00
ddadminandClaude Opus 5 94a1ffeee2 docs(ods): описана семантика snapshot_date после схлопывания версий
- Зачем:
  - проверка #137 показала: у заказа, не менявшегося несколько дней, версию
    выбирает только updated_at, и какая из одинаковых строк переживёт
    схлопывание — не обещано; snapshot_date выжившей строки означал не то,
    что обещала документация (у 86 заказов стартового мира выжил серединный
    день наблюдения).
- Что:
  - в docs/architecture/orders/ingestion.md записано: snapshot_date, _load_id
    и _load_ts выжившей строки — координаты одного из наблюдений версии, не
    обязательно последнего; допущение «уточнение поднимает updated_at»
    названо допущением с границей применимости.
  - та же оговорка — в комментарии DDL ods.order_rep.
- Проверка:
  - замеры на живом стенде: во всех 3034 парах строк с равным updated_at
    деловые поля совпали побайтово; монотонность updated_at по слепкам —
    без нарушений; ods.order_v сошёлся с эталоном argMax из сырья построчно.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 04:28:51 -04:00
ddadminandClaude Opus 5 8c76a7a0d8 fix(ods): заказы разложены по своему ключу шардирования
- Зачем:
  - заводское parallel_distributed_insert_select = 2 исполняло вставку из
    Distributed в Distributed локально на каждом шарде, минуя ключ цели:
    1189 из 1662 заказов задвоились на обоих шардах, а ReplacingMergeTree
    через границу шарда дубли не схлопывает.
- Что:
  - в обе вставки sql/ods/order_parse.sql добавлено явное
    parallel_distributed_insert_select = 0 с доводом комментарием.
  - в docs/architecture/storage.md описан капкан «INSERT из Distributed в
    Distributed при несовпадающих ключах» и записана проверка (#137).
- Проверка:
  - межшардовые дубли по ods.order_rep дают 0 (было 1189), каждый шард
    держит только свои ключи; uniqExact(order_id) не изменился.
  - после прожитого дага world_next_day новый слепок принят, дублей
    по-прежнему 0.
  - make smoke, make check-clickhouse.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 04:02:52 -04:00
ddadminandClaude Fable 5 f218795472 docs(research): изучено соединение Distributed-таблиц на кластере
Зачем: тикет #129 (карта #127) требовал проверить, где выполняется JOIN
двух Distributed-таблиц, что даёт GLOBAL и как влияет
distributed_product_mode, — от этого зависят сборка dds.identity_map и
витрина сверки purchase_vs_orders_v этапа 4.

Что: заметка docs/research/2026-08-22-distributed-join.md. Ключевое:
GLOBAL рассылает правую часть с инициатора на шарды; режим local молча
даёт неверный ответ без настоящей ко-локации; подзапрос слева переносит
соединение на инициатор; FULL OUTER с голой левой таблицей задваивает
непарные строки правой части. Попутная находка: ко-локация заказов по
cityHash64(order_id) сломана заводским parallel_distributed_insert_select=2
— починка отдельным тикетом.

Проверка: читающие запросы на живом стенде 26.3.17.56 (log_comment
r129-* в system.query_log обеих нод) и документация ClickHouse через
MCP Context7; стенд не менялся, main не тронут.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 03:39:26 -04:00