* 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>
5.6 KiB
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 всегда — не хватало только объявления слота в продакшн-шаблоне.
Решение
- Восстановлена ровно одна строка 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нет. - Только
sub-icon—badgeиsubtitleостаются удалёнными из продакшн-шаблона (вне scope PR#201)./cover(ADR-088) запрещает subtitle стандартом; badge не используется в Lime-стандарте. - Условный рендер (PR#144) сохраняет одно-иконочный кейс побайтово идентичным:
assets/cover.png(icon=opencode, безsub-icon) → 18077 bytes,cmp→ IDENTICAL. Рендер с двумя иконками (icon=mic,sub-icon=opencode) → 23171 bytes (больше, как ожидалось). - Тесты не затронуты: 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 тестирует движок, продакшн — конкретный бренд-стандарт.