ADR-0065: Per-supplier поведение через инъекцию стратегий + канонический словарь SupplierRef
Status: accepted Date: 2026-07-07 Deciders: Maxim Belkanov
Контекст
Логика конкретного поставщика протекла в общие слои (domain/app/platform), а
выбор поведения делается switch/if по строке поставщика вместо инъекции стратегии.
Строковый ключ ("etm", "russvet", …) не типизирован и встречается ~1160 раз без
единого источника правды. Каждый infra/normalization-модуль держит собственный
const SupplierName = "...", синхронизируемый вручную; sentinel-тест каталога
проверяет только len(supportedSuppliers), не паритет с зарегистрированными
модулями — добавление поставщика в каталог без правки всех модулей компилируется,
но падает в runtime. Это нарушает ADR-0031 (domain чистый, взаимодействие через
порты), ADR-0030 (композиция в DI-корне) и ADR-0064 §4 (generic-код домен-агностичен).
Решение
- Специфика поставщика — за интерфейсом в правильном BC (
ingestion/normalizationinfra), выбирается в DI-корне через существующий fx-group реестр (bundles/normalizers), а не ветвлением по строке. Новый рукописный локатор не вводим (ADR-0030 rule 16); fx-group→map легитимен, т.к. собирается самим fx. - Канонический типизированный
SupplierRef— единственный источник правды. Набор констант (SupplierETM,SupplierIEK,SupplierSysteme,SupplierDKC,SupplierRussvet,SupplierETMWeb) +KnownSuppliers()(5 customer-facing, безetm_web) +ParseSupplierRef()живут вsupplier-network/domain. Per-moduleconst SupplierName= ссылка на канонический ref, ручная синхронизация устранена. switch/ifпо поставщику и голые supplier-литералы вdomain/app/platformзапрещены. Per-supplier поведение выражается стратегией/конфигом, инъектируемым поSupplierRef.- Энфорсмент. Sentinel-тест паритета:
supplier_catalog.All()↔KnownSuppliers()↔ множествоNormalizer.Name()зарегистрированных customer-facing нормализаторов совпадают. Расширениеcmd/layerlint: supplier-литерал /switch-on-supplier вdomain/app/platform— активен как error (фаза 0 — warn; Phase 4 полного sweep’а — эскалировано до error, 2026-07-07). Долг до-ADR фиксируется в allowlist линтера (сокращать, не расширять). Исключение:catalog/taxonomy_builder/app/— text-matching по меткам таксономии авторской разметки (смесь канонических ссылок и синонимов брендов); архитектурно запрещено импортироватьsupplier-network/domain.
Рефакторинг ведётся фазами (фундамент → packing → характеристики → периферия → sweep →
refs.go → триаж TODO), каждая фаза = отдельный PR-scope с gitnexus_impact перед
правкой, gitnexus_detect_changes перед коммитом, make backend-layerlint +
backend-archlint + go test.
Последствия
Плюсы
- Единый типизированный словарь поставщиков; рассинхрон каталог↔модули ловится compile-time/sentinel-тестом вместо runtime-падения.
- Новый поставщик подключается регистрацией стратегии в DI, без правок generic-слоёв.
domain/app/platformочищаются от supplier-специфики (behaviour-preserving).
Минусы
- Фаза полного sweep’а (~1160 литералов) массова и рискует задеть map-ключи/фикстуры; митигируется пофазностью по слоям и build+test per слой.
- refs.go/
Warehouse.Supplierзатрагивает 10+ BC importers (proposal-pipeline); изолированная поздняя фаза.
Нейтральные последствия
etm_webостаётся внеKnownSuppliers()/каталога (internal-only), появляется лишь какSupplierETMWebи вAllForAdmin().
Рассмотренные альтернативы
Отдельный kernel/domain для словаря
Отклонено: отдельного kernel/domain в проекте нет (есть только catalog/kernel/infra
— утилиты). SupplierRef уже живёт в supplier-network/domain и импортируется 10+ BC;
новый общий kernel не оправдан.
Новый рукописный supplier-локатор
Отклонено ADR-0030 rule 16: расширяем существующий fx-group реестр, а не заводим параллельный ручной registry.
Ссылки
- ADR-0011 (no-proxy), 0024 (supplier connector contract), 0030 (fx DI + rule 16), 0031 (microkernel sub-modules), 0039 (handler registry), 0047 (strategy pure-functions), 0064 (clean layers + generic-код домен-агностичен §4).
- Design spec:
docs/superpowers/specs/2026-07-07-supplier-strategy-architecture-design.md. - План фазы 0:
docs/superpowers/plans/2026-07-07-supplier-strategy-phase0-foundation.md.