Перейти к основному содержимому

Замеры с живых баз — 2026-08-02

Замерено основным агентом. Делегатам: НЕ ПЕРЕПРОВЕРЯТЬ, у вас нет доступа к серверам. Если цифра нужна для работы — берите отсюда.

Источники: gwptd_kernel и gwptd_intake на s3, lamoda_reports на s2.

Потеря финальных статусов заказов

Механизм. Сборщики ходят окном 7 дней по дате СОЗДАНИЯ. Если заказ перешёл в финальный статус позже, к следующему прогону он вышел из окна и перехода мы не увидим никогда.

Доказанная потеря (финансы против фактов), Ozon:

площадказаказоввыручка
Ozon FBS delivering6207 849 498 ₽
Ozon FBO delivering911 557 742 ₽
Ozon rFBS delivering240 984 ₽
Ozon FBS awaiting_packaging40 ₽
итого7179 448 224 ₽

По ним в gwptd_intake.ozon_finance_transactions есть проводка OperationAgentDeliveredToCustomer — товар передан покупателю, — а в fact_orders статус не delivered. Самая старая 2026-04-17.

Подозрение — пересчитано по реестру статусов (было завышено):

Первая оценка «3736 заказов, 59 588 171 ₽» получена отбором по подстрокам в имени статуса и потому включала финальные исходы Lamoda. После подключения docs/domain/machine-rules/order-status-lifecycle.yaml одна сумма распалась на две:

группазаказовсуммачто это значит
достоверно не завершены (IN_FLIGHT)157619 950 309 ₽заказ реально ещё движется — это потеря
смысл статуса не подтверждён (AMBIGUOUS)188734 294 206 ₽ждёт решения владельца, в потери не складывать

AMBIGUOUS — это Lamoda On shelf, Rejected, Not delivered, Claimed ok/defective/used, Postponed, Failed delivery, Delivery incidence и YM PICKUP, PARTIALLY_DELIVERED.

⚠️ Найден статус, которого нет в реестре: Lamoda «Refund investigation», 1 заказ, 14 900 ₽. Класс не определён — угадывать нельзя, это вход в расчёт потерь.

API-фильтры «по дате изменения» — проверены живьём 2026-08-02

источниквердикт
YM updateFrom/updateTo✅ приняты, 36 из 100 заказов страницы созданы раньше окна
Ozon last_changed_status_date в одиночку❌ HTTP 400 «filter.since and filter.to … must not be empty»
Ozon в комбинации с обязательным since/to✅ учитывается: та же выборка сузилась со 100 до 0

Положительный пример нужного случая у Ozon: создано 8–30 дней назад (вне окна базовой спеки), изменено за трое суток — 61 постинг, статусы delivered и cancelled. Окна создания 30/60/90 дней дали одинаковый результат, поэтому days: 30 достаточно. limit у v4 — жёстко ≤100.

Новые спеки подхватываются расписанием автоматически: у ozon-daily и ym-daily режим endpointSet: marketplace с пустым exclude, то есть --mp ozon перечисляет реестр спек целиком. Отдельная правка расписания не нужна, генерируемый crontab.s3-next.txt не меняется.

Wildberries структурно неуязвим — не включать в детекторы потерь

У WB выкуп это отдельная строка в wb_sales со своим saleID. Пространства идентификаторов не пересекаются:

ordered    e0.i1b9ac3115974dfa07882186a4f030e52.0.0   (42 симв.)
cancelled 88677034626530973.0.0 (41 симв.)
sale S24176983605 (12 симв., префикс S)

Пересечение order_id между ordered и saleноль. Realized у WB это новое событие со своей датой, оно попадает в окно в момент возникновения. У Ozon, YM и Lamoda realized — смена статуса старой строки, и она теряется.

fact_orders хранит текущее состояние

У каждого order_id ровно один статус, обновление перетирает прошлый. Проверено по всем девяти площадкам: ни одного заказа с двумя статусами. Значит «добор по номеру» ложится на схему без изменений.

Что умеют API по дате изменения

источникфильтр «изменено после»используем
Ozon FBS /v4/posting/fbs/listfilter.last_changed_status_date.{from,to}нет
YM /v2/campaigns/{id}/stats/ordersupdateFrom/updateTo (взаимоисключающи с dateFrom/dateTo)нет
Ozon FBO /v3/posting/fbo/listнет
Lamoda /api/v1/ordersсерверных фильтров нет вовсе
WBне установлено, зеркало спеки пустое

Lamoda — худший случай: сервер не фильтрует, коллектор обрывает весь сбор на первом заказе старше 7 дней (spec_runtime/runner.py:1810-1816, _stop_all).

Квота Wildberries: второй потребитель — мы сами

Оба контура собирают один аккаунт WB: s3 в 05:00, s2 в 09:00. Бьются в лимит на одних и тех же эндпоинтах:

эндпоинт429 на s3429 на s2
wb.item_rating4843
wb.stock_turnover2421

Из-за этого wb.stocks исключён из расписания с 11.07. Внешнего потребителя нет.

Решено 02.08: из прогона s2 убраны 10 эндпоинтов, которые не кормят ни ядро, ни старый интерфейс: item_rating, stock_turnover, search_queries, tariffs, claims, deductions, promo_calendar, balance, seller_health, cards_trash. Основание — ядро читает ровно 26 таблиц интейка, и ни одной из целевых таблиц этих спек среди них нет; легаси-маппингов у них тоже нет. Оба главных пожирателя квоты (item_rating, stock_turnover) в этом списке. Бэкап: s2:/home/deploy/crontab.bak-20260802-wb.

Хранение по площадкам

источникстрокразных артикуловсуммавывод
ym_storage16 994722440 102 ₽разбивка по товарам есть
ozon_storage1 458120 395 ₽суточный агрегат, к модели не привязать

⚠️ По YM резолвится через dim_product_identifier (shopSku, mp_id=6, is_current=1) только 230 из 722. На 492 нерезолвленных висит 131 865 ₽ из 440 102 — почти треть. Простая проекция потеряет их молча. Докстрока build_fact_storage.py:17 требует «mapped/unallocated contract».

Дыры в правах

  • gwptd_monitor — нет SELECT на dim_marketplaceзакрыто 02.08, миграция kernel/schemas/migrations/2026-08-02_monitor_dim_marketplace_grant.sql применена.
  • gwptd_collector — нет прав на collector_runtime_pointer и collector_lease, коллектор работает без DB-lease и через legacy-маршрутизацию.

Состояние ядра после бэкфилла 01.08

Остатки, цены и заказы за 90 дней — ноль пропусков. Июльский рейтинг пересчитан на build_all 02.08, экспозиция 21 → 27.09 дня.

Инструменты, удалённые с ветки, но живые в master

Коммит 2e2bae46 от 14.07 удалил 1306 строк: replay_wb_raw_payloads.py (ре-деривация intake из raw_payload без обращения к API) и backfill_intake_from_archive.py с диапазоном дат. Живы в master и в /Volumes/2TB-64/NEW_MP/gwptd-s2-master/.

Первый живой прогон спек добора — 02.08 вечером

Обе спеки отработали status=success, 0 пропущено, ни одного 429.

Ozon (run_id=4410, 1470 постингов) исправил 444 заказа:

сталобылозаказовсумма
delivereddelivering2543 720 155 ₽
cancelleddelivering1221 581 758 ₽
deliveringawaiting_deliver38634 559 ₽
awaiting_deliverawaiting_packaging28441 443 ₽

YM (run_id=4411, 1243 заказа) исправил 299:

сталобылозаказовсумма
DELIVEREDPICKUP117611 749 ₽
DELIVEREDDELIVERY45295 276 ₽
CANCELLED_IN_DELIVERYPICKUP59385 554 ₽
RETURNEDDELIVERED17119 834 ₽
RETURNEDPICKUP961 858 ₽
прочие переходы52246 125 ₽

⚠️ Коррекция идёт в обе стороны. Строки RETURNED ← DELIVERED — это заказы, которые ядро считало реализованными, а они возвращены. Рейтинг считается от продаж за вычетом возвратов, поэтому добор не только добавляет выручку, но и снимает фантомную.

Это снимает часть неопределённости по классу AMBIGUOUS

YM PICKUP — промежуточный, не конечный. Доказано наблюдением: 117 заказов из PICKUP перешли в DELIVERED, ещё 59 — в CANCELLED_IN_DELIVERY. Реестр относил его к AMBIGUOUS из осторожности («не подтверждено, ожидание выдачи это или уже состоявшееся получение»). Теперь подтверждено: ожидание.

Решение о переводе PICKUP в IN_FLIGHT остаётся за владельцем, но данных для него достаточно. По статусам Lamoda такого наблюдения нет — у неё нет фильтра по дате изменения, поэтому её AMBIGUOUS так и остаются открытыми.

⚠️ Поправка 03.08: собранное НЕ доходило до фактов

Первый прогон спек добора показал 743 расхождения между тем, что вернул маркетплейс, и тем, что лежит в fact_orders. Утверждение «они станут delivered на ближайшем пересчёте» было неверным.

approved_payload_join (build_input_projection.py:195) подшивает одобренный payload с фильтром по точному коду эндпоинта, а OZON_POSTING_ENDPOINTS сопоставлял таблице ровно один код. Строки с *_changed отсекались.

Исправлено (коммит 24b9aa24): одна intake-таблица может законно наполняться несколькими эндпоинтами. Проверено на живой базе s3 тем же approved-join, что использует боевой INSERT:

выборка ядразаказовиз них delivered
только базовая спека47802030
базовая + добор48292233

Добор добавляет 49 заказов, которых ядро не видело вовсе, и переводит 203 в delivered. В 1470 заказах побеждает строка добора — через MAX(id), без всякого приоритета по коду эндпоинта.

Это же ограничение объясняет, почему для Lamoda не поможет отдельная спека: её пришлось бы так же вносить в сопоставление ядра, а сама проблема Lamoda не в фильтре, а в обрыве сбора и в отсутствии серверного фильтра по дате изменения.

Ozon FBO: финансы дают дату, но НЕ статус

OZON_FBO_DELIVERY_ENRICH_SQL (build_fact_orders.py:842) по проводке OperationAgentDeliveredToCustomer проставляет fo.delivery_date — и только его. Статус остаётся прежним. Поэтому 91 заказ FBO на 1 557 742 ₽ висят в delivering, хотя передача покупателю доказана финансами.

Фильтра по дате изменения у /v3/posting/fbo/list нет, поэтому единственный путь закрыть FBO — выводить исход из финансов. Это меняет то, что считается продажей, и потому требует решения владельца, а не только кода.

Lamoda: статус каждого заказа собирался всё это время (замер 03.08)

Спека lamoda.status_dates бьёт в тот же эндпоинт /api/v1/orders, что и lamoda.orders, но без itemStop: проходит все ~449 страниц за ~41 минуту, ежедневно, и пишет order_id, статус уровня заказа и дату статуса.

Поэтому расширять окно lamoda.orders с 7 до 30 дней не понадобилось — а стоило бы это ~43 минуты в сутки (1757 заказов против 239, и enrich делает отдельный GET детали на каждый). Слот бы не выдержал: пакет 08:00 заканчивается в 08:49, пересчёт ядра в 09:15. Разбивка пакета:

эндпоинтсекунд
lamoda.status_dates2463
lamoda.orders344
lamoda.nomenclatures106
остальные четыре< 35 каждый

Расхождения статуса — 1329 заказов. Крупнейшие:

в свежих данныхв fact_ordersзаказоввыручка
ReturnedRejected4009 480 901 ₽
ReturnedOn shelf3899 748 387 ₽
ReturnedNot delivered821 991 002 ₽
ReturnedShipped35791 986 ₽
Claimed defectiveDelivered10125 943 ₽
Claimed okDelivered9152 537 ₽

Влияние на признание продаж мало: продажами становятся 0, перестают быть 22 на 319 133 ₽.

Сколько это снимает с «неясного» остатка

статусвсего старше 30 днейразрешаетсявыручка
On shelf6193486 906 660 ₽
Rejected4213305 801 773 ₽
Not delivered140741 455 238 ₽
Claimed ok/defective/used2200

Итого 756 заказов на ~14,2 млн ₽ из 34,29 млн уходят без вопросов к владельцу. Семейство Claimed * не разрешается: там статус тот же и в свежих данных, нужен человек, знающий кабинет Lamoda.

Ozon: 717 заказов доказанно доставлены, но не признаны продажей

схемастатус сейчасзаказоввыручка
FBS (3)delivering6207 849 498 ₽
FBO (5)delivering911 557 742 ₽
FBS (3)awaiting_packaging40 ₽
rFBS (4)delivering240 984 ₽

Риск: 19 из них имеют запись в fact_returns (не помеха — возврат вычитается отдельно), 33 имеют финансовую операцию с Return/Cancel в operation_type — этих исключать, доказательство перестаёт быть однозначным.