Слой получил расчётную сущность: стенд режет визиты сам, а VisitID
генератора остаётся эталоном самопроверки.
Что внутри
dds.session_rep / _dist, двойник-донор dds.session_stage_rep / _dist
и публичный договор dds.session_v.
Нарезка двумя оконными проходами из dds.event_v: первое окно ставит шов
там, где пауза длиннее тридцати минут, второе считает нарастающий итог швов —
номер визита внутри дня куки. Границу суток держит разбиение окна, отдельной
проверки ей не нужно.
Объём прогона — от первой дыры в слое по последний прожитый день. Прожитый
день выводится из позиции мира и первого дня событий: события живой день от
прожитого не отличают, а собранная посреди дня сессия осталась бы обрезанной
навсегда.
Группа задач session в dds_transform рядом с заказом, зависимости по
данным между ними нет. Собирать нечего — группа пропускается, а не зеленеет
впустую.
Приёмка
Мир пересобран с нуля (make rebuild-storage), даг собрал все восемь дней
стартового мира:
расхождение с uniqExact(VisitID) по паре «кука × день» — ноль;
79 367 сессий, session_id уникальны, все 401 185 событий ровно в одной
сессии каждое;
ни одной паузы длиннее тридцати минут внутри сессии и ни одной пары соседних
визитов куки, разделённой меньшим промежутком;
повтор после DROP PARTITION ALL — те же session_id и то же содержимое
строк;
снесённая руками партиция 2026-06-04: следующий прогон взял хвост от неё,
дни до дыры не тронуты.
make lint, make smoke (21 проверка), make check-clickhouse (10), make check-services — зелёные.
Ревью
Две слепые линии: Кодекс по коду, свежий Опус по уместности. Одиннадцать
находок — девять закрыты правкой, две отклонены с доводом и отклонение принято
на перепроверке обеими линиями. Самая ценная находка: два окна дают две
независимые сортировки, и при равных метках времени шов и нарастающий итог
могли достаться разным строкам, разорвав сессию надвое. Порядок в окнах теперь
полный — по метке времени и event_id.
Известная граница
Позиция мира отвечает за «прожит», а не за «доехал». Пока нет сторожа хвоста
топика hits (#156), недожёванный день замёрзнет недособранным: окна
пересборки у сессий нет. Сказано вслух в docs/architecture/etl.md и в sql/dds/session_scope.sql.
Ветка отрезана от main до слияния #165. Пересечься они могут в docs/architecture/etl.md (раздел «Объём прогона», абзац про snapshot_date)
и в docs/architecture/storage.md. Кода это не касается: файлы ODS здесь не
трогались.
Closes #152
Слой получил расчётную сущность: стенд режет визиты сам, а `VisitID`
генератора остаётся эталоном самопроверки.
## Что внутри
- `dds.session_rep` / `_dist`, двойник-донор `dds.session_stage_rep` / `_dist`
и публичный договор `dds.session_v`.
- Нарезка двумя оконными проходами из `dds.event_v`: первое окно ставит шов
там, где пауза длиннее тридцати минут, второе считает нарастающий итог швов —
номер визита внутри дня куки. Границу суток держит разбиение окна, отдельной
проверки ей не нужно.
- Объём прогона — от первой дыры в слое по последний прожитый день. Прожитый
день выводится из позиции мира и первого дня событий: события живой день от
прожитого не отличают, а собранная посреди дня сессия осталась бы обрезанной
навсегда.
- Группа задач `session` в `dds_transform` рядом с заказом, зависимости по
данным между ними нет. Собирать нечего — группа пропускается, а не зеленеет
впустую.
## Приёмка
Мир пересобран с нуля (`make rebuild-storage`), даг собрал все восемь дней
стартового мира:
- расхождение с `uniqExact(VisitID)` по паре «кука × день» — **ноль**;
- 79 367 сессий, `session_id` уникальны, все 401 185 событий ровно в одной
сессии каждое;
- ни одной паузы длиннее тридцати минут внутри сессии и ни одной пары соседних
визитов куки, разделённой меньшим промежутком;
- повтор после `DROP PARTITION ALL` — те же `session_id` и то же содержимое
строк;
- снесённая руками партиция 2026-06-04: следующий прогон взял хвост от неё,
дни до дыры не тронуты.
`make lint`, `make smoke` (21 проверка), `make check-clickhouse` (10),
`make check-services` — зелёные.
## Ревью
Две слепые линии: Кодекс по коду, свежий Опус по уместности. Одиннадцать
находок — девять закрыты правкой, две отклонены с доводом и отклонение принято
на перепроверке обеими линиями. Самая ценная находка: два окна дают две
независимые сортировки, и при равных метках времени шов и нарастающий итог
могли достаться разным строкам, разорвав сессию надвое. Порядок в окнах теперь
полный — по метке времени и `event_id`.
## Известная граница
Позиция мира отвечает за «прожит», а не за «доехал». Пока нет сторожа хвоста
топика `hits` (#156), недожёванный день замёрзнет недособранным: окна
пересборки у сессий нет. Сказано вслух в `docs/architecture/etl.md` и в
`sql/dds/session_scope.sql`.
## Слияние рядом с #165
Ветка отрезана от `main` до слияния #165. Пересечься они могут в
`docs/architecture/etl.md` (раздел «Объём прогона», абзац про `snapshot_date`)
и в `docs/architecture/storage.md`. Кода это не касается: файлы ODS здесь не
трогались.
Зачем:
- Дать слою расчётную сущность, которой в потоке нет: стенд режет визиты сам,
а 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>
ddmitry
merged commit 650efacc3f into main2026-08-26 16:19:08 +03:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #152
Слой получил расчётную сущность: стенд режет визиты сам, а
VisitIDгенератора остаётся эталоном самопроверки.
Что внутри
dds.session_rep/_dist, двойник-донорdds.session_stage_rep/_distи публичный договор
dds.session_v.dds.event_v: первое окно ставит шовтам, где пауза длиннее тридцати минут, второе считает нарастающий итог швов —
номер визита внутри дня куки. Границу суток держит разбиение окна, отдельной
проверки ей не нужно.
день выводится из позиции мира и первого дня событий: события живой день от
прожитого не отличают, а собранная посреди дня сессия осталась бы обрезанной
навсегда.
sessionвdds_transformрядом с заказом, зависимости поданным между ними нет. Собирать нечего — группа пропускается, а не зеленеет
впустую.
Приёмка
Мир пересобран с нуля (
make rebuild-storage), даг собрал все восемь днейстартового мира:
uniqExact(VisitID)по паре «кука × день» — ноль;session_idуникальны, все 401 185 событий ровно в однойсессии каждое;
визитов куки, разделённой меньшим промежутком;
DROP PARTITION ALL— те жеsession_idи то же содержимоестрок;
дни до дыры не тронуты.
make lint,make smoke(21 проверка),make check-clickhouse(10),make check-services— зелёные.Ревью
Две слепые линии: Кодекс по коду, свежий Опус по уместности. Одиннадцать
находок — девять закрыты правкой, две отклонены с доводом и отклонение принято
на перепроверке обеими линиями. Самая ценная находка: два окна дают две
независимые сортировки, и при равных метках времени шов и нарастающий итог
могли достаться разным строкам, разорвав сессию надвое. Порядок в окнах теперь
полный — по метке времени и
event_id.Известная граница
Позиция мира отвечает за «прожит», а не за «доехал». Пока нет сторожа хвоста
топика
hits(#156), недожёванный день замёрзнет недособранным: окнапересборки у сессий нет. Сказано вслух в
docs/architecture/etl.mdи вsql/dds/session_scope.sql.Слияние рядом с #165
Ветка отрезана от
mainдо слияния #165. Пересечься они могут вdocs/architecture/etl.md(раздел «Объём прогона», абзац проsnapshot_date)и в
docs/architecture/storage.md. Кода это не касается: файлы ODS здесь нетрогались.