Перейти к содержанию

ADR 0055: Skia instrument composition pipeline (Intent -> Declutter -> Layout -> Render)

Статус: Accepted
Дата: 2026-04-17

Связанные ADR

ADR Роль
0036 Канал → CDS → surface
0047 Instrument / slot
0049 Поэтапный Skia rollout
0053 Semantic Map, control flow
0056 Первый consumer — карта намерений
0064 Стадия Render, примитивы deck

Резюме

  • Общий pipeline Skia-инструментов: Intent → Declutter → Layout → Render.
  • Единые invariants для semantic map, deck и будущих приборов.
  • Потребители — 0056, 0057.

Контекст

Skia-инструменты в CIDE (workspace_navigation_map, будущие приборы и overlays) размещаются через host surface compositor, но внутренняя композиция каждого инструмента (данные, declutter, геометрия, рендер-правила) исторически смешивалась в конкретной фиче.

Это дало два системных эффекта:

  1. Граница ответственности размыта: "surface" и "instrument internals" смешиваются в обсуждении и коде.
  2. Каждая новая Skia-фича рискует заново изобретать собственный мини-pipeline без общих invariants.
  3. На примере controlFlow по 0053 видно, что без отдельного declutter-слоя читаемость деградирует на маленьком viewport.

Решение

1) Ввести единый pipeline для всех Skia-инструментов

Для каждого Skia-инструмента фиксируется внутренняя последовательность:

  1. Intent: построение доменной модели состояния инструмента (source-of-truth для содержимого).
  2. Declutter: policy-фильтрация/агрегация и приоритизация перед геометрией.
  3. Layout: геометрическая раскладка.
  4. Render: отрисовка готовой scene без бизнес-логики.

Surface compositor при этом остаётся внешним слоем и отвечает только за "куда инструмент монтируется" (slot/surface), но не за внутреннюю геометрию/declutter инструмента.

2) Внутренний композитор инструмента обязателен

В каждом инструменте вводится отдельный композитор (например *Compositor), который:

  • выбирает layout-движок по доменному уровню детализации;
  • применяет policy высоты/плотности viewport;
  • возвращает готовую scene и параметры отображения.

Это канонический путь для новых Skia-фич, чтобы не дублировать логику в VM и контролах.

3) Declutter — общий слой политики, не "if'ы" в layout

Правила снижения шума (плотность, агрегация повторов, приоритет главного сценария над вторичными деталями — у графа: main-flow vs второстепенные рёбра) вводятся как отдельный policy-слой с единым интерфейсом для разных инструментов.
Layout не должен решать "что скрывать", а только "как раскладывать то, что уже отобрано".

4) Layout / Render: инварианты читаемости (ориентиры HF / кабина)

Ниже — инструмент-агностичные правила: они относятся к любому Skia-инструменту с pipeline из §1 (таймлайн чата, шкала, граф потока управления, схема и т.д.). Примеры в скобках иллюстрируют частный случай; каноническая детализация для control-flow — 0053. Связь с моделью внимания кокпита: 0021, 0046.

  1. Иерархия внимания и порядок отрисовки (Render). У инструмента задаётся фиксированный порядок слоёв базовой сцены: сначала фон/сетка и «несущие» примитивы, затем основной контент, затем подписи и вспомогательная разметка в пределах своих зон. Сигналы внимания из CDS/каналов (0036) — подсветки, трассы, health — рисуются поверх этой базы, без перестройки доменной геометрии под «алерт». Интерактивный фокус (курсор, выделение) — верхний читаемый слой относительно статики. (Пример: граф — рёбра → узлы → подписи в полосе; чат — фон ветки → пузыри → метки времени.)

  2. Бюджет шума: Declutter выбирает что, Layout ограничивает сколько помещается. Declutter задаёт набор видимых сущностей и агрегацию; Layout навешивает плотностные и геометрические потолки под viewport (минимальные зазоры между блоками, лимиты строк/колонок, резервы под вспомогательные колонки). Нельзя компенсировать перегруз контентом одним масштабом, если policy уже сигнализирует «слишком много» — сначала снизить объём или уровень детализации. (Пример: граф — шаг по вертикали и ширина полосы; чат — число видимых сообщений и высота превью.)

  3. Уровни детализации (Glance / Normal / Inspect) — прежде всего Declutter, не только геометрия. Доменный уровень детализации (в т.ч. общие glance / normal / inspect из плана внедрения) задаёт отбор и агрегацию до Layout. Layout меняет метрики раскладки, но не подменяет решение «сколько сущностей показывать» между Glance и Inspect. (Пример: CodeNavigationMapDetailLevel для карты; для другого инструмента — свой enum/шкала, тот же принцип разделения ролей.)

  4. Минимумы читаемости в Glance (Render / тема). При сжатии viewport сохранять нижние пороги читаемости: размер глифа, толщина линий, контраст обводок — чтобы режим «взгляд сбоку» не превращался в неразличимый шум. Числа задаются темой/константами инструмента; инвариант — не жертвовать различимостью ради влезания в rect. (Пример: минимальная толщина связей и обводок узлов; минимальная высота строки в списке.)

  5. Стабильные пространственные роли (Layout). Подписи, легенды, шкалы и прочая вспомогательная графика привязываются к якорной зоне основного контента (смежная область, фиксированный отступ от «полосы» данных), а не прыгают в произвольный угол viewport — ниже стоимость сопоставления метки с объектом. (Пример: легенда у полосы графа 0053; подпись оси у края той же области, что и данные.)

  6. Алертинг поверх базы. Композиторы каналов (TraceFlow, health и т.д.) добавляют overlay к уже собранной базовой scene инструмента: они не дублируют Intent/Layout доменной модели, а только отображают состояние внимания/трасс/статуса поверх неё — для любого типа базового прибора.

Контрактные проверки (тесты pipeline): на малом viewport — нет запрещённых для инструмента пересечений layout-примитивов (коллизии, нечитаемое наложение) при заявленном уровне детализации; при переходе к более глубокому уровню (например Glance → Inspect) объём полезной информации не сужается без явной policy-деградации (пустое состояние, ошибка данных). Конкретика «что считать коллизией» — в контракте каждого инструмента.


Последствия

Плюсы

  • Чёткая архитектурная граница: host surface vs instrument internals.
  • Единый контракт для всех будущих Skia-фич и приборов.
  • Можно независимо эволюционировать declutter/layout/render без регрессий в slot-композиции.

Минусы

  • Больше сущностей и контрактов в слое Skia-инструментов.
  • Нужны отдельные тесты pipeline-уровня (не только layout unit tests).

Не-цели

  • Не менять ADR 0036 и 0047: внешняя surface-композиция остаётся как есть.
  • Не фиксировать здесь конечный UI-стиль всех edge-кейсов и всех инструментов (это эволюция в рамках pipeline и policy).

План внедрения (минимум)

  1. Зафиксировать базовый контракт общего pipeline для Skia-инструментов.
  2. Канонизировать CodeNavigationMapCompositor как первый внедрённый адаптер этого контракта.
  3. Выделить общий DeclutterPolicy интерфейс (минимум: glance, normal, inspect) и инструмент-специфичные реализации.
  4. Зафиксировать контрактные тесты pipeline:
  5. стабильная композиция scene при одинаковом входе;
  6. читаемость на малом viewport (без критических коллизий/наложений по контракту инструмента);
  7. корректная деградация при неполных входных данных (без ложного контента).