Опоздания заказов: слепок догоняет жизнь #185

Closed
opened 2026-08-28 18:42:12 +03:00 by ddmitry · 1 comment
Owner

Part of #8.

Цель

Часть заказов прячется от ранних слепков и впервые приезжает в D+1/D+2 —
«вчера не сходилось, сегодня сошлось». Класс awaiting_order в витрине
сверки становится живым на дни, а не на часы. Учебный результат:
late-arriving data и закрытые окна — почему отчет дня D нельзя закрывать в
день D.

Что войдет

  • Жеребьевка задержки δ — заказная сторона, подпоток ORDERS
    (fate.md, «Два подпотока дня»: опоздание — судьба заказа). Таблица весов
    из трех строк: 0 на подавляющем весе, 1 и 2 — «D+1/D+2» мастер-спеки;
    ориентир суммарной доли опоздавших ~10%. Меряется в днях снятия слепка,
    не отправки. Бросок — на полную длину дня, последним в подпотоке —
    по правилу «броски последними» из seeds.md: существующие броски
    исходов и моментов не сдвигаются. Хеши дней этого не сторожат — они
    считаются по событиям и заказной стороны не видят; неподвижность судеб
    наблюдаема по слепкам: строки не опоздавших заказов остаются байт в
    байт теми же, меняется только состав строк.
  • Скрытие от ранних слепков. В слепках дней d…d+δ−1 строки заказа нет;
    с d+δ она приезжает в том состоянии, до которого заказ дожил: отмененный
    на второй день и опоздавший на третий приедет в первом же своем слепке
    как cancelled — выгрузка догоняет жизнь. created_at не подделывается
    (сдвиг отклонен в fate.md: подделка аудита источника ломает сверку).
  • Гарантия моста. Назначенные планом заказы не опаздывают (δ = 0):
    заказ, не попавший ни в один снятый слепок стартового мира, унес бы куку
    из карты идентичностей. Заказной стороне признак назначения сейчас
    неоткуда взять — orders.of_day видит только Purchases, а
    assigned_order живет в плане; признак доводится до заказной стороны
    каналом: соседний тикет событийной стороны заводит такой же до места
    порчи — использовать его форму, если она достает, иначе довести полем на
    Purchases. Форму выбирает реализация. Инвариант закрывается тестом.
  • Пересборка описи. Байты и хеши слепков изменятся; хеши дней — нет;
    счетчики классов закрытых дней не меняются — к закрытию окна (δ ≤ 2 при
    окне 7) всякий опоздавший давно виден, а класс считается по итоговой
    судьбе.
  • Правки прозы: snapshot.md — слепок больше не включает всякий заказ окна
    безусловно; orders/README.md при необходимости — тем же PR.

Границы

  • Событийную сторону (потеря, дубль) не трогать — соседний тикет.
    Провести признак назначения через общие структуры (Purchases) —
    можно: это канал, не механика порчи.
  • SQL сверки и DQ не менять: awaiting_order уже построен и оживает сам;
    classes_vs_inventory читает только закрытые дни и опозданий не видит.
  • Таблицу весов дальше δ = 2 не расширять: заказ с δ = 6 приехал бы ровно
    в одном слепке, и обещание «пропущенный день ничего не ломает» на нем
    перестало бы быть верным (fate.md).
  • Точные доли — калибровка этапа 7.

Кому что

Механика, скрытие, тесты — Codex целиком по брифу: проект принят в
fate.md. Вычитка правок прозы (snapshot.md) — вкусовой модели.

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

  • docs/architecture/orders/fate.md, «Опоздание — заказ прячется от
    ранних слепков» и «Два подпотока дня» — это спека тикета.
  • Мастер-спека, раздел 4 (абзац про опоздание) и раздел 8 (закрытое окно).
  • generator/src/clickstream_generator/orders.py (of_day, window,
    at_boundary), serialize.py (orders), inventory.py (_snapshot),
    plan.py (assigned_order), commerce.py (Purchases — куда встает
    признак назначения).
  • docs/architecture/orders/snapshot.md — как снимается слепок.
  • Линт и тесты — make lint, make typecheck, make test из generator/.

Проверка

Опись пересобирается make inventory из generator/; «изменились ли
хеши» читается по git diff data/world-inventory.json.

  • make lint, make typecheck, make test в generator/ зеленые.
  • Хеши дней в описи не изменились; хеши слепков пересобраны.
  • Счетчики классов закрытых дней в описи не изменились.
  • Тест неподвижности судеб: строки не опоздавших заказов в слепках —
    байт в байт прежние, разница слепков — только состав.
  • Тест: заказ с δ = 2 отсутствует в слепках d и d+1, присутствует с
    d+2 в дожитом состоянии; created_at равен дню рождения.
  • Тест гарантии моста: у назначенных планом заказов δ = 0.
  • На стенде: world_live_day зеленый; в открытом окне
    dm.purchase_vs_orders_v показывает awaiting_order, к закрытию окна
    счетчики сходятся с описью.
Part of #8. ## Цель Часть заказов прячется от ранних слепков и впервые приезжает в D+1/D+2 — «вчера не сходилось, сегодня сошлось». Класс `awaiting_order` в витрине сверки становится живым на дни, а не на часы. Учебный результат: late-arriving data и закрытые окна — почему отчет дня D нельзя закрывать в день D. ## Что войдет - **Жеребьевка задержки δ** — заказная сторона, подпоток `ORDERS` (fate.md, «Два подпотока дня»: опоздание — судьба заказа). Таблица весов из трех строк: 0 на подавляющем весе, 1 и 2 — «D+1/D+2» мастер-спеки; ориентир суммарной доли опоздавших ~10%. Меряется в днях снятия слепка, не отправки. Бросок — на полную длину дня, **последним в подпотоке** — по правилу «броски последними» из `seeds.md`: существующие броски исходов и моментов не сдвигаются. Хеши дней этого не сторожат — они считаются по событиям и заказной стороны не видят; неподвижность судеб наблюдаема по слепкам: строки не опоздавших заказов остаются байт в байт теми же, меняется только состав строк. - **Скрытие от ранних слепков.** В слепках дней d…d+δ−1 строки заказа нет; с d+δ она приезжает в том состоянии, до которого заказ дожил: отмененный на второй день и опоздавший на третий приедет в первом же своем слепке как `cancelled` — выгрузка догоняет жизнь. `created_at` не подделывается (сдвиг отклонен в fate.md: подделка аудита источника ломает сверку). - **Гарантия моста.** Назначенные планом заказы не опаздывают (δ = 0): заказ, не попавший ни в один снятый слепок стартового мира, унес бы куку из карты идентичностей. Заказной стороне признак назначения сейчас неоткуда взять — `orders.of_day` видит только `Purchases`, а `assigned_order` живет в плане; признак доводится до заказной стороны каналом: соседний тикет событийной стороны заводит такой же до места порчи — использовать его форму, если она достает, иначе довести полем на `Purchases`. Форму выбирает реализация. Инвариант закрывается тестом. - **Пересборка описи.** Байты и хеши слепков изменятся; хеши дней — нет; счетчики классов закрытых дней не меняются — к закрытию окна (δ ≤ 2 при окне 7) всякий опоздавший давно виден, а класс считается по итоговой судьбе. - Правки прозы: `snapshot.md` — слепок больше не включает всякий заказ окна безусловно; `orders/README.md` при необходимости — тем же PR. ## Границы - Событийную сторону (потеря, дубль) не трогать — соседний тикет. Провести признак назначения через общие структуры (`Purchases`) — можно: это канал, не механика порчи. - SQL сверки и DQ не менять: `awaiting_order` уже построен и оживает сам; `classes_vs_inventory` читает только закрытые дни и опозданий не видит. - Таблицу весов дальше δ = 2 не расширять: заказ с δ = 6 приехал бы ровно в одном слепке, и обещание «пропущенный день ничего не ломает» на нем перестало бы быть верным (fate.md). - Точные доли — калибровка этапа 7. ## Кому что Механика, скрытие, тесты — Codex целиком по брифу: проект принят в fate.md. Вычитка правок прозы (`snapshot.md`) — вкусовой модели. ## Сначала прочитать - `docs/architecture/orders/fate.md`, «Опоздание — заказ прячется от ранних слепков» и «Два подпотока дня» — это спека тикета. - Мастер-спека, раздел 4 (абзац про опоздание) и раздел 8 (закрытое окно). - `generator/src/clickstream_generator/orders.py` (`of_day`, `window`, `at_boundary`), `serialize.py` (`orders`), `inventory.py` (`_snapshot`), `plan.py` (`assigned_order`), `commerce.py` (`Purchases` — куда встает признак назначения). - `docs/architecture/orders/snapshot.md` — как снимается слепок. - Линт и тесты — `make lint`, `make typecheck`, `make test` из `generator/`. ## Проверка Опись пересобирается `make inventory` из `generator/`; «изменились ли хеши» читается по `git diff data/world-inventory.json`. - [x] `make lint`, `make typecheck`, `make test` в `generator/` зеленые. - [x] Хеши дней в описи не изменились; хеши слепков пересобраны. - [x] Счетчики классов закрытых дней в описи не изменились. - [x] Тест неподвижности судеб: строки не опоздавших заказов в слепках — байт в байт прежние, разница слепков — только состав. - [x] Тест: заказ с δ = 2 отсутствует в слепках d и d+1, присутствует с d+2 в дожитом состоянии; `created_at` равен дню рождения. - [x] Тест гарантии моста: у назначенных планом заказов δ = 0. - [x] На стенде: `world_live_day` зеленый; в открытом окне `dm.purchase_vs_orders_v` показывает `awaiting_order`, к закрытию окна счетчики сходятся с описью.
ddmitry added the ready-for-agent label 2026-08-28 18:42:36 +03:00
Author
Owner

Уточнение после слияния #184 — для будущего исполнителя.

  • Уже существующий пятиэлементный Woven слишком велик для позиционного кортежа: в распаковке columns, page, product, purchases, event_outcome читателю приходится помнить порядок разнородных значений. В рамках №185 заменить его dataclass с именованными полями до дальнейшего расширения шва. Признак assigned_order, который уже доезжает до _purchases и места порчи событий, вернуть заказной стороне именованным полем этого результата. Шестипозиционный кортеж не заводить.
  • Чтобы не оставлять исполнителю выбор чернового числа мира, стартовая таблица весов δ = 0/1/2 — (90, 5, 5). Обе задержки наблюдаемы, суммарная доля около 10%; точная калибровка по-прежнему остаётся этапу 7.
  • Само наличие awaiting_order после world_live_day не доказывает опоздание: этот класс уже дают покупки текущего дня до очередного слепка. При стендовой приёмке дополнительно показать переход конкретного опоздавшего заказа: строки ещё нет в раннем слепке, затем она появляется в D+1 либо D+2. Точный инвариант δ = 2 остаётся обязательным модульным тестом из постановки.

Это уточнение формы реализации и приёмки; смысл опоздания и границы задачи не меняются.

Уточнение после слияния #184 — для будущего исполнителя. - Уже существующий пятиэлементный `Woven` слишком велик для позиционного кортежа: в распаковке `columns, page, product, purchases, event_outcome` читателю приходится помнить порядок разнородных значений. В рамках №185 заменить его dataclass с именованными полями до дальнейшего расширения шва. Признак `assigned_order`, который уже доезжает до `_purchases` и места порчи событий, вернуть заказной стороне именованным полем этого результата. Шестипозиционный кортеж не заводить. - Чтобы не оставлять исполнителю выбор чернового числа мира, стартовая таблица весов δ = 0/1/2 — `(90, 5, 5)`. Обе задержки наблюдаемы, суммарная доля около 10%; точная калибровка по-прежнему остаётся этапу 7. - Само наличие `awaiting_order` после `world_live_day` не доказывает опоздание: этот класс уже дают покупки текущего дня до очередного слепка. При стендовой приёмке дополнительно показать переход конкретного опоздавшего заказа: строки ещё нет в раннем слепке, затем она появляется в D+1 либо D+2. Точный инвариант δ = 2 остаётся обязательным модульным тестом из постановки. Это уточнение формы реализации и приёмки; смысл опоздания и границы задачи не меняются.
ddmitry self-assigned this 2026-08-28 22:17:55 +03:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ddmitry/clickstream-data-platform#185