Runbook: cutover идентичности каноника (per-offer + матчер) + re-key миграция
Область: устранение коллизии «10127» на проде — переход с legacy article-hash
каноников ("mpn|article", производитель-слепой) на per-offer провижининг +
матчер-владеет-идентичностью + valuenorm-дедуп производителя. См. ADR-0070/0071/0072,
спека docs/superpowers/specs/2026-07-09-canonical-identity-manufacturer-scoped-design.md.
Природа операции: необратимая, широкий блэк-радиус (~98k legacy-каноников / ~220k офферов). Только off-peak, с dry-run перед apply. Отката к article-hash нет (это и был баг) — при проблемах сходимся пере-прогоном матчера/проекторов.
0. Предусловия
- Задеплоены (одной связкой): матчер part-1 (
3e9b6b13), провижинер per-offer (55e24e5a), brand-normalizer (8ff0c06a), re-key cmd (a65a9ce0). Провижинер per-offer обязателен ДО миграции — иначе свежий ингест продолжит плодить article-hash каноники. - Off-peak окно; DB-VPS не насыщен (свериться с health-матрицей).
- Свежий бэкап/снапшот БД.
1. Deploy связки
Push main → CI собирает и пушит образы по SHA в LAN-registry → App-VPS/DB-VPS
pull по SHA → recreate воркеров: supplier-sync, matcher-worker,
canonical-assignment-worker, catalog-projector, valuenorm-worker
(pull-only deploy, см. memory tracium_pull_only_deploy).
2. (Опц.) Seed valuenorm-словаря производителей
Для известных вариантов написания завести записи characteristic_value_dictionary
scope manufacturer (source seed/moderator): напр. «Konkord Ltd»/«ООО Конкорд»
→ «Konkord». Неизвестные варианты valuenorm сам ставит в unmapped-очередь →
LLM/модератор дозаполняют. Дедуп производителя работает и без сида (по мере
наполнения словаря).
3. Dry-run миграции
canonical-rekey # dry-run по умолчанию
Проверить в логе: scanned, need_repoint, distinct_legacy_canonicals
(ожидаемо ~98k), сэмплы old_canonical → new_canonical. Санити: величины
совпадают с замером (SELECT count(*) … HAVING count(distinct manufacturer_id) > 1).
4. Apply миграции (off-peak, батчами)
canonical-rekey --apply --batch 500 --statement-timeout 2m
Репойнтит офферы на per-offer каноники (через рантайм EnsureForOffer — тот же
canonical_id и viewable_id), чистит match_decisions офферов, ставит
assignment-dirty и projector-reconcile; осушённые legacy-каноники → deprecated. Резюм-safe
(идемпотентно по per-offer id). Мониторить нагрузку; при насыщении — пауза.
5. Пере-кластеризация + пере-проекция
matcher-worker: очищенные офферы (md.offer_id IS NULL) заново матчатся → корректная кластеризация по (производитель, артикул) / fingerprint / характеристикам (без-артикульные) / LLM. Дать беклогу стечь.canonical-assignment-worker+catalog-projector: пересобирают характеристики/представителя из dirty-очередей.
6. Верификация
- Ноль каноников с >1 производителем:
SELECT count(*) FROM ( SELECT canonical_id FROM supplier_offers WHERE canonical_id IS NOT NULL AND manufacturer_id IS NOT NULL GROUP BY canonical_id HAVING count(DISTINCT manufacturer_id) > 1) t; -- ожидаем 0 - Боевые SKU («10127»):
2491970/1512547/1926123/265448/2013423/7810266— на разных канониках; пара Конкорд-кабель (2491970+2013423) слита, остальные раздельно. - Админ-карточка
TR-VB18679больше не мешает кабель+защёлку+прожектор.
7. Запреты / после
- НЕ запускать
canonical-dedupe-repair— он мерджит по артикулу (старая идентичность), отменит фикс. Считать obsolete. - Мониторить рост Tier3-LLM (пустобрендовые/без-артикульные уходят на LLM до дозаполнения) и unmapped-очередь valuenorm (производители на дозаполнение).