Files
ddadminandClaude Opus 5 722dbe22b7 feat(generator): торговые события — корзина, покупка, сырой ecommerce
- Зачем:
  - клиентская сторона мира становится целой: без add_to_cart и purchase
    в данных нет ни таксономии событий, ни вложенного JSON, ни денег,
    а метка «покупатель» из плана состава ни на что не влияла (#40).
- Что:
  - добавлен модуль commerce: корзина шире заказа, номер заказа вида
    ГГГГММДД-NNNN, промокод без скидки в сумме, сырой ecommerce через orjson;
  - метка покупателя получила два рычага — долгую жизнь куки в плане и
    свою воронку в дне; CART_PERCENT опущен с 8 до 6, чтобы конверсия
    мира осталась около 2%;
  - часть цен каталога получила копейки: productPrice округляется форматом,
    purchaseRevenue несёт точную сумму — расхождение живёт внутри события;
  - граница суток забирает страницу подтверждения вместе с её покупкой:
    потерь на клиентской стороне этот этап не заводит;
  - решения и перемеренные числа мира записаны в спеку генератора, §9.
- Проверка:
  - make lint && make typecheck && make test — 383 passed (было 353).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 19:13:30 +03:00

42 lines
1.7 KiB
Python

"""Идентификаторы событий: неповторяющиеся и переживающие JSON.
Обещание одно, но держит его дедупликация при переигровке дня: два
одинаковых `WatchID` склеили бы разные события (спека, раздел 4).
"""
import numpy as np
from clickstream_generator import ids
from clickstream_generator.seeds import CANONICAL_SEED
def stream(offset: int = 0) -> np.random.Generator:
return np.random.Generator(np.random.PCG64(CANONICAL_SEED + offset))
def test_ids_do_not_repeat_and_survive_json():
numbers = ids.unique(stream(), 10_000)
assert numbers.dtype == np.uint64
assert len(set(numbers.tolist())) == numbers.size
assert numbers.max() < ids.LIMIT
assert numbers.min() > 0
def test_ids_do_not_give_away_the_order_of_the_rows():
"""Иначе номер события рассказывал бы, каким по счёту оно родилось."""
numbers = ids.unique(stream(), 1_000)
assert not np.all(np.diff(numbers.astype(np.int64)) > 0)
def test_ids_of_another_stream_are_other_ids():
assert not np.array_equal(ids.unique(stream(), 100), ids.unique(stream(1), 100))
def test_ids_can_be_drawn_beside_the_ones_already_taken():
"""Торговые строки берут номера из своего подпотока и не задевают чужие."""
taken = ids.unique(stream(), 5_000)
numbers = ids.unique_apart_from(stream(1), 500, taken)
assert len(set(numbers.tolist())) == numbers.size
assert not set(numbers.tolist()) & set(taken.tolist())
assert numbers.max() < ids.LIMIT