Тикет #90: заказ — вторая проекция покупки, а не второе порождение.
Что внутри
Второй выход commerce — покупки дня готовой структурой: номер
заказа, корзина, выручка клиента, промокод, человек за кукой. Сумма
позиций считается один раз на день и уезжает в обе стороны: в событие
как purchaseRevenue, в заказ как items_total — разойтись им негде.
Новых бросков в подпоток COMMERCE не добавилось.
Заказная сторона — подпоток ORDERS на позиции 2 дерева зерна
(прежнее мёртвое имя DISCREPANCIES), ветвление по дню рождения заказа. LATECOMERS не тронут: его наполнит этап 6.
orders.py — деньги заказа целыми копейками: discount по таблице
«код → скидка» (округление вниз), delivery броском по таблице весов на
полную длину дня, total = items_total − discount + delivery.
person_id — последним броском когорты, после паспортов: вторая кука
пары повторяет ID своего человека, заказ показывает его как user_id, в
событие Метрики он не попадает.
ORDER_WINDOW_DAYS = 7 рядом с D0 и поясом; первым читателем станет
команда слепка (#92).
Критерии приёмки
у каждого заказа дня ровно одно событие purchase, order_id равен purchaseID, корзина и суммы совпадают с торговой половиной;
события дня не изменились байт в байт — опись мира не покраснела;
на каждом заказе total = items_total − discount + delivery;
обе куки пары дают один user_id, в событие он не попадает;
повторный прогон того же дня даёт те же заказы.
Ревью
Три линии: две Клод-линии (стандарты и уместность, спека и критерии) и
холодное ревью Кодексом свежим тредом (дефекты, инварианты, честность
тестов) — APPROVED_WITH_MINORS. Пересечений между семействами не было.
Принято: слепок дня в тестах сторожил только события — теперь сторожит и
заказы; снят лишний сторож таблицы доставки; снят дубль теста чистоты.
Находка Кодекса (второй коммит): тест анонимности сверял только числовые
колонки, и личность, уехавшая строкой в сыром ecommerce, проходила мимо.
Дыра воспроизведена мутацией, правка проверена ею же — до правки тест
зелёный, после красный.
Отклонено с доводом: возить промокод индексом вместо кода (модель в том,
что бэкенд читает код по общей таблице мира); заводить тип Stream вместо
тройки columns/page/product (клубок был до тикета, а person едет только
на вход).
Открытые вопросы владельцу
заказ не несёт купон: в таблице слепка мастер-спеки такого поля нет,
поэтому сверка идёт через discount. Если купон в заказе нужен — правка
на строчку.
числа таблицы доставки черновые, финальная калибровка — этап 7.
Проверка
Из generator/: make lint, make typecheck, make test (417 тестов).
В корне: make lint.
Тикет #90: заказ — вторая проекция покупки, а не второе порождение.
## Что внутри
- **Второй выход `commerce`** — покупки дня готовой структурой: номер
заказа, корзина, выручка клиента, промокод, человек за кукой. Сумма
позиций считается один раз на день и уезжает в обе стороны: в событие
как `purchaseRevenue`, в заказ как `items_total` — разойтись им негде.
Новых бросков в подпоток `COMMERCE` не добавилось.
- **Заказная сторона** — подпоток `ORDERS` на позиции 2 дерева зерна
(прежнее мёртвое имя `DISCREPANCIES`), ветвление по дню рождения заказа.
`LATECOMERS` не тронут: его наполнит этап 6.
- **`orders.py`** — деньги заказа целыми копейками: `discount` по таблице
«код → скидка» (округление вниз), `delivery` броском по таблице весов на
полную длину дня, `total` = `items_total` − `discount` + `delivery`.
- **`person_id`** — последним броском когорты, после паспортов: вторая кука
пары повторяет ID своего человека, заказ показывает его как `user_id`, в
событие Метрики он не попадает.
- **`ORDER_WINDOW_DAYS` = 7** рядом с D0 и поясом; первым читателем станет
команда слепка (#92).
## Критерии приёмки
- у каждого заказа дня ровно одно событие `purchase`, `order_id` равен
`purchaseID`, корзина и суммы совпадают с торговой половиной;
- события дня не изменились байт в байт — опись мира не покраснела;
- на каждом заказе `total` = `items_total` − `discount` + `delivery`;
- обе куки пары дают один `user_id`, в событие он не попадает;
- повторный прогон того же дня даёт те же заказы.
## Ревью
Три линии: две Клод-линии (стандарты и уместность, спека и критерии) и
холодное ревью Кодексом свежим тредом (дефекты, инварианты, честность
тестов) — `APPROVED_WITH_MINORS`. Пересечений между семействами не было.
Принято: слепок дня в тестах сторожил только события — теперь сторожит и
заказы; снят лишний сторож таблицы доставки; снят дубль теста чистоты.
Находка Кодекса (второй коммит): тест анонимности сверял только числовые
колонки, и личность, уехавшая строкой в сыром `ecommerce`, проходила мимо.
Дыра воспроизведена мутацией, правка проверена ею же — до правки тест
зелёный, после красный.
Отклонено с доводом: возить промокод индексом вместо кода (модель в том,
что бэкенд читает код по общей таблице мира); заводить тип `Stream` вместо
тройки `columns/page/product` (клубок был до тикета, а `person` едет только
на вход).
## Открытые вопросы владельцу
- заказ не несёт купон: в таблице слепка мастер-спеки такого поля нет,
поэтому сверка идёт через `discount`. Если купон в заказе нужен — правка
на строчку.
- числа таблицы доставки черновые, финальная калибровка — этап 7.
## Проверка
Из `generator/`: `make lint`, `make typecheck`, `make test` (417 тестов).
В корне: `make lint`.
Closes #90
- Зачем:
- тикет #90: второй источник должен смотреть на торговую половину дня
глазами бэкенда — заказ есть проекция покупки, а не второе порождение;
учебный результат — два источника согласованы по построению, а не
сверкой.
- Что:
- `commerce` отдаёт вторым выходом покупки дня: номер заказа, корзину,
выручку клиента, промокод и человека за кукой; новых бросков в
подпоток `COMMERCE` не добавилось, события дня не сдвинулись.
- заведена заказная сторона: подпоток `ORDERS` на позиции 2 дерева зерна
(прежнее мёртвое имя `DISCREPANCIES`), ветвление — по дню рождения
заказа; `LATECOMERS` не тронут, его наполнит этап 6.
- новый модуль `orders.py`: деньги заказа целыми копейками —
`items_total` из корзины, `discount` по таблице «код → скидка»
(округление вниз), `delivery` броском по таблице весов на полную длину
дня, `total` = `items_total` − `discount` + `delivery`.
- план состава завёл `person_id` — последним броском когорты, после
паспортов: вторая кука пары повторяет ID своего человека, заказ
показывает его как `user_id`, в событие Метрики он не попадает.
- `world`: окно изменяемости `ORDER_WINDOW_DAYS` = 7 рядом с D0 и поясом,
черновая таблица стоимости доставки.
- слепок дня в тестах сторожит обе половины: заказы сравниваются наравне
с потоком событий.
- доки: имя подпотока заказной стороны и состав денег заказа записаны в
`docs/architecture/orders`, README генератора знает про новый модуль.
- Проверка:
- из `generator/`: make lint, make typecheck, make test (417 тестов);
в корне — make lint.
- опись мира не покраснела: байты восьми дней те же, заказная сторона
события не сдвинула.
Closes#90
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Зачем:
- холодное ревью Кодексом (линия дефектов) показало дыру в проверке
анонимности: личность, уехавшая строкой в сыром `ecommerce`, проходила
мимо сравнения числовых колонок, и тест оставался зелёным. Дыра
воспроизведена: user_id, дописанный в блок покупки, тест не замечал.
- Что:
- тест анонимности спрашивает двумя способами: числовые колонки дня — со
всеми личностями аудитории, строки покупок целиком — с личностями
покупателей. Сырой блок собирается руками, и лишнее поле в нём теперь
красит проверку.
- Проверка:
- из `generator/`: make lint, make typecheck, make test (417 тестов).
- мутация «дописать user_id в ecommerce покупки»: до правки тест зелёный,
после — красный.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ddmitry
merged commit 62941d2ee5 into main2026-08-18 15:19:17 +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.
Тикет #90: заказ — вторая проекция покупки, а не второе порождение.
Что внутри
commerce— покупки дня готовой структурой: номерзаказа, корзина, выручка клиента, промокод, человек за кукой. Сумма
позиций считается один раз на день и уезжает в обе стороны: в событие
как
purchaseRevenue, в заказ какitems_total— разойтись им негде.Новых бросков в подпоток
COMMERCEне добавилось.ORDERSна позиции 2 дерева зерна(прежнее мёртвое имя
DISCREPANCIES), ветвление по дню рождения заказа.LATECOMERSне тронут: его наполнит этап 6.orders.py— деньги заказа целыми копейками:discountпо таблице«код → скидка» (округление вниз),
deliveryброском по таблице весов наполную длину дня,
total=items_total−discount+delivery.person_id— последним броском когорты, после паспортов: вторая кукапары повторяет ID своего человека, заказ показывает его как
user_id, всобытие Метрики он не попадает.
ORDER_WINDOW_DAYS= 7 рядом с D0 и поясом; первым читателем станеткоманда слепка (#92).
Критерии приёмки
purchase,order_idравенpurchaseID, корзина и суммы совпадают с торговой половиной;total=items_total−discount+delivery;user_id, в событие он не попадает;Ревью
Три линии: две Клод-линии (стандарты и уместность, спека и критерии) и
холодное ревью Кодексом свежим тредом (дефекты, инварианты, честность
тестов) —
APPROVED_WITH_MINORS. Пересечений между семействами не было.Принято: слепок дня в тестах сторожил только события — теперь сторожит и
заказы; снят лишний сторож таблицы доставки; снят дубль теста чистоты.
Находка Кодекса (второй коммит): тест анонимности сверял только числовые
колонки, и личность, уехавшая строкой в сыром
ecommerce, проходила мимо.Дыра воспроизведена мутацией, правка проверена ею же — до правки тест
зелёный, после красный.
Отклонено с доводом: возить промокод индексом вместо кода (модель в том,
что бэкенд читает код по общей таблице мира); заводить тип
Streamвместотройки
columns/page/product(клубок был до тикета, аpersonедет толькона вход).
Открытые вопросы владельцу
поэтому сверка идёт через
discount. Если купон в заказе нужен — правкана строчку.
Проверка
Из
generator/:make lint,make typecheck,make test(417 тестов).В корне:
make lint.Closes #90
- Зачем: - холодное ревью Кодексом (линия дефектов) показало дыру в проверке анонимности: личность, уехавшая строкой в сыром `ecommerce`, проходила мимо сравнения числовых колонок, и тест оставался зелёным. Дыра воспроизведена: user_id, дописанный в блок покупки, тест не замечал. - Что: - тест анонимности спрашивает двумя способами: числовые колонки дня — со всеми личностями аудитории, строки покупок целиком — с личностями покупателей. Сырой блок собирается руками, и лишнее поле в нём теперь красит проверку. - Проверка: - из `generator/`: make lint, make typecheck, make test (417 тестов). - мутация «дописать user_id в ecommerce покупки»: до правки тест зелёный, после — красный. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>