WB Localization 2.0

Автономный сервис, который сам перекладывает товар между складами Wildberries
Паспорт сервиса · версия 2 · 28 мая 2026

Что это. Сервис, который каждый день сам решает «какой товар куда переставить» внутри складов Wildberries, отправляет задачи в кабинет WBcon и следит за их выполнением. CEO не одобряет задачи поштучно — только настраивает защитные правила и смотрит отчёт.

Единственная цель. Поднять индекс локализации с текущих 67% до 90%+. Чем выше локализация — тем дешевле логистика WB, выше выкуп, быстрее доставка.

Где живёт. Сервер timeweb (cron + Python). Данные — в нашей Supabase. Кабинет — в WBcon. Сводки — в Telegram @wookiee_alerts_bot.

01Что делает сервис 02Откуда берёт данные 03Главная метрика — индекс локализации 04Дневной цикл — 6 этапов 05Алгоритм — как выбираем что переставить 06Воронка кандидатов — общая логика 07База данных — что копится и как смотреть 08Склады WB + защитные правила 09Telegram-сообщения 10Расписание cron (МСК) 11Известные проблемы 12Дорожная карта 13Интерфейс в Hub

01 · Что делает сервис

Проблема, которую решаем. У Wookiee 920+ артикулов лежат на 23 рабочих складах WB по всей России. Когда покупатель из Новосибирска заказывает товар, который физически лежит в Коледино — WB везёт его 5 дней через всю страну и берёт с нас за это повышенный коэффициент тарифа (КТР) и сниженный коэффициент региональной приоритезации (КРП). Покупатель ждёт долго → выкуп падает. Карточка не попадает в ТОП регионального поиска → продаж меньше.

Что делает сервис. Каждый день автоматически считает: «вот этот товар лучше переставить из Коледино в Новосибирск, потому что там его всё равно покупают». Отправляет такие задачи в WBcon. Следит, чтобы за неделю индекс локализации (доля заказов с ближайшего склада) рос.

Из каких четырёх блоков состоит сервис

📥
Сбор данных
Читает остатки, заказы, активные задачи WBcon, квоты направлений. Складывает снимки в Supabase.
🧠
Алгоритм
Считает кандидатов на перестановку. Скорит каждого по формуле: «выполнимость × деньги × приоритет».
🚚
Постановка
Удаляет устаревшие задачи, отправляет новые в WBcon. Аудирует каждый ответ. Окно: 09:00 МСК.
📊
Контроль
4 раза в день проверяет «что выполнено, что отменено». Шлёт сводки в Telegram. Алерт если cron упал.

Как они связаны

flowchart LR DATA["📥 Сбор данных
каждый цикл"] --> ALGO["🧠 Алгоритм
ранжирует кандидатов"] ALGO --> POST["🚚 Постановка
POST/DELETE в WBcon"] POST --> CTRL["📊 Контроль
трекер + отчёт"] CTRL -.обратная связь.-> ALGO style DATA fill:#eaf2fa,stroke:#1e4d7a style ALGO fill:#e8f0eb,stroke:#2a4d3a style POST fill:#fdf2e6,stroke:#b54708 style CTRL fill:#eaf2fa,stroke:#1e4d7a

Контроль возвращает данные в алгоритм: какие пары (склад A → склад B) выполняются успешно, какие WB отклоняет, какие зависают. Это та самая «калибровка по факту», которая будет в Sub-project B.

02 · Откуда сервис берёт данные

Сервис общается с тремя внешними системами. Понимать кто кому хозяин — критично, иначе непонятно почему мы не можем просто «прийти и взять».

flowchart LR WB[("🟣 Wildberries
(сам маркетплейс)")] PARTNER[("🟠 Подрядчик
Wildberries DB
89.23.119.253:6433")] SVC["🟢 Наш сервис
WB Localization 2.0
на timeweb")] SUPA[("💾 Наша Supabase
17 таблиц wb2_/wbcon_")] WBCON["🟡 WBcon API
наш кабинет для
перестановок"] WB --"раз в день ETL"--> PARTNER PARTNER --"только чтение
остатки, заказы"--> SVC SVC <--"снимки + аудит"--> SUPA SVC <==>|"чтение + запись
POST/DELETE задач"| WBCON WBCON -.задачи на номер.- WB style WB fill:#f0e8f5,stroke:#6b3a8c style PARTNER fill:#fdf2e6,stroke:#b54708 style SVC fill:#e8f0eb,stroke:#2a4d3a,stroke-width:3px style SUPA fill:#eaf2fa,stroke:#1e4d7a style WBCON fill:#fff5d6,stroke:#b58c08

Кто здесь кто

СистемаЧьяЧто оттуда нужноМожем ли писать?
Wildberries (сам маркетплейс) WB Источник всех данных. WB не отдаёт нам данные напрямую — только через свой API (медленный и ограниченный). Только через стандартный API селлера. Перестановки — отдельно через WBcon.
Wildberries DB (89.23.119.253) Сторонний подрядчик Готовая агрегированная база: остатки по складам, заказы, движения, история. Подрядчик сам ETL-ит данные из WB и держит свою копию. ТОЛЬКО ЧТЕНИЕ Подрядчик нам не разрешает писать.
WBcon (сторонний сервис) Сторонний сервис, наш кабинет Это система, через которую WB разрешает делать перестановки. Звонит на телефон при создании задачи. У нас 2 номера-кабинета: ООО ВУКИ + ИП Медведева. ЧТЕНИЕ + ЗАПИСЬ Поставить новую задачу, удалить старую, посмотреть статус.
Supabase (наша) Наша Наш «мозг» — здесь хранятся снимки WBcon, итоги расчётов алгоритма, аудит всех POSTов, история индекса. ЧТЕНИЕ + ЗАПИСЬ Полный контроль.

Почему нельзя «просто взять у WB напрямую»

03 · Главная метрика — индекс локализации

Что это. Доля заказов, которые ушли с ближайшего к покупателю склада. Если покупатель из Новосибирска купил товар, который физически лежал в Новосибирске — это +1 к локализации. Если приехал с Коледино — 0.

Зачем поднимать.

Как сейчас. Колеблется около 67% последнюю неделю. Цель — 90%+. Каждая точка процента индекса = сотни тысяч рублей в месяц (точная цифра — задача Sub-project C).

ДатаИндексSKU в выборкеЧто произошло
22 мая67.11%275Расширенная выборка
23 мая67.28%201Перешли на core-выборку
26 мая67.22%201Первый live-батч 483 POST (вручную)
27 мая67.19%201
28 мая67.16%201Cron запущен · 164 POST автономно

Важно Колебание ±0.1 п.п. за неделю — это шум, не сигнал. Решения смотрим на горизонте 14–30 дней. Автопилот стартовал вчера.

04 · Дневной цикл — 6 этапов

Каждый день сервис проходит один и тот же цикл из 6 этапов. Все времена — по московскому времени.

flowchart LR E["🌙 22:00
построить план"] --> M["🌅 07:00
перепроверка"] --> P["🚚 09:00
POST в WBcon"] --> T["📈 12/15/18/21
трекер"] --> D["📊 21:30
отчёт"] L["⏰ каждый час
сторож"] style E fill:#e8f0eb,stroke:#2a4d3a style M fill:#e8f0eb,stroke:#2a4d3a style P fill:#fdf2e6,stroke:#b54708,stroke-width:3px style T fill:#eaf2fa,stroke:#1e4d7a style D fill:#eaf2fa,stroke:#1e4d7a style L fill:#f0ede5,stroke:#8a8a8a
🌙 22:00
Вечер — построить план
Подтягивает свежие данные из всех источников. Прогоняет алгоритм. Сохраняет 700–2500 кандидатов в БД, экспортирует план в Google Sheet, шлёт сводку в Telegram «План на завтра: N задач, X штук».
🌅 07:00
Утренняя перепроверка
За ночь могут поменяться остатки и квоты. Сервис снова собирает свежие данные и считает drift — процент кандидатов, которые перестали быть валидными. Если < 20% — молчит. Если > 50% — URGENT «нужен ручной пересчёт».
🚚 09:00
Постановка в WBcon
Главное событие дня. Окно WBcon открывается ровно в 09:00. Сервис: 1) удаляет устаревшие задачи; 2) отправляет новые. Каждый ответ WBcon аудируется. В Telegram прилетает «Батч поставлен: N задач», сообщение потом обновляется трекером весь день.
📈 12/15/18/21
Трекер — следить за выполнением
4 раза в день ходит в WBcon и спрашивает «что с моими задачами». Редактирует то же Telegram-сообщение — прогресс растёт прямо в одной строчке: «выполнено 87/164, в очереди 65, отменено WB 8».
📊 21:30
Дайджест — отчёт за день
Если за день что-то странное (отказов больше 5%, технических ошибок больше 20%, drift в утренней проверке) — собирает в одно сообщение. Если день был спокойный — молчит.
⏰ каждый час
Сторож — heartbeat
Чистит зависшие блокировки. Проверяет «а сработали ли cron-этапы за последние 24 часа». Если evening или morning не отметились — URGENT «cron сломан».

05 · Алгоритм — как мы выбираем что переставить

Это сердце сервиса. Объясняю по шагам — как для человека, не как для разработчика.

Шаг 1 — перебрать все возможные перестановки

Для каждой пары (SKU + размер + склад-донор + склад-получатель) сервис задаёт вопрос: «может, стоит переставить?». На 920 артикулах × ~6 размерах × 23 склада × 23 склада это потенциально миллион пар. Большинство отсеивается сразу — нет товара на доноре, нет смысла везти на получателя, не хватает квоты направления.

После первичного отсева остаётся 700–2500 живых кандидатов в день (зависит от того, сколько SKU «съехало» с целевой локализации за сутки).

Шаг 2 — посчитать ранг каждого кандидата

Главная формула:

rank = feasibility × max(0, impact_рублей) × (1 + priority_bonus)

Три компонента:

🚦 feasibility 0..1

«Доедет ли задача?» Произведение четырёх вероятностей:

  • policy_mult — пара складов разрешена? (1.0 если auto, 0.5 если manual, 0 если blocked)
  • quota_stability — направление стабильное в истории?
  • quota_fit — наша задача помещается в дневную квоту WB?
  • success_rate — историческая успешность пары (по умолчанию 0.85, пока wb2_pair_outcomes не накопил)
💰 impact рубли в месяц

«Сколько мы заработаем/сэкономим, если этот SKU переедет?» Считается так:

  • Берём current_loc (где сейчас процент локализации этого SKU)
  • Считаем projected_loc (где будет, если переставим планируемое qty)
  • Смотрим, как изменятся КТР и КРП WB на этих процентах
  • Множим на месячные заказы → получаем экономию логистики + рост выручки от КРП в рублях
🎯 priority bonus множитель

«Насколько срочно тащить именно этот SKU вверх?» Плавный приоритет (без жёстких порогов):

  • Ниже 60% локализации — сильный бонус (×10)
  • 60–90% — слабый бонус (×1)
  • Выше 90% — ноль (уже достигли цели, не приоритет)

Пример: SKU на 42% → bonus 2.28. На 88% → 0.02.

Шаг 3 — разложить кандидатов по дорожкам (lanes A–F)

Это вторая защитная сетка: даже отранжированных кандидатов алгоритм разделяет по «дорожкам» в зависимости от текущей локализации SKU и приоритетности направления WB:

ДорожкаУсловиеЧто значит
ASKU <60% локализация + направление tier=highСамое приоритетное — критично низкая локализация на горячем направлении
BSKU 60–75% + tier=highПодтянуть «середняка» на горячем направлении
CSKU <60% + tier=mediumНизкая локализация на среднем направлении (~90% сегодняшних кандидатов сюда)
DSKU 75–90% + tier=highДотянуть «хорошо» до «отлично» на горячем направлении
ESKU 60–75% + tier=mediumСредний приоритет
FЗаблокирован / низкое направление / уже >90%Не предлагаем

Шаг 4 — финальная сортировка

В POST идут отсортированные по: (1) Новосибирск в конец (там высокая конкуренция за квоту, не блокируем остальные направления), (2) по убыванию rank-score. Топ-N (сейчас 500) реально отправляется в WBcon.

Что меняет CEO, а что — алгоритм сам

ЧтоГде лежитКто меняет
Веса формулы (0.30 локализация, 0.20 выручка, …)Код scoring.pyБудущий Sub-project B — автокалибровка
Пороги lanes (60%, 75%, 90%)Код planner.pySub-project B
Список заблокированных складовБД wbcon_constraintsCEO — UPDATE в БД
Cooldown 72чБД wbcon_constraintsCEO
Дневные лимиты (per-SKU 400, total 5000)Код sync.pyCEO через обсуждение → правит код
candidate_limit=500Код sync.pyCEO — защитная заглушка первого дня

06 · Воронка кандидатов — общая логика

Каждый день одна и та же воронка из 6 ступеней. Цифры в иллюстрации — типичные, в реальности зависят от дня (плюс-минус 30%).

flowchart TB A["🧮 ~миллион потенциальных пар
SKU × размер × склад-донор × склад-получатель"] A -->|"нет товара / нет смысла
нет квоты направления"| B["🎯 ~700–2 500 живых кандидатов
(алгоритм построил)"] B -->|"scoring по формуле
отсев lane F (заблокированные)"| C["📊 ~500–2 000 после фильтра
дорожки A–E"] C -->|"candidate_limit = 500
(защитная заглушка)"| D["🚦 топ-500 идут в POST stage"] D -->|"per-SKU 400 шт / day
total 5 000 шт / day"| E["⚡ 400–500 попыток POST"] E -->|"chrt_id resolve
(БД → кэш → live)"| F["✅ N задач уходит в WBcon"] E -.->|"не нашли chrt_id"| G["⚠️ остальные в очередь
(кэш растёт со временем)"] style A fill:#f0e8f5,stroke:#6b3a8c style B fill:#eaf2fa,stroke:#1e4d7a style C fill:#e8f0eb,stroke:#2a4d3a style D fill:#fdf2e6,stroke:#b54708 style E fill:#fdf2e6,stroke:#b54708 style F fill:#e8f0eb,stroke:#2a4d3a,stroke-width:3px style G fill:#fdf2e6,stroke:#b54708

Что отсеивается на каждом шаге

#СтупеньЧто отсевается и почему
1Построение пар Алгоритм не рассматривает пары: где на доноре нет товара, где донор и получатель совпадают, где у получателя уже хороший остаток, где направление закрыто WB.
2Scoring + lane F Кандидаты с заблокированными парами (politicy=blocked / direction_tier=low) уходят в lane F и не доходят до POST.
3candidate_limit=500 Жёсткая константа в sync.py:177. «Защитная заглушка первого дня». Берёт топ-500 по rank. Когда автопилот докажет стабильность — поднимем до 1500–2000.
4Дневные лимиты Не больше 400 шт одной модели в день (через все пары складов). Не больше 5000 шт всего. Лишнее переносится «на завтра» (но завтра алгоритм пересчитывает с нуля — это просто верхний потолок).
5chrt_id resolve Чтобы POST в WBcon прошёл, нужен chrt_id (внутренний ID размера в WBcon). 3 источника: колонка в БД (пока NULL), live-запрос в WBcon stocks (rate-limited), исторический кэш из wb2_task_outcomes (растёт сам). Сегодня покрытие ~35%, через 2 недели должно быть 70–90%.
6POST в WBcon Что осталось — реально летит в кабинет. Каждый запрос аудируется в wb2_task_outcomes: что отправили, что ответ, в какое время. Дальше задачу подхватывает WB и кладёт на исполнение склада.

07 · База данных — что копится и как смотреть

17 таблиц в Supabase. Делятся на 4 функциональные группы. Для каждой ключевой таблицы — что лежит, какие колонки, пример строки, какие срезы можно делать.

Группа A — снимки WBcon (что лежит в нашем кабинете)

ТаблицаЧто хранитСтрок
wbcon_warehousesСправочник 29 складов WB с их WBcon-ID29
wbcon_task_snapshotsАктивные задачи WBcon — снимок на каждый цикл~2 500
wbcon_in_transit_snapshotsТовар «в пути» по парам складов~700
wbcon_quota_snapshotsКвоты направлений WBcon (сколько примет каждый склад)~200
wbcon_direction_snapshotsСнимки разрешённых направлений~1 500
wbcon_constraintsЗащитные правила (см. §08)12

Главная — wbcon_task_snapshots

Активные задачи WBcon. Колонки:

external_task_id  — ID задачи в WBcon (например, 845)
normalized_status — нормализованный статус (active / in_transit / no_response)
nm_id, chrt_id    — что за товар и размер
size_name         — название размера ("S", "M")
src_id, dst_id    — ID складов донора и получателя
src_name, dst_name — их названия
qty               — сколько штук просим переставить
first_seen_at, last_seen_at  — когда впервые увидели в WBcon и когда последний раз

Срезы которые можно делать:

Главная — wbcon_in_transit_snapshots

Товар, который уже отправили, но ещё не доехал. Алгоритм использует это в формуле эффективного остатка (см. §05). Без этой таблицы он бы предлагал переставить одно и то же снова и снова.

Группа B — расчёты алгоритма (мозги сервиса)

ТаблицаЧто хранитСтрок
wb2_runs1 строка = 1 прогон алгоритма. Дата, статус, итоги в JSON.~10–15 в день
wb2_candidate_movesКаждый кандидат на перестановку с полной диагностикой scoring5 000+
wb2_rule_setsНастройки алгоритма (cadence, thresholds)2 (1 active)

Самая важная таблица сервиса — wb2_candidate_moves

Здесь лежат ВСЕ кандидаты которые алгоритм когда-либо рассматривал — и принятые, и отброшенные. Это и есть «черный ящик» алгоритма наружу. Колонки:

id                    — уникальный ID кандидата
run_id                — к какому прогону относится (FK на wb2_runs)
candidate_key         — уникальный ключ (cabinet|article|size|src|dst)
article, nm_id, chrt_id, size_name  — что за товар
src_warehouse_name, dst_warehouse_name — пара складов
lane                  — A/B/C/D/E/F (см. §05)
rank_score            — итоговый ранг (feasibility × impact × priority)
expected_success_probability  — вероятность что доедет
expected_localization_gain    — на сколько вырастет локализация SKU (рубли/месяц)
score_features_json   — ПОЛНАЯ диагностика scoring (см. ниже)
decision              — selected / rejected / backlog / cooldown
planned_qty           — сколько штук планируем переставить
decision_reason       — почему такое решение
created_at            — когда посчитан

Внутри score_features_json лежит scoring_diag — расшифровка каждого числа:

{
  "impact": {
    "price": 2122.12,            // цена единицы
    "current_loc": 48.9,         // текущая локализация SKU
    "projected_loc": 50.4,       // прогнозируемая после перестановки
    "monthly_orders": 45.2,      // сколько заказов в месяц
    "ktr_now": 1.2, "ktr_new": 1.1,
    "krp_now": 2.05, "krp_new": 2.05,
    "impact_ktr_rub": 361.0,     // экономия логистики, ₽/мес
    "impact_krp_rub": 0.0        // дополнительная выручка от КРП, ₽/мес
  },
  "feasibility": {
    "policy_mult": 1.0,          // разрешено
    "quota_fit": 1.0,            // помещаемся
    "success_rate": 0.85,        // историческая
    "pair_history": [0, 0]       // [успехов, попыток] — пока пусто
  },
  "priority": {
    "projected_loc_pct": 100.0,
    "bonus_primary": 0.0,
    "bonus_secondary": 0.0
  }
}

Срезы которые можно делать:

Группа C — аудит и история (что реально произошло)

ТаблицаЧто хранитСтрок
wb2_task_outcomesАудит каждой операции POST/DELETE с полным request/response1 200+
wb2_run_logHeartbeat + DB-lock каждого cron-этапа~10/день
wb2_localization_historyДневной снимок индекса локализации по каждому SKU+201/день

Главная — wb2_task_outcomes

Каждая операция (POST новой задачи, DELETE устаревшей) пишет сюда строку. Это наш чёрный ящик — если что-то пошло не так, ищем здесь.

id                       — уникальный
cabinet_code             — 'ooo' или 'ip'
external_task_id         — ID задачи в WBcon (для POST=success)
candidate_move_id        — FK на wb2_candidate_moves (откуда брали)
submitted_at, resolved_at — времена постановки и завершения
resolution               — 'success' / 'unknown' / 'cancelled'
sku_loc_pct_before, sku_loc_pct_after — локализация SKU до/после
metadata_json            — request, response, error в JSON

В metadata_json — полная история: что отправили, что получили, какая ошибка. Это и есть тот неявный кэш chrt_id — sync.py при следующих POSTах смотрит сюда «а постили ли мы такой SKU раньше».

Срезы:

История индекса — wb2_localization_history

+201 строка в день (по SKU из core-выборки). Поля:

snapshot_date  — дата
cabinet_code   — ooo / ip
nm_id          — SKU
loc_pct        — индекс локализации в этот день
orders_period  — заказы за расчётный период (для веса)

Это и есть та таблица, на которой будут все графики «индекс растёт?». Из неё считается средневзвешенный индекс по кабинету. И именно здесь Sub-project C будет искать каузальную связь «наши действия → рост».

08 · Склады WB + защитные правила

29 складов

Все живут в wbcon_warehouses. Разбиты по регионам (региональная группировка — для понимания, в БД её пока нет):

Центральные
Коледино · Подольск · Тула · Электросталь · Белые Столбы · Рязань · Котовск · Сарапул
Юг
Краснодар (Тихорецкая) · Невинномысск · Волгоград
Восток
Казань · Новосемейкино · Самара · Пенза · Екатеринбург · Новосибирск
Северо-Запад
СПБ Шушары · Владимир Воршинское

Двойники : Питание — отдельный режим WB, в перестановках не используется (заблокирован в защитных правилах).

12 защитных правил в wbcon_constraints

«Не навреди» — главный принцип. Правила версионируются (effective_from / effective_to), менять = политическое решение, не эксперимент алгоритма.

ПравилоЗначениеНа человеческом
blocked_to_warehouses Коледино, Подольск, СПБ Шушары, Шушары, Казань, Питание Перегружены — никогда не отправляем сюда товар, даже если по математике выгодно
blocked_from_warehouses Екатеринбург, Владимир, Новосемейкино, Самара, Пенза, Подольск С этих складов забирать через автомат нельзя — пойдут на ручной разбор
high_competition_warehouses Новосибирск, Екатеринбург, СПБ, Казань Эти склады нарасхват — режем квоту, не лезем впереди других продавцов
cooldown_hours_72 72 часа Если вчера предложили пару (SKU + склад-донор) — следующие 3 суток повторно не предложим
no_response_reserve_hours_23 23 часа Задачи без ответа считаем «возможно едут» 23 часа после создания (потом списываем)
in_transit_confidence_0_9 0.9 Товар в пути считаем как 90% — 10% риск что не доедет (отмены, потери)
safe_rate_per_phone_per_second_3 3 req/s Безопасная скорость наших запросов к WBcon на номер
rate_limit_429_threshold_4_5 4.5 req/s Выше этого WBcon начнёт отдавать 429 (rate limit)
default_daily_capacity_units_300 300 шт Дневной потолок единиц для одного направления (когда квота направления неизвестна)
default_capture_factor_0_6 0.6 Можем занять до 60% квоты направления одной задачей — остальное оставляем другим

Настройки нашего алгоритма — wb2_rule_sets

Активный набор: phase-a-default. Это не правила WB, а наши тайминги:

{
  "cycle_evening_msk":              "22:00",     ← вечерний расчёт по МСК
  "cycle_morning_check_msk":        "07:00",     ← утренняя перепроверка
  "cycle_post_msk":                 "09:00",     ← окно WBcon открывается
  "cycle_tracker_msk":              ["12:00","15:00","18:00","21:00"],
  "cycle_digest_msk":               "21:30",     ← вечерний дайджест
  "morning_check_drift_threshold":   0.2,        ← молчим если < 20% drift
  "morning_check_replan_if_invalid_pct_gt": 0.5, ← URGENT если > 50%
  "digest_threshold_tech_fail_pct":  20,         ← порог tech-fail для дайджеста
  "digest_threshold_wb_reject_pct":  5,          ← порог отказов WB
  "duplicate_alert_window_hours":    24,         ← окно дедупа URGENT
  "lock_ttl_minutes":                60,         ← макс длительность DB-lock
  "hanging_task_ttl_days":           7           ← когда списать «зависшую» задачу
}

09 · Telegram-сообщения — на человеческом

Бот: @wookiee_alerts_bot (общий с другими сервисами Wookiee). 6 типов сообщений, переписаны на нормальный русский, без жаргона.

🌙 Вечером — план на завтра (22:00)

22:00 МСК · silent
📋 План перестановок на 29 мая Подготовил 782 задачи на 4 250 штук. В среднем у каждой 42% шанс что склад примет. Топ-5 по объёму: • Wendy чёрный, размер S — 50 шт • Лунный комплект белый, S — 42 шт • Alice чёрный, S — 36 шт • Carmen бежевый, M — 28 шт • Vivi красный, S — 22 шт Если ничего не случится — в 9 утра всё уйдёт в WBcon само.

🌅 Утром — короткая перепроверка (07:00)

07:00 МСК · silent (только если drift >20%)
🌅 Утренняя перепроверка За ночь поменялось 18% кандидатов из вечернего плана (остатки сместились, новые задачи WBcon). План остался валидным — иду на POST в 09:00 МСК без изменений.

🚚 В 09:00 — батч поставлен

09:0X МСК · silent · потом обновляется
🚚 Батч 29 мая ушёл в WBcon Поставлено: 164 задачи Не получилось: 302 (нет chrt_id, разберём вечером) Удалено устаревших: 124 Прогресс буду обновлять прямо в этом сообщении до 21:00.

📈 Трекер — обновляется в течение дня

15:00 МСК · edit того же сообщения
🚚 Батч 29 мая — обновлено 15:00 МСК ✅ Уже на складе: 87 задач (412 штук) 🚛 Ещё в пути: 65 задач (280 штук) ❌ WB отменил: 8 ⚠️ Технические сбои: 4 (разберу вечером) Следующее обновление в 18:00 МСК.

📊 Дайджест за день (21:30)

21:30 МСК · silent · только если есть аномалии
📊 Итоги дня 29 мая Что прошло хорошо: 152 задачи доехали, экономия логистики ~28 000 ₽. На что обратить внимание: • 12% задач упали с ошибкой сервера WBcon (502). Завтра попробуем те же пары — должно пройти. • 6% задач отклонил WB — превысили дневную квоту Краснодара. • Утренний drift 18% — норма. Завтрашний план посчитаю в 22:00 МСК как обычно.

🚨 URGENT — что-то сломалось

громкий · требует реакции
🚨 POST не получился 09:03 МСК пытался отправить батч 29 мая — WBcon ответил «503 Service Unavailable». Это сторона WBcon. Жду стабильности, повторю автоматически в 09:30. Если не получится — напишу снова.

10 · Расписание cron — всё по Москве

Файл /etc/cron.d/wb-loc-2 на сервере timeweb. TZ=Europe/Moscow в шапке файла.

Время МСКЭтапCron expression
22:00Вечер — построить план0 22 * * *
07:00Утренняя перепроверка0 7 * * *
09:00POST batch0 9 * * *
12:00, 15:00, 18:00, 21:00Трекер0 12,15,18,21 * * *
21:30Дайджест30 21 * * *
каждый час :30Сторож (cleanup + heartbeat)30 * * * *

Сейчас Запущен только кабинет ООО ВУКИ. Кабинет ИП Медведева — на паузе по решению CEO.

11 · Известные проблемы и обходные пути

1. WBcon rate-limit на /stocks

WBcon ужесточил лимит на эндпоинт остатков — пустые ответы при превышении 4 req/window.

Обход: исторический кэш chrt_id. Сегодня ~35% покрытия, растёт с каждым POST.

2. wb2_candidate_moves.chrt_id пустой

Колонка есть (миграция 013), но планировщик пока её не заполняет — резолюция на POST-этапе.

План: в evening-этапе подмешивать chrt_id из кэша.

3. candidate_limit=500 захардкожено

«Защитная заглушка» в sync.py. Сейчас режет ~282 кандидата из плана.

План: поднять до 1500–2000 после 2–3 успешных автономных циклов.

4. ИП-кабинет (Медведева) выключен

Cron работает только для ООО.

Когда включать: по решению CEO.

5. Drift монитор простой

Считает «процент невалидных» — без разбора по причинам.

План: разложить причины в Sub-project B.

6. Нет каузальной атрибуции

Не отвечаем на вопрос «индекс вырос благодаря нам или сам».

План: Sub-project C — отдельный движок атрибуции.

12 · Дорожная карта — Sub-projects B–E

flowchart LR A["✅ Phase A
Reliability
cron + alerts + audit"] --> B["Phase B
Pair statistics
+ автокалибровка"] B --> C["Phase C
Causal attribution
«мы или само?»"] C --> D["Phase D
LLM agents
weekly review +
CEO digest"] D --> E["Phase E
Auto-stop
когда остановиться?"] UI["Hub UI
экраны §13-14"] A -.parallel.-> UI style A fill:#e8f0eb,stroke:#2a4d3a,stroke-width:3px style UI fill:#fdf2e6,stroke:#b54708,stroke-width:2px
ФазаЧто добавляет
B · Pair statisticsТаблица wb2_pair_outcomes копит «сколько раз пара (склад A→B) завершалась успехом». Алгоритм начинает учитывать реальные success-rate, а не догадку 0.85.
C · Causal attributionРаскладывает прирост индекса по причинам: вклад наших действий vs алгоритм WB vs сезонность. Отвечает на главный вопрос «работает ли сервис».
D · LLM agentsЕженедельный обзор по pair_outcomes. Утренний дайджест CEO на человеческом языке («что произошло вчера, на что обратить внимание»).
E · Auto-stopЛогика «когда хватит». Если индекс на плато 14 дней — снижаем интенсивность. Если ROI падает — стоп.

13 · Интерфейс в Hub

Макеты экранов вынесены в отдельный документ — это позволяет показывать паспорт сервиса (этот файл) отдельно от прототипа UI. Макеты собраны 1:1 на дизайн-системе настоящего Wookiee Hub (stone-палитра, DM Sans + Instrument Serif, двухуровневая боковая навигация, те же карточки и таблицы что и в каталоге).

В интерфейсе менеджер видит:

Прототип UI → wb-loc-2-hub-ui.pages.dev