Forge

docs/ / adr/0049-skia-surface-rollout-over-avalonia-host.md · branch develop

ADR 0049: Поэтапный rollout Skia-поверхностей при Avalonia-host (CIDE-wide)

Статус: Accepted (частично: chat surface, SkiaKit; остальные поверхности — по волнам)
Дата: 2026-04-15

Связанные ADR

ADR Роль
0036 канал -> CDS -> композитор -> поверхность
0044 гипотеза Skia в чате
0047 instrument/slot
0046 инварианты P/F/M
0017 топология окон и surfaces
0037 строгая PFD-поверхность

Резюме

  • Поэтапный rollout Skia-поверхностей при Avalonia как хосте (dual-path, волны).
  • Не big-bang: миграция по инструментам/зонам с сохранением fallback на Avalonia-контролы.
  • Связка с pipeline Intent→Declutter→Layout→Render (0055).

Контекст

Эксперимент со Skia в чате подтвердил практическую полезность кастомной отрисовки для плотных agent-first поверхностей. Следующий шаг - не точечный спайк, а управляемая миграция по зонам CIDE без потери стабильности host-слоя.

Риск "переписать все UI на Skia" в том, что в одну корзину попадут разные ответственности:

  • host/runtime окна (focus, input routing, диалоги, жизненный цикл);
  • семантика кабины (CDS, policy, intent, slot composition);
  • отрисовка отдельных поверхностей.

Этот ADR фиксирует rollout-стратегию: расширять Skia там, где она реально упрощает surface-слой, и не размывать границы, уже закрепленные предыдущими ADR.

Решение

  1. Модель слоев остается неизменной:
    • Avalonia = host/fuselage (окна, ввод, фокус, lifecycle, системные контролы);
    • CDS/композитор = источник семантики "что и где показывать";
    • Skia = реализация surface-отрисовки там, где это выгодно.

  1. Rollout делается волнами (strangler), не big bang:
    • Wave 1: индикаторные/плотные read-mostly поверхности (status bars, cockpit cards, overlays);
    • Wave 2: MFD-страницы с кастомной геометрией;
    • Wave 3: строго маркированные PFD-поверхности (в связке с 0037).

  1. Для каждой зоны обязателен dual-path: feature flag + fallback на текущий Avalonia view до подтвержденной стабильности. Удаление fallback разрешено только после стабилизации и измерений.

  1. Migration unit = surface-host contract, не "контрол": каждая миграция опирается на явный DTO/кадр из CDS/композитора (например slot/instrument descriptors), а не на прямые зависимости от произвольного дерева контролов.

  1. Области, которые не мигрируются в baseline:
    • редактор-хост и системные диалоги;
    • глобальный window chrome;
    • UX, где стандартные Avalonia-контролы уже достаточны и не создают узких мест.

  1. Критерии "готово" для каждой миграции:
    • визуальный и поведенческий паритет с текущей поверхностью;
    • отсутствие регрессий по input/focus/navigation;
    • измеряемый выигрыш (читабельность/плотность/поддерживаемость, при необходимости - perf);
    • сохранение инвариантов CDS/presentation.

  1. Вводится отдельный Roslyn-guardrail для Skia-surface (рабочий ID: CASCOPE004):
    • цель: не допускать протаскивание host/runtime-логики в surface-слой;
    • область действия: файлы/типы, помеченные как Skia-surface (конвенция или атрибут - по реализации);
    • стартовый режим: warning/info на этапе rollout;
    • целевой режим: error после стабилизации первой волны и чистки текущих нарушений;
    • минимальный стартовый набор проверок:
      • запрет прямых зависимостей на MainWindowViewModel и другие "толстые" VM;
      • запрет прямого управления Window/TopLevel/диалоговым lifecycle из surface-типов;
      • разрешение только контрактных DTO из CDS/композитора и рендер-утилит без host-side эффектов.

  1. Базовая mount-style для production-пресетов (instrument_id -> slot_id):
    • heavy/workflow инструменты (например Solution Explorer, настройки, тяжёлые интерактивные панели) -> mfd;
    • sa инструменты (повышение situational awareness: навигация, статус, ранние сигналы "что происходит/что дальше") -> pfd;
    • hybrid инструменты -> основной слот mfd, в pfd допускается только компактная read-mostly проекция (summary/badge), без полного heavy UX;
    • forward не используется по умолчанию для этих инструментов: это рабочая ось редактора, отклонения - только отдельным решением.

  1. Область действия CASCOPE004 фиксируется как гибридная:
    • primary scope: по namespace/папке (например Cockpit/Surface/**, *.Skia*) для автоматического покрытия базовой зоны;
    • explicit include: атрибут SkiaSurface для типов вне primary scope;
    • explicit escape: атрибут SkiaSurfaceHostEscape (редкий, документированный случай) для контролируемого исключения;
    • правило анализатора: срабатывает при (in primary scope OR [SkiaSurface]) AND NOT [SkiaSurfaceHostEscape].

  1. instrument_id -> instrument_class вводится как incremental registry v1 (source of truth):
  • формат: отдельный реестр (например instrument-classification.toml) в слое cockpit policy;
  • scope v1: обязательная запись только для новых и существенно изменяемых instrument_id, без мгновенного "тотального freeze" для всего наследия;
  • enforcement: старт с warning (missing classification), затем переход к stricter-режиму по волнам rollout;
  • цель: единая классификация (heavy / sa / hybrid) для mount-style и guardrail-проверок без расползания по устным договоренностям.

  1. Для slot_id=pfd строгая маркировка не переопределяется в этом ADR:
  • критерии и режим PfdStrict задаются ADR 0037;
  • состав инструментов и раскладка instrument_id -> slot_id задаются слоем композитора/реестром по ADR 0047;
  • ADR 0049 не дублирует эти правила, а использует их как нормативную основу rollout-политики Skia.

  1. Минимальный perf-gate v1 для снятия fallback (без performance analyzers):
  • отсутствуют функциональные регрессии в ключевых сценариях зоны (открытие, переключение, ввод, фокус);
  • отсутствуют устойчиво воспроизводимые визуальные артефакты при типовых resize/theme switch;
  • отсутствуют устойчиво воспроизводимые крэши/зависания в smoke-сценариях;
  • по рабочей оценке команды новая поверхность не ощущается медленнее baseline на целевом железе;
  • поверхность прошла agreed minimum реальных сессий без отката на fallback (порог задаётся в task/итерации).
  • performance analyzers/метрики профилирования считаются deferred до этапа стабилизации rollout.

  1. Минимальная политика SkiaSurfaceHostEscape:
  • атрибут разрешён только как временное исключение для unblock задачи, если без host-доступа зона не запускается;
  • каждое исключение обязано содержать:
    • reason (кратко: что именно блокирует чистый surface-путь);
    • ссылку на task/issue/ADR-заметку;
    • целевой срок снятия (remove_by - итерация или дата);
  • исключения без этих полей считаются нарушением политики и подлежат удалению до merge;
  • продление срока допускается только отдельным review-решением с обновлением reason и ссылки.

  1. Дизайн рассматривается как измеряемая SA-гипотеза (L1/L2/L3), а не только как инженерный rollout:
  • каждая mount_style обязана иметь целевые сценарии и SA-профиль по уровням:
    • L1 (Perception): какие сигналы оператор должен заметить;
    • L2 (Comprehension): какие связи/смысл должен корректно собрать;
    • L3 (Projection): какие ближайшие развития ситуации должен предсказать.
  • принятие/снятие fallback для policy разрешено только после проверки по батарее метрик:
    • SA-метрики (объективные probes, при необходимости freeze/query);
    • workload (отдельно от SA);
    • performance (отдельно от SA/workload).
  • single-score политика запрещена: агрегирование в одно число без разреза по L1/L2/L3 и сценариям считается недостаточным.
  • если policy улучшает локально один слой, но деградирует глобальную SA-картину (например туннелирование внимания между P/F/M), policy не считается готовой к production preset.

Последствия

  • Skia становится штатным инструментом surface-слоя CIDE, но не заменой всей UI-платформы.
  • Технический долг контролируется через волновой rollout и dual-path.
  • Инварианты архитектуры (0036/0046/0047) не размываются ради скорости миграции.
  • Rollout получает явные SA-gates: дизайн-решения проверяются как гипотезы с измеримым эффектом, а не только по инженерным/визуальным критериям.

Открытые вопросы

  • На момент этого ADR открытых вопросов нет; дальнейшие уточнения фиксируются отдельными ADR-обновлениями.
View only · write via MCP/CIDE