Анализ 6 554 кандидатов на перестановку, 2 105 попыток POST в WBcon, 149 завершённых задач. Где режется пайплайн, какие склады работают, что объединяет провалы, и какие 10 правок алгоритма поднимут конверсию.
Сквозная конверсия плана в выполненную задачу — 2.3%. Главное горлышко не там, где думали. WBcon не отказывает: алгоритм отсеивает кандидатов внутри расчёта, а оставшиеся падают на этапе POST из-за рассинхрона chrt_id.
99% всех неудачных POST'ов — рассинхрон chrt_id (наша БД либо WBcon-side).
Это самый дешёвый фикс на неделю: pre-flight проверка после
_attach_chrt_ids поднимет POST success rate с 61% до 99%
(как было 31 мая, когда сработало случайно).
За неделю система обработала 6 554 кандидата. До WBcon доехала треть. До выполнения — каждый 44-й. Разберём по шагам.
| Дата | Кандидатов | Selected | Invalidated | POST | POST OK | DELETE | Completed | SR POST |
|---|---|---|---|---|---|---|---|---|
| 26 мая | 1 077 | 1 077 | 0 | 191 | 133 | 2 | 3 | 70% |
| 27 мая | 3 458 | 3 458 | 0 | 483 | 403 | 1 | 65 | 83% |
| 28 мая | 782 | 782 | 0 | 466 | 164 | 124 | 29 | 35% ↓ |
| 29 мая | — | — | — | 453 | 151 | 64 | 29 | 33% ↓ |
| 30 мая | 629 | 453 | 176 | 312 | 246 | 100 | 8 | 79% ↑ |
| 31 мая | 608 | 421 | 187 | 200 | 198 | 156 | 15 | 99% ↑ |
| Итого | 6 554 | 6 191 | 363 | 2 105 | 1 295 | 447 | 149 | 61.5% |
Chrt_id storm — WBcon stocks API перестал отдавать chrt_id для половины SKU. Что изменилось на стороне WBcon — неясно. 30–31 мая ситуация выправилась. Pre-flight проверка решила бы это без человеческого вмешательства.
91% кандидатов попадает в lane C (универсальная корзина). Lane A (топ-приоритет) даёт всего 45 кандидатов в день. Lane E/F не используются вообще.
| Lane | Selected | POST | POST OK | Completed | sel→POST | POST OK rate | POST→done |
|---|---|---|---|---|---|---|---|
| A | 270 | 57 | 40 | 5 | 21% | 70% | 12% |
| B | 92 | 31 | 17 | 1 | 34% | 55% | 6% |
| C | 5 612 | 1 347 | 935 | 113 | 24% | 69% | 12% |
| D | 217 | 47 | 26 | 1 | 22% | 55% | 4% |
Окно «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)
в данных невидимы.
На 5 доноров и 1 получателя приходится почти весь объём. На 5 других доноров и 1 получателя — нулевая отдача. Управление политиками сейчас в коде, не в БД.
| Донор | Tasks | Done | SR | Units done | Стабильность | Вердикт |
|---|---|---|---|---|---|---|
| СПБ Шушары | 241 | 102 | 90% | 683 | 3/7 дней | 🟢 опора |
| Казань | 90 | 8 | 80% | 44 | 2/7 | 🟢 опора |
| Коледино | 219 | 63 | 61% | 254 | 2/7 | 🟡 под контролем |
| Краснодар (Тих.) | 110 | 31 | 78% | 241 | 1/7 | 🟡 разовая удача? |
| Тула | 249 | 8 | 8% | 113 / 2 179 потеряно | 2/7 | 🔴 мёртвый |
| Сарапул | 83 | 2 | 10% | 9 | 2/7 | 🔴 мёртвый |
| Невинномысск | 154 | 0 | 0% | 0 / 1 111 | 0/7 | 🔴 мёртвый |
| Электросталь | 81 | 0 | 0% | 0 / 150 | 0/7 | 🔴 мёртвый |
| Рязань (Тюш.) | 67 | 0 | 0% | 0 / 74 | 0/7 | 🔴 мёртвый |
| Получатель | Tasks | Done | SR | Units done | Вердикт |
|---|---|---|---|---|---|
| Краснодар (Тих.) | 397 | 137 | 51% | 905 | 🟡 ядро объёма |
| Екатеринбург Персп. | 291 | 77 | 43% | 439 | 🟡 54% потерь |
| Новосибирск | 660 | 0 | 0% | 0 / 5 715 | 🔴 чёрная дыра |
| # | Пара | Tasks | Done | SR | Units done |
|---|---|---|---|---|---|
| 1 | СПБ Шушары → Новосибирск | 125 | 0 | 0% | 0 |
| 2 | Тула → Краснодар (Тих.) | 117 | 8 | 12% | 113 |
| 3 | Коледино → Краснодар (Тих.) | 98 | 49 | 66% | 209 |
| 4 | Тула → Новосибирск | 91 | 0 | — | 0 |
| 5 | СПБ Шушары → Краснодар (Тих.) ⭐ | 88 | 74 | 95% | 555 |
| 6 | Невинномысск → Екатеринбург | 84 | 0 | 0% | 0 |
| 7 | Коледино → Новосибирск | 82 | 0 | — | 0 |
| 11 | Краснодар → Екатеринбург | 49 | 31 | 79% | 241 |
| 18 | СПБ Шушары → Екатеринбург ⭐ | 28 | 28 | 100% | 128 |
| 27 | Казань → Краснодар | 6 | 4 | 100% | 19 |
8 пар безусловно идут на блок:
| Пара | Финализировано | Cancel WB | Expired |
|---|---|---|---|
| СПБ Шушары → Новосибирск | 7 | 0 | 0 (всё tech) |
| Невинномысск → Екатеринбург | 25 | 19 | 6 |
| Тула → Екатеринбург | 26 | 20 | 6 |
| Электросталь → Краснодар | 18 | 10 | 4 |
| Рязань → Краснодар | 13 | 7 | 5 |
| Электросталь → Екатеринбург | 9 | 4 | 3 |
| Сарапул → Екатеринбург | 10 | 8 | 1 |
| Рязань → Екатеринбург | 5 | 4 | 1 |
Тула: 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. Фича бесполезна как ранкер.
165 уникальных SKU за неделю. У 27 моделей идеальная конверсия, у 4 — провальная. Размер не влияет. Жизнь задачи — 1.5 суток или никогда.
| nm_id | Артикул | POST | SR |
|---|---|---|---|
| 448199842 | Moon2/brown | 29 | 93% |
| 493054553 | set_moon2/black_white_nude | 22 | 96% |
| 604357866 | set_vuki2/fall | 18 | 94% |
| 467226643 | set_ruby/black | 17 | 100% |
| 493054540 | set_moon2/nude | 15 | 93% |
| 460344901 | Joy/wine_red | 15 | 93% |
| 258162862 | Miafull/dark_beige | 14 | 100% |
| 372026190 | Ruby/washed_brown | 12 | 92% |
| 601126742 | Audrey/ivory | 12 | 100% |
| 502525154 | Moon2/bright_yellow | 10 | 100% |
| nm_id | Артикул | POST | SR | Гипотеза |
|---|---|---|---|---|
| 231729984 | Ruby/ivory | 46 | 20% | chrt_id поплыл в номенклатуре |
| 515606810 | Moon2/red | 10 | 10% | то же |
| 545069082 | Wendy/fig | 6 | 17% | то же |
| 502525161 | Vuki2/leo_brown | 5 | 20% | то же |
| Размер | POST | SR |
|---|---|---|
| (no size = no chrt_id) | 672 | 0% |
| S | 465 | 93% |
| M | 440 | 89% |
| L | 434 | 88% |
| XL | 83 | 89% |
| XXL | 11 | 100% |
Никаких «токсичных размеров». Все провалы — это no chrt_id ещё до формирования payload.
| Событие | n | p50 | p90 |
|---|---|---|---|
| POST → completed (archive_status_1) | 183 | 25.5ч | 35.6ч |
| POST → cancelled by WBcon (archive_status_2) | 222 | 37.6ч | 43.1ч |
| POST → expired (archive_status_5) | 149 | 43.2ч | 85.1ч |
Задача выполняется быстро (<48ч) или почти никогда. WBcon не отменяет в первые 6ч (instant-reject = 0) и почти не отменяет в первые сутки. Окно отказа = 24–48ч (95% всех cancel). TTL WBcon номинально 120ч, но реальное окно действия = первые 48ч.
| Возраст | Задач |
|---|---|
| <24ч | 183 |
| 24–48ч | 352 |
| 48–72ч | 0 |
| 72–96ч | 72 |
| 96–120ч ⚠ доживают до TTL | 274 |
| >120ч | 0 |
| Тип ошибки | Кол-во | Доля fail |
|---|---|---|
no chrt_id in candidate DB row or stocks API | 672 | 83% |
HTTP 400: no src_chrtID от WBcon | 130 | 16% |
| Сетевые (RemoteProtocolError, ReadError) | 7 | 1% |
HTTP 400: no size | 1 | 0.1% |
99% всех POST-падений — рассинхрон chrt_id (наша БД либо WBcon-side). Не WBcon-отказ, не лимиты, не сеть. Pre-flight проверка решает 80%+ проблемы.
447 операций за неделю, 100% status_code=200. Средний возраст задачи на момент DELETE = 37ч. Это проактивная зачистка — снимаем устаревшие задачи до того, как они уйдут в expire.
Все топ-5 пар по количеству active — это * → Новосибирск:
| Пара | Active |
|---|---|
| СПБ Шушары → Новосибирск | 118 |
| Тула → Новосибирск | 91 |
| Коледино → Новосибирск | 82 |
| Казань → Новосибирск | 78 |
| Невинномысск → Новосибирск | 70 |
440+ задач висят в Новосибирске без движения. Либо физический bottleneck приёмки, либо алгоритм слишком много туда отправляет.
Средний возраст active задач из Краснодара = 106ч (в 2× выше других доноров). Кандидат на принудительный DELETE+rePOST через альтернативный донор.
От «дёшево и быстро поднимет конверсию вдвое» до «стратегическая перестройка». Уровни 1 → 2 → 3 по соотношению impact/effort.
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 мая).
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.
Каждое утро считать 7-day rolling SR по доноровым складам. Если SR<10% при N≥10 → донор в manual_review на 14 дней. Новая таблица wb2_donor_health.
Тула, Невинномысск, Электросталь, Рязань, Котовск автоматически выпадают. Освободит ~30% бесполезных POST'ов.
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 отказы.
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'ов.
Новая таблица wb2_pair_outcomes_sku с агрегатом (src, dst, nm_id, size) × окно 14 дней. JOIN в score_direction → SKU-aware успешность вместо текущей по (src, dst).
Ruby/ivory (46 попыток, 20% SR) и подобные SKU больше не пушатся слепо.
Проблема: все блоки в коде (planner.py:35-51), таблица wbcon_direction_policies пуста.
Правка: мигрировать хардкоды в БД + добавить UI (через Hub) для управления политиками без деплоя.
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.
Drift растёт 12% → 31% за 4 дня (окно 9 часов). К утру треть плана устарела.
Правка: либо передвинуть morning на 06:00 (за 8ч до POST), либо добавить delta-recheck в 03:00.
В phase3_recalc дописать причину отсева в wb2_run_log.metadata_json с разбивкой по группам (daily_cap / per_warehouse / cooldown / quota). Без этого половина боттлнеков невидима для будущей аналитики.
Предлагаю встроить в Hub новую страницу /wb-loc-2/health
с обновлением раз в час. 4 KPI со светофором, карта складов, воронка,
алерты в Telegram, кнопки управления.
Color-coded heatmap «донор × получатель» с success rate за последние 7 дней. Двойной клик → детализация по SKU.
planned → selected → POST attempted → POST OK → completed, с цифрами потерь на каждом шаге и кликом по сегменту для drill-down.
no_chrt_id > 50/час → автоматический alertwbcon_direction_policiesЧто не удалось установить за неделю — кандидаты для следующего этапа.
Нужен ручной запрос в WB-поддержку про реальную приёмку склада.
archive_status_4?В коде не размечено. Из payload — отмена со стороны склада, но семантика отличается от status_2. Уточнить через WBcon docs.
Stocks API стало давать пустые ответы. Что изменилось на стороне WBcon — неясно. К 30 мая прошло само.
wb2_task_outcomes.metadata_json.response_id ↔ wbcon_task_snapshots.external_task_idРаботает с подменой формата. Нужен миграционный фикс, чтобы было поле external_task_id напрямую (не через JSON path).