# ADR-089: Restore sub-icon slot in production cover.svg (PR#201) ## Статус Accepted (2026-07-31) ## Контекст PR#197 (ADR-087) упростил продакшн-шаблон `templates/cover.svg` до единственного `icon`-слота 520×520 + `{{title}}` y=830, удалив slot-комментарии `sub-icon`, `badge` и subtitle-``. Это было демонстрацией отвязки тестов от продакшн-шаблона (тесты переехали на `tests/fixtures/cover.svg`). Удалённые слоты в продакшн-рендере тогда не использовались, и `assets/cover.png` остался побайтово идентичным. Однако движок `buildSvg` итерирует по слотам, **объявлённым в шаблоне** (`slot-parser` читает HTML-комментарии из шаблона), а не по `args.slots`, переданным в вызов. Поэтому после PR#197 переданный `sub-icon=...` молча отбрасывался — слот не объявлен в шаблоне → рендерер его не видит. Команда `/cover` (PR#199, ADR-088) документирует `sub-icon` как optional-слот и передаёт его в `draw-image` (пример: `sub-icon=opencode`). Возникла рассогласованность: команда обещает `sub-icon`, рендерер его игнорирует. Сценарий «icon + sub-icon + title» (например, иконка фичи + логотип OpenCode) не работал. Условный рендер слотов (PR#144, ADR-061) уже поддерживает опциональность: передан `sub-icon` → рендерится; не передан → слот пропускается. Это доказано fixture-тестами (`render.optional.test.ts` на `tests/fixtures/cover.svg`, где sub-icon присутствует). Движок поддерживал sub-icon всегда — не хватало только объявления слота в продакшн-шаблоне. ## Решение 1. **Восстановлена ровно одна строка** slot-комментария `sub-icon` в `templates/cover.svg`: `` (та самая, что удалил PR#197). Изменений в коде движка (`src/render.ts`) и команде `/cover` нет. 2. **Только `sub-icon`** — `badge` и `subtitle` остаются удалёнными из продакшн-шаблона (вне scope PR#201). `/cover` (ADR-088) запрещает subtitle стандартом; badge не используется в Lime-стандарте. 3. **Условный рендер (PR#144) сохраняет одно-иконочный кейс побайтово идентичным**: `assets/cover.png` (`icon=opencode`, без `sub-icon`) → 18077 bytes, `cmp` → IDENTICAL. Рендер с двумя иконками (`icon=mic,sub-icon=opencode`) → 23171 bytes (больше, как ожидалось). 4. **Тесты не затронуты**: 58/58 проходят — тесты используют `tests/fixtures/cover.svg` (PR#197), а не продакшн-шаблон, поэтому изменение продакшн-шаблона их не ломает. ## Альтернативы - **Не восстанавливать слот, убрать `sub-icon` из `/cover` (ADR-088)**: отвергнуто — `sub-icon` — полезный сценарий (иконка фичи + логотип проекта), и ADR-088 уже документирует его как optional. Убрать из команды = потерять функциональность, которую движок уже поддерживает. - **Восстановить также `badge` и `subtitle`**: отвергнуто — вне scope issue #200. Lime-стандарт (ADR-088) запрещает subtitle; badge не используется. Восстановление мёртвых слотов вернёт проблему, которую решал PR#197. - **Изменить `buildSvg` чтобы итерировать по `args.slots`, а не по шаблонным слотам**: отвергнуто — крупное архитектурное изменение движка ради одной строки. Текущая модель (шаблон объявляет слоты, рендерер их заполняет) чище и детерминированнее: шаблон = контракт на layout, args = данные. ## Последствия - Частичный реверс ADR-087 (PR#197): продакшн `templates/cover.svg` снова объявляет `sub-icon` (наряду с `icon`). `badge` и `subtitle` остаются удалёнными — реверс точечный. - Сценарий «icon + sub-icon» теперь работает в продакшн-рендере; одно-иконочный кейс побайтово идентичен (условный рендер PR#144). - Тест-контракт (`tests/fixtures/cover.svg`) не изменён — продакшн и fixture снова расходятся по набору слотов (fixture имеет все 4 типа, продакшн — 2), но это намеренно: fixture тестирует движок, продакшн — конкретный бренд-стандарт.