Детерминизм от зерна: что воспроизводимо и как зерно переживает параллельность #28

Closed
opened 2026-08-01 15:46:05 +03:00 by ddmitry · 1 comment
Owner

Part of #26.

Вопрос

Что именно воспроизводимо при том же зерне (seed): поток событий целиком или только состав мира? Как зерно проходит через распараллеливание по модельным дням, чтобы параллельный прогон давал тот же результат, что последовательный?

Развилка отложена мастер-спекой (см. тикет #14). На кону самопроверки лаб: расхождения A–D и доли детерминированы от зерна (раздел 4 мастер-спеки), манифест хранит точные счётчики (раздел 8).

Part of #26. ## Вопрос Что именно воспроизводимо при том же зерне (seed): поток событий целиком или только состав мира? Как зерно проходит через распараллеливание по модельным дням, чтобы параллельный прогон давал тот же результат, что последовательный? Развилка отложена мастер-спекой (см. тикет #14). На кону самопроверки лаб: расхождения A–D и доли детерминированы от зерна (раздел 4 мастер-спеки), манифест хранит точные счётчики (раздел 8).
ddmitry added the wayfinder:grilling label 2026-08-01 15:46:41 +03:00
ddmitry self-assigned this 2026-08-01 16:21:45 +03:00
Author
Owner

Резолюция (сессия 2026-08-01, владелец подтвердил):

  1. Граница обещания — содержимое до байта. Два прогона с одним зерном дают тот же набор событий (те же WatchID/VisitID, поля, метки модельного времени); артефакт эталонного мира при пересборке побайтово совпадает: канонический порядок ключей и строк, пустой git diff = «ничего не изменилось». Вне обещания — транспорт: офсеты и партиции Kafka, какая нода прочитала, _ingested_at, темп живого режима.

  2. Условия обещания. Детерминизм держится при зафиксированном uv.lock и внутри канонического контейнера (везде Linux — на маке и в WSL тоже; переменная только архитектура CPU). Истина — CI на linux; сходимость любой машины проверяется скриптом «пересгенерируй день N — сравни хеш с манифестом»; расхождение на любой платформе — баг генератора, а не допуск.

  3. Раздача зерна — иерархией подпотоков. Корневое зерно → состав мира; (зерно, день) → подпоток дня → именованные подпотоки компонентов (трафик, торговые события, расхождения, опоздания). По построению: параллельный прогон равен последовательному; продление истории днём N+1 не трогает дни 1…N; правка одного компонента меняет только его часть артефакта — дифф читаем.

  4. Дисциплина целочисленной случайности. Случайность тянется целыми числами (диапазоны, выбор из таблиц); плавающие распределения из системной математики не используются — снимает межархитектурные расхождения (arm64/amd64). Деньги считаются в целых копейках; Float64 — только представление в клиентском purchase (урок мастер-спеки о расхождениях).

  5. Канонический seed и паспорт мира. Эталонный мир собирается одним каноническим зерном — константой репозитория; свои зёрна менти крутит без гарантий манифеста. Манифест хранит паспорт мира (зерно + версия генератора); чек-скрипты сверяют паспорт до счётчиков. Суточные волны активности (ночной провал, обеденный и вечерний пики, будни/выходные) с детерминизмом совместимы: профиль интенсивности задаёт день-функция.

Отклонено с доводами:

  • «Воспроизводимы только состав мира и счётчики»: ломает доигрывание дня через дедуп (другие WatchID — дубли вместо склейки) и воспроизводимую отладку.
  • «События те же, байты не обещаем»: экономия копеечная (файл на день + каноническая запись), а честный git diff артефакта и тесты «хеш совпал» теряются.
  • Общий RNG-поток на все дни: порядок исполнения менял бы результат — «параллельно == последовательно» недостижимо.
  • Обещание детерминизма поверх обновления зависимостей: numpy сознательно улучшает алгоритмы распределений между версиями (NEP 19), Faker меняет словари; фиксация — uv.lock, обновление = осознанная пересборка артефакта одним PR.

Хвосты: в спеку (#32) — форма суточного профиля интенсивности, механизм подпотоков (SeedSequence.spawn или аналог, сверить через Context7), правило целочисленной случайности как правило кода этапа 2.

Резолюция (сессия 2026-08-01, владелец подтвердил): 1. **Граница обещания — содержимое до байта.** Два прогона с одним зерном дают тот же набор событий (те же WatchID/VisitID, поля, метки модельного времени); артефакт эталонного мира при пересборке побайтово совпадает: канонический порядок ключей и строк, пустой git diff = «ничего не изменилось». Вне обещания — транспорт: офсеты и партиции Kafka, какая нода прочитала, _ingested_at, темп живого режима. 2. **Условия обещания.** Детерминизм держится при зафиксированном uv.lock и внутри канонического контейнера (везде Linux — на маке и в WSL тоже; переменная только архитектура CPU). Истина — CI на linux; сходимость любой машины проверяется скриптом «пересгенерируй день N — сравни хеш с манифестом»; расхождение на любой платформе — баг генератора, а не допуск. 3. **Раздача зерна — иерархией подпотоков.** Корневое зерно → состав мира; (зерно, день) → подпоток дня → именованные подпотоки компонентов (трафик, торговые события, расхождения, опоздания). По построению: параллельный прогон равен последовательному; продление истории днём N+1 не трогает дни 1…N; правка одного компонента меняет только его часть артефакта — дифф читаем. 4. **Дисциплина целочисленной случайности.** Случайность тянется целыми числами (диапазоны, выбор из таблиц); плавающие распределения из системной математики не используются — снимает межархитектурные расхождения (arm64/amd64). Деньги считаются в целых копейках; Float64 — только представление в клиентском purchase (урок мастер-спеки о расхождениях). 5. **Канонический seed и паспорт мира.** Эталонный мир собирается одним каноническим зерном — константой репозитория; свои зёрна менти крутит без гарантий манифеста. Манифест хранит паспорт мира (зерно + версия генератора); чек-скрипты сверяют паспорт до счётчиков. Суточные волны активности (ночной провал, обеденный и вечерний пики, будни/выходные) с детерминизмом совместимы: профиль интенсивности задаёт день-функция. **Отклонено с доводами:** - «Воспроизводимы только состав мира и счётчики»: ломает доигрывание дня через дедуп (другие WatchID — дубли вместо склейки) и воспроизводимую отладку. - «События те же, байты не обещаем»: экономия копеечная (файл на день + каноническая запись), а честный git diff артефакта и тесты «хеш совпал» теряются. - Общий RNG-поток на все дни: порядок исполнения менял бы результат — «параллельно == последовательно» недостижимо. - Обещание детерминизма поверх обновления зависимостей: numpy сознательно улучшает алгоритмы распределений между версиями (NEP 19), Faker меняет словари; фиксация — uv.lock, обновление = осознанная пересборка артефакта одним PR. **Хвосты:** в спеку (#32) — форма суточного профиля интенсивности, механизм подпотоков (SeedSequence.spawn или аналог, сверить через Context7), правило целочисленной случайности как правило кода этапа 2.
Sign in to join this conversation.