feat(generator): глагол next-day — следующий модельный день от слепка
- Зачем:
- режим кормления стенда порциями: менти триггерит «следующий день»,
видит полный цикл DWH за один шаг (задача 13, вариант 2 — генерация
от слепка T_end).
- Что:
- новый ограниченный режим next-day: восстановление мира из state,
генерация ровно [T_end, T_end+24h), публикация данные -> state ->
манифест (манифест — точка фиксации, автоотката нет).
- операция next-day в DAG generator_control: своя предпроверка границы
вместо clean-guard, идемпотентность через параметр expected_t_end.
- цепочка границ — накопительное поле boundaries в манифесте, старый
формат читается как [T0, T_end]; импорт не изменён.
- новая проверка цепочки (make generated-history-chain-check): непарные
счётчики и однородность по каждой границе, явный статус нулевого
стыка, хвост за границей по всем четырём топикам, литералы в UTC
с микросекундами.
- документация OPERATIONS.md: глагол, предпроверка, восстановление
после сбоя, ограничение retention; в задаче 13 — решения двух слепых
ревью постановки и кода с аргументами отклонений.
- Проверка:
- make test: 204 теста генератора + 31 контракт корня, зелёные.
- make generated-history-chain-check: зелёный, 2 внутренние границы,
непарные счётчики нулевые; учебный цикл: DM 322 -> 10026 -> 19196
за два next-day подряд.
- make generated-history-runtime-check (регрессия задачи 20): зелёный.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+56
-8
@@ -1,4 +1,4 @@
|
||||
Status: ready-for-agent
|
||||
Status: done
|
||||
|
||||
# Глагол next-day: собрать следующий модельный день
|
||||
|
||||
@@ -111,26 +111,26 @@ Status: ready-for-agent
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] Глагол `next-day` в `generator_control`: батч ровно за
|
||||
- [x] Глагол `next-day` в `generator_control`: батч ровно за
|
||||
`[T_end, T_end + 24h)` от `T_end` манифеста; после прогона манифест
|
||||
содержит новую границу в `boundaries` и новый `T_end`.
|
||||
- [ ] Предпроверка границы: на пустом стенде (нет манифеста) next-day
|
||||
- [x] Предпроверка границы: на пустом стенде (нет манифеста) next-day
|
||||
громко падает; при работающем live-генераторе — громко падает;
|
||||
`clean`-guard и существующие глаголы `backfill|import|check` не изменены.
|
||||
- [ ] Идемпотентность: запуск с `expected_t_end`, не равным `T_end`
|
||||
- [x] Идемпотентность: запуск с `expected_t_end`, не равным `T_end`
|
||||
манифеста, — громкий отказ с обеими границами в тексте; повторный запуск
|
||||
того же дня после успеха — тот же отказ, дублей и второго мира нет.
|
||||
- [ ] Проверка цепочки (новая make-цель): проходит по всем границам из
|
||||
- [x] Проверка цепочки (новая make-цель): проходит по всем границам из
|
||||
`boundaries`; после N прогонов next-day в цепочке N новых границ;
|
||||
непарные счётчики нулевые, per-event поля визитов через каждую границу
|
||||
однородны (браузер, referer, utm).
|
||||
- [ ] Учебный цикл целиком и повторяемо: next-day -> прогон `etl_pipeline`
|
||||
- [x] Учебный цикл целиком и повторяемо: next-day -> прогон `etl_pipeline`
|
||||
-> в DM-витринах появились строки ровно за новый день (счётчики до/после,
|
||||
прирост только в диапазоне нового дня); проверено на двух next-day подряд.
|
||||
- [ ] Регрессий нет: тесты генератора и контракты корня зелёные
|
||||
- [x] Регрессий нет: тесты генератора и контракты корня зелёные
|
||||
(`make test`), сценарий `make generated-history-runtime-check`
|
||||
задачи 20 остаётся зелёным.
|
||||
- [ ] Документация: OPERATIONS.md — глагол, предпроверка, поведение при
|
||||
- [x] Документация: OPERATIONS.md — глагол, предпроверка, поведение при
|
||||
сбое до фиксации манифеста (восстановление переимпортом артефакта).
|
||||
|
||||
## Границы (что не трогать)
|
||||
@@ -158,3 +158,51 @@ state и закрыл тихие fallback'и. Прежняя редакция э
|
||||
«Доливка стартовой истории кусочком от слепка». Проверенные 2026-07-07
|
||||
факты (import «всё или ничего», донор задачи 09) подтверждены обоими ревью
|
||||
2026-07-12 по коду ветки.
|
||||
|
||||
## Решения по слепым ревью реализации (2026-07-12)
|
||||
|
||||
### Полная перечитка Kafka и конечный срок хранения — отклонено в задаче 13
|
||||
|
||||
Накопительные `visits` и `users` требуют точного объединения идентификаторов,
|
||||
а текущая контрольная сумма — SHA-256 последовательности событий. Из одних
|
||||
итоговых чисел и готовой контрольной суммы нельзя точно добавить новый день. Для
|
||||
инкрементального расчёта пришлось бы хранить множества идентификаторов и новое
|
||||
состояние hash в manifest. Это изменило бы формат артефакта сверх разрешённого
|
||||
поля `boundaries` и нарушило бы решение 6.
|
||||
|
||||
Поэтому в задаче 13 остаётся точная пересборка по доступной истории Kafka.
|
||||
Её проверяет
|
||||
`test_next_day_publishes_24h_then_state_then_cumulative_manifest`: два дня,
|
||||
точные накопительные счётчики и суммы. Риск принят только для ручного учебного
|
||||
цикла. Ограничение по времени, памяти и сроку хранения записано в OPERATIONS.md.
|
||||
Задача про расписание из решения 8 до включения обязана выбрать бессрочное
|
||||
хранение data-топиков или новый согласованный формат накопительного состояния.
|
||||
|
||||
### Device/geo min/max timestamps после пересборки — отклонено
|
||||
|
||||
Эти два диапазона являются диагностическими полями статистики топика и не
|
||||
участвуют в `compare_clickhouse_stats_to_manifest`, проверке цепочки или
|
||||
критериях приёмки. Контракт задачи требует накопительные строки и контрольные
|
||||
суммы; они пересчитываются точно и проверяются тестом двух `next-day`.
|
||||
Выравнивание
|
||||
device/geo min/max с потактовым backfill потребовало бы сохранять связь каждой
|
||||
повторной строки с исходным browser-событием, которой в этих сообщениях нет.
|
||||
Менять формат ради неиспользуемых диагностических полей в задаче 13 не следует.
|
||||
|
||||
### Нулевой стык — допустим с явным статусом
|
||||
|
||||
Диагноз текущего стенда подтвердил естественный ночной провал, а не потерю
|
||||
визитов при восстановлении. На границе `2026-01-02T01:00:00+00:00` DDS и STG
|
||||
дали `crossing_visits=0`. За предыдущий час завершилось 27 визитов, за
|
||||
следующий началось 24. Последний визит закончился в `00:56:57.766327`, новый
|
||||
начался в `01:00:00`; пауза составила 183 секунды. State на границе содержал
|
||||
`active_visits=0`, поэтому restore не мог отбросить активный визит. Для
|
||||
контроля: на предыдущей границе state содержал один активный визит, и DDS/STG
|
||||
нашли один переходящий визит.
|
||||
|
||||
Поэтому нулевой стык проходит с явным статусом «однородность неприменима».
|
||||
Пустая порция, хвост за последней границей и непарные строки по-прежнему дают
|
||||
отказ. Остаточный слепой участок принят: однородность нельзя проверить без
|
||||
переходящего визита. Restore закреплён тестом двух последовательных `next-day`
|
||||
и детерминизмом задачи 09, а live-гейт задачи 20 отдельно проверяет стык, где
|
||||
переходящий визит гарантирован сценарием.
|
||||
|
||||
Reference in New Issue
Block a user