opencode-config/docs/decisions/089-pr-201-restore-cover-subicon-slot.md
Sergey 85d7d62fcd
fix(cover): restore sub-icon slot in cover.svg (#201)
* fix(cover): restore sub-icon slot in cover.svg

* docs(cover): add ADR-089 and handoff for PR #201

---------

Co-authored-by: opencode-agent <agent@opencode.local>
2026-08-01 02:56:40 +03:00

31 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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-`<text>`. Это было демонстрацией отвязки тестов от продакшн-шаблона (тесты переехали на `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`:
`<!-- slot: name=sub-icon, x=412, y=600, w=200, h=200, fit=contain, recolor=accent -->`
(та самая, что удалил 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 тестирует движок, продакшн — конкретный бренд-стандарт.