WB Localization 2.0 · 25–31 мая 2026

Полный отчёт за неделю.
Куда уходит план, и что с этим делать.

Анализ 6 554 кандидатов на перестановку, 2 105 попыток POST в WBcon, 149 завершённых задач. Где режется пайплайн, какие склады работают, что объединяет провалы, и какие 10 правок алгоритма поднимут конверсию.

Кабинет: ООО ВУКИ Окно: 7 дней Метод: 3 параллельных глубинных среза Сформировано: 2026-05-31
TL;DR

10 главных фактов недели

Сквозная конверсия плана в выполненную задачу — 2.3%. Главное горлышко не там, где думали. WBcon не отказывает: алгоритм отсеивает кандидатов внутри расчёта, а оставшиеся падают на этапе POST из-за рассинхрона chrt_id.

Конверсия план → выполнено
2.3%
6 554 → 149
Главный боттлнек
34%
selected → POST: 4 086 потерь
Причина POST-fail'ов
83%
no chrt_id (672 из 810)
Мёртвых доноров
5
Тула, Невинномысск, Электросталь…
Звёзд (100% SR ≥5 попыток)
27
Ruby, Moon, Vuki, Bella, Audrey…
Токсичных SKU
4
Ruby/ivory лидер: 46 попыток, 20%
Медиана выполнения
25.5ч
p90 = 35.6ч, окно действия 48ч
Окно отмены WBcon
24–48ч
95% всех cancel в этом окне
Очередь active
3 282
2+ месяца разгрузки при темпе ~50/день
Дед-зона приёмки
0/660
Новосибирск как получатель
⚠ Главный вывод

99% всех неудачных POST'ов — рассинхрон chrt_id (наша БД либо WBcon-side). Это самый дешёвый фикс на неделю: pre-flight проверка после _attach_chrt_ids поднимет POST success rate с 61% до 99% (как было 31 мая, когда сработало случайно).

Раздел 1 · Воронка кандидат → POST → выполнено

Где режется план

За неделю система обработала 6 554 кандидата. До WBcon доехала треть. До выполнения — каждый 44-й. Разберём по шагам.

Воронка единым числом

Кандидатов
6 554
100%
Selected
6 191
94.5%
POST attempted
2 105
32% ↓
POST OK
1 295
61% от POST
Completed
149
11.5% от OK

По дням — POST success rate скачет от 33% до 99%

Дата Кандидатов Selected Invalidated POST POST OK DELETE Completed SR POST
26 мая1 0771 07701911332370%
27 мая3 4583 458048340316583%
28 мая78278204661641242935% ↓
29 мая453151642933% ↓
30 мая629453176312246100879% ↑
31 мая6084211872001981561599% ↑
Итого6 5546 1913632 1051 29544714961.5%
📊 Что объясняет провал 28–29 мая

Chrt_id storm — WBcon stocks API перестал отдавать chrt_id для половины SKU. Что изменилось на стороне WBcon — неясно. 30–31 мая ситуация выправилась. Pre-flight проверка решила бы это без человеческого вмешательства.

Lane × decision — приоритет фактически не работает

91% кандидатов попадает в lane C (универсальная корзина). Lane A (топ-приоритет) даёт всего 45 кандидатов в день. Lane E/F не используются вообще.

LaneSelectedPOSTPOST OKCompletedsel→POSTPOST OK ratePOST→done
A2705740521%70%12%
B923117134%55%6%
C5 6121 34793511324%69%12%
D2174726122%55%4%

Morning-check drift растёт

Окно «evening 22:00 → morning-check 07:00» (9 часов) становится слишком длинным. К утру треть плана уже устарела.

ДатаDrift %Действие
28 мая12.8%no_action
29 мая21.6%trimmed
30 мая28.0%trimmed
31 мая30.8%trimmed
🔍 Слепая зона диагностики

В wb2_candidate_moves за неделю только 2 значения decision: selected и invalidated. Все остальные (backlog, blocked, cooldown, no_stock) фильтруются внутри phase3_recalc и в БД не пишутся. Реальные cap'ы (daily=200, per-warehouse=10, daily_capacity=300, cooldown 72h) в данных невидимы.

Раздел 2 · Склады и направления

Что работает. Что нет.

На 5 доноров и 1 получателя приходится почти весь объём. На 5 других доноров и 1 получателя — нулевая отдача. Управление политиками сейчас в коде, не в БД.

Профиль доноров

ДонорTasksDoneSRUnits doneСтабильностьВердикт
СПБ Шушары24110290%6833/7 дней🟢 опора
Казань90880%442/7🟢 опора
Коледино2196361%2542/7🟡 под контролем
Краснодар (Тих.)1103178%2411/7🟡 разовая удача?
Тула24988%113 / 2 179 потеряно2/7🔴 мёртвый
Сарапул83210%92/7🔴 мёртвый
Невинномысск15400%0 / 1 1110/7🔴 мёртвый
Электросталь8100%0 / 1500/7🔴 мёртвый
Рязань (Тюш.)6700%0 / 740/7🔴 мёртвый

Профиль получателей

ПолучательTasksDoneSRUnits doneВердикт
Краснодар (Тих.)39713751%905🟡 ядро объёма
Екатеринбург Персп.2917743%439🟡 54% потерь
Новосибирск66000%0 / 5 715🔴 чёрная дыра

Топ-10 пар по объёму

#ПараTasksDoneSRUnits done
1СПБ Шушары → Новосибирск12500%0
2Тула → Краснодар (Тих.)117812%113
3Коледино → Краснодар (Тих.)984966%209
4Тула → Новосибирск9100
5СПБ Шушары → Краснодар (Тих.) ⭐887495%555
6Невинномысск → Екатеринбург8400%0
7Коледино → Новосибирск8200
11Краснодар → Екатеринбург493179%241
18СПБ Шушары → Екатеринбург ⭐2828100%128
27Казань → Краснодар64100%19

Мёртвые пары (≥5 финализированных, 0 done)

8 пар безусловно идут на блок:

ПараФинализированоCancel WBExpired
СПБ Шушары → Новосибирск700 (всё tech)
Невинномысск → Екатеринбург25196
Тула → Екатеринбург26206
Электросталь → Краснодар18104
Рязань → Краснодар1375
Электросталь → Екатеринбург943
Сарапул → Екатеринбург1081
Рязань → Екатеринбург541

Квоты — не предиктор успеха

⚠ Аномалии

Тула: src-квота 0, отгрузила 113 единиц. Реальная отгрузка не упирается в src-квоту WBcon.
Котовск: dst-квота 347 326 единиц, отгружено 0. Огромная свободная ёмкость не используется.
СПБ Шушары: src-квота 10 160, отгрузила 683 (utilization 6.7%). Самый надёжный донор далёк от лимита.

🔴 Управление политиками — в коде, не в БД

Таблица wbcon_direction_policiesпуста. Все блокировки в хардкоде planner.py:35-51. Менять политики нельзя без деплоя.
Таблица wbcon_direction_snapshots — 194 пары, у всех success_count=0. Снимок UI WBcon до автономного режима. Алгоритм считает direction probability на этих данных — всегда получает ≈0. Фича бесполезна как ранкер.

Раздел 3 · SKU, lifecycle, ошибки

Кто проходит. Как долго живёт. Где падает.

165 уникальных SKU за неделю. У 27 моделей идеальная конверсия, у 4 — провальная. Размер не влияет. Жизнь задачи — 1.5 суток или никогда.

Уникальных nm_id
165
461 триплов nm × size
100% SR (≥5 попыток)
27
«звёзды» — рабочая база
≤20% SR
4
токсичные SKU
0% SR
0
все хоть раз доезжают

Топ-10 звёздных SKU

nm_idАртикулPOSTSR
448199842Moon2/brown2993%
493054553set_moon2/black_white_nude2296%
604357866set_vuki2/fall1894%
467226643set_ruby/black17100%
493054540set_moon2/nude1593%
460344901Joy/wine_red1593%
258162862Miafull/dark_beige14100%
372026190Ruby/washed_brown1292%
601126742Audrey/ivory12100%
502525154Moon2/bright_yellow10100%

4 токсичных SKU (для ручного разбора)

nm_idАртикулPOSTSRГипотеза
231729984Ruby/ivory4620%chrt_id поплыл в номенклатуре
515606810Moon2/red1010%то же
545069082Wendy/fig617%то же
502525161Vuki2/leo_brown520%то же

Размер не влияет

РазмерPOSTSR
(no size = no chrt_id)6720%
S46593%
M44089%
L43488%
XL8389%
XXL11100%

Никаких «токсичных размеров». Все провалы — это no chrt_id ещё до формирования payload.

Lifecycle — окно действия 1.5 суток

Событиеnp50p90
POST → completed (archive_status_1)18325.5ч35.6ч
POST → cancelled by WBcon (archive_status_2)22237.6ч43.1ч
POST → expired (archive_status_5)14943.2ч85.1ч
💡 Что это значит

Задача выполняется быстро (<48ч) или почти никогда. WBcon не отменяет в первые 6ч (instant-reject = 0) и почти не отменяет в первые сутки. Окно отказа = 24–48ч (95% всех cancel). TTL WBcon номинально 120ч, но реальное окно действия = первые 48ч.

Распределение возраста active задач (881 шт)

ВозрастЗадач
<24ч183
24–48ч352
48–72ч0
72–96ч72
96–120ч ⚠ доживают до TTL274
>120ч0

Ошибки POST — полная роспись

Тип ошибкиКол-воДоля fail
no chrt_id in candidate DB row or stocks API67283%
HTTP 400: no src_chrtID от WBcon13016%
Сетевые (RemoteProtocolError, ReadError)71%
HTTP 400: no size10.1%
⚠ Главный вывод раздела

99% всех POST-падений — рассинхрон chrt_id (наша БД либо WBcon-side). Не WBcon-отказ, не лимиты, не сеть. Pre-flight проверка решает 80%+ проблемы.

DELETE работает корректно

447 операций за неделю, 100% status_code=200. Средний возраст задачи на момент DELETE = 37ч. Это проактивная зачистка — снимаем устаревшие задачи до того, как они уйдут в expire.

Концентрация active задач — Новосибирск

Все топ-5 пар по количеству active — это * → Новосибирск:

ПараActive
СПБ Шушары → Новосибирск118
Тула → Новосибирск91
Коледино → Новосибирск82
Казань → Новосибирск78
Невинномысск → Новосибирск70

440+ задач висят в Новосибирске без движения. Либо физический bottleneck приёмки, либо алгоритм слишком много туда отправляет.

Краснодар как донор — критическая зона

⚠ Скоро уйдут в expired

Средний возраст active задач из Краснодара = 106ч (в 2× выше других доноров). Кандидат на принудительный DELETE+rePOST через альтернативный донор.

Раздел 4 · Доработки алгоритма

10 конкретных правок — приоритизировано

От «дёшево и быстро поднимет конверсию вдвое» до «стратегическая перестройка». Уровни 1 → 2 → 3 по соотношению impact/effort.

🔴 Уровень 1 — критично (1–2 дня работы)

Уровень 1

П1. Pre-flight chrt_id check ~4 часа

802 из 810 fail'ов (99%) — отсутствие chrt_id. Алгоритм пихает SKU в POST без проверки.

В legacy_adapter.compute_scored_candidates ПОСЛЕ _attach_chrt_ids — отсеять кандидатов с chrt_id IS NULL. Файл: legacy_adapter.py:586.

POST success rate с 61% → 99% (как 31 мая).

Уровень 1

П2. Cooldown по паре (src, dst, sku) ~6 часов

Cooldown сейчас 72ч на (cabinet, sku, src). Если Тула→Краснодар отказала, через 72ч маршрут повторится. Файл: planner.py:106-109.

Ключ (cabinet, item, src, dst) + fail-counter (3 fail подряд → карантин 7 дней).

Мёртвые пары (Тула→Краснодар 0/54, Невинномысск→Екатеринбург 0/25 и т.д.) перестанут предлагаться. Освободит ~15–20% planning capacity.

🟡 Уровень 2 — высокий impact (2–4 дня)

Уровень 2

П3. Rolling success blacklist доноров ~1 день

Каждое утро считать 7-day rolling SR по доноровым складам. Если SR<10% при N≥10 → донор в manual_review на 14 дней. Новая таблица wb2_donor_health.

Тула, Невинномысск, Электросталь, Рязань, Котовск автоматически выпадают. Освободит ~30% бесполезных POST'ов.

Уровень 2

П4. Auto-cancel зависших задач старше 96ч ~1 день

hanging_task_ttl_days=7 в БД, но в коде main НИГДЕ не читается. 72 задачи >72h, 274 в 96–120h.

В новый стейдж cleanup (можно повесить на existing cleanup-stale-locks): читать TTL, DELETE active-задачи старше 96h из доноров с низким SR.

Освобождает квоты доноров на 700+ единиц/цикл, снижает age-related WBcon отказы.

Уровень 2

П5. Hard cap на размер батча ~4 часа

WBcon отказывает большие батчи (sample 26–50 шт = 9% SR vs 40–55% у мелких).

В daily_cap.apply_global_cap — per-batch hard cap = 15 единиц. Большие батчи бить на части.

При N=55 batch'ах в неделю с qty 26–50 — спасёт ~30 cancellation'ов.

🟢 Уровень 3 — стратегия (1–2 недели)

Уровень 3

П6. SKU-level pair history таблица

Новая таблица wb2_pair_outcomes_sku с агрегатом (src, dst, nm_id, size) × окно 14 дней. JOIN в score_direction → SKU-aware успешность вместо текущей по (src, dst).

Ruby/ivory (46 попыток, 20% SR) и подобные SKU больше не пушатся слепо.

Уровень 3

П7. Перенос BLOCKED_FROM/TO в БД

Проблема: все блоки в коде (planner.py:35-51), таблица wbcon_direction_policies пуста.

Правка: мигрировать хардкоды в БД + добавить UI (через Hub) для управления политиками без деплоя.

Уровень 3

П8. Lane rebalance

A=270 (4%), B=92 (1.5%), C=5 612 (91%), D=217 (3.5%). Lane-приоритет не работает.

Правка: loosen criteria для A/B (loc<70 вместо <60), чтобы 30–40% уходили в A/B. Дать им приоритет в apply_global_cap.

Уровень 3

П9. Сократить окно evening → morning

Drift растёт 12% → 31% за 4 дня (окно 9 часов). К утру треть плана устарела.

Правка: либо передвинуть morning на 06:00 (за 8ч до POST), либо добавить delta-recheck в 03:00.

Уровень 3

П10. Логирование cap'ов в БД

В phase3_recalc дописать причину отсева в wb2_run_log.metadata_json с разбивкой по группам (daily_cap / per_warehouse / cooldown / quota). Без этого половина боттлнеков невидима для будущей аналитики.

Раздел 5 · Дашборд

Как изменить подход к мониторингу

Предлагаю встроить в Hub новую страницу /wb-loc-2/health с обновлением раз в час. 4 KPI со светофором, карта складов, воронка, алерты в Telegram, кнопки управления.

KPI bar — верхняя панель

POST success rate (24ч)
79%
🟢 >85% / 🟡 60–85% / 🔴 <60%
Completion rate
15%
24h done / 48h-ago POST
Active queue size
3 282
🟢 <2000 / 🟡 2000–3500 / 🔴 >3500
Morning-check drift
30.8%
🟢 <15% / 🟡 15–25% / 🔴 >25%

Карта складов

Color-coded heatmap «донор × получатель» с success rate за последние 7 дней. Двойной клик → детализация по SKU.

Sankey-воронка

planned → selected → POST attempted → POST OK → completed, с цифрами потерь на каждом шаге и кликом по сегменту для drill-down.

Алерты в Telegram (@wookiee_alerts_bot)

Кнопки управления

Open questions

4 вопроса без ответов

Что не удалось установить за неделю — кандидаты для следующего этапа.

1. Почему Новосибирск как dst держит 660 задач active с 0 done?

Нужен ручной запрос в WB-поддержку про реальную приёмку склада.

2. Что значит archive_status_4?

В коде не размечено. Из payload — отмена со стороны склада, но семантика отличается от status_2. Уточнить через WBcon docs.

3. Что вызвало chrt_id storm 28–29 мая?

Stocks API стало давать пустые ответы. Что изменилось на стороне WBcon — неясно. К 30 мая прошло само.

4. Связка wb2_task_outcomes.metadata_json.response_idwbcon_task_snapshots.external_task_id

Работает с подменой формата. Нужен миграционный фикс, чтобы было поле external_task_id напрямую (не через JSON path).