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

ADR 0063: Instrument deck — именованная композиция инструментов в одном якоре внимания

Статус: Accepted
Дата: 2026-04-17
Обновлено: 2026-04-24 — § deck страницы MFD (композиция внутри страницы Mfd). Подробности — § История.

Связанные ADR

ADR / документ Роль
0021 Якоря; композиция внутри региона
0021 § зоны Различие терминов зон
0050 [instrument_routing], слоты
0046 Политика layout P/F/M
0047 Instrument, слоты
0010 UiModes, пресеты
0064 Виды индикаторов, PrimitivesKit
0068 Payload строки vs проекция
workspace-health-implementation-map-v1.md Чертёж IDE Health deck

Резюме

  • Instrument deck — именованная композиция вокруг одного якоря (фрагмент кода / метод).
  • ContentRepresentation, таксономия примитивов (Readout, Trend, Gauge, Presence…).
  • Presence/Activity vs Dark Cockpit; DedicatedPage — режим страницы MFD, не deck.
  • Deck внутри страницы Mfd — ортогонально навигации между страницами.

Контекст

В разговоре о кокпите раньше смешивались две оси:

  1. Форма представлениякак показать контент в разметке: полоса (Strip), блок «страницы» региона (Page), компактный индикатор и т.д.
  2. Композиционная единицачто и в каком порядке: набор инструментов / сегментов канала / индикаторов (вкладки, стек, split, порядок в композиторе).

В текущем продукте DedicatedPage / bottom_strip в пресете канала IDE Health (ide_health_surfaceIdeHealthUiSurface.DedicatedPage / BottomStrip) относятся к оси 1 (форма представления того же логического канала IDE Health), а не к «именованной колоде инструментов целикого якоря». Имя DedicatedPage канал-специфично; абстрактно это режим ContentRepresentation.Page для IDE Health (§ «Две оси» ниже).

Отдельно: в разговоре о кокпите часто хочется сказать «страница» в смысле оси 2упорядоченный набор инструментов и раскладка в одном месте. Это пересекается с словом Page на оси 1 → нужны разные имена (0021).

Нужны явные термины, чтобы документация, TOML и обсуждения не смешивали: - форму представления канала (Strip / Page / …), - пресет UiMode (вся картина окон и якорей), - именованную композицию инструментов в одном якоре — instrument deck (ось 2 для инструментов; для IDE Health порядок сегментов — композитор канала, ортогонально Strip/Page).

Две ортогональные оси: representation vs composition

Смысл deck здесь: не дублировать имя Page на оси A (форма контейнера в регионе), а назвать ось B — «какие сущности и в каком порядке/раскладке» в этом контейнере: инструменты, сегменты канала, ячейки сетки. У канала IDE Health на оси B — порядок сегментов в композиторе, независимо от Strip/Page.

Ось A — форма представления Ось B — композиция
Вопрос Каким шаблоном/контейнером показать контент в регионе (полоса vs блок «страницы» региона …) Что на этом контейнере и в какой раскладке: несколько инструментов на одном экране, сегменты канала, вкладки/стек, сетка …
Каноническое имя (этот ADR) Перечисление ContentRepresentation: минимум Strip, Page. Дополнительные значения (например Indicator) — по мере продуктовой необходимости, не фиксируем полный список в Proposed. Для инструментов в якоре — instrument deck (ниже). Для канала IDE Health — порядок сегментов в IdeHealthSurfaceCompositor, независимо от Strip/Page (чертёж).
IDE Health сегодня TOML ide_health_surface: bottom_stripStrip, dedicated_pagePage. В коде — IdeHealthUiSurface.BottomStrip / DedicatedPage (не синоним «любой страницы MFD**). IdeHealthSurfaceCompositor: Build → Tests → Debug → Git.

Инвариант: смена ContentRepresentation для IDE Health не меняет снимок IdeHealthInputSnapshot и логику композитора сегментов — только выбор какой View (полоса vs вторичная страница) привязать к тем же IdeHealthSegments (0021, чертёж).

ContentRepresentation.Page и instrument deck — вместе: типичный образ — один экран региона (например зона PFD), на котором одновременно видны несколько инструментов в раскладке — как на реальном PFD: альтиметр, указатель скорости, крен и т.д. на одном приборном поле. Здесь Page (ось A) задаёт форму: контент канала/якоря показан блоком страницы региона, а не узкой полосой (Strip). Instrument deck (ось B) задаёт именно эту композицию: какие инструменты и как размещены (сетка, доли колонок, приоритет ячеек). Оси не смешиваются, но складываются: «страница региона» без колоды была бы пустым контейнером; колода без выбора формы не определяет, полоса это или полный блок.

Узкий случай IDE Health: для одного канала IDE Health DedicatedPage — это ContentRepresentation.Page только для данных IDE Health (те же сегменты, другой View), а не обязательно «весь PFD как авиа-приборная доска»; deck всего якоря PFD в продукте может включать и IDE Health, и другие инструменты — см. 0021.

Вкладки / стекчастный случай deck, когда инструменты не показаны одновременно, а переключаются; для образа «один экран — много приборов» важнее совместная сетка на Page.

ContentRepresentation и код (направление; вопрос закрыт): канон имени оси формы представления контента в регионе — ContentRepresentation (Strip, Page, …). У канала IDE Health это сегодня выражено IdeHealthUiSurface и TOML ide_health_surfaceне отдельная «ось канала», а выбор шаблона размещения (полоса vs блок страницы) для данных IDE Health; соответствие Strip/Page — в таблице выше.

Когда для другого потока данных (другой канал в смысле 0021) понадобится тот же выбор «полоса или страница региона», переиспользуется та же ось ContentRepresentation. Каналы задают что показать; форма (Strip/Page) — общая ось представления, её не смешивают с «осями канала».

Рефакторинг в коде: ввести enum ContentRepresentation и маппить на него IdeHealthUiSurface (или со временем переименовать тип) — шаг реализации, не открытый архитектурный выбор после этого ADR.

Deck в пользовательских пресетах (направление; закрыто эволюционно): на текущий горизонт deck остаётся понятием и внутренним чертёжом композитора (и именем в обсуждении кода), не обязательной сущностью в пользовательском TOML. Декларативное описание именованных колод в .cascade / settings откладывается: это тянет контракт merge, валидацию, версионирование и UI, пока не стабилизирована сама композиция слотов и не ясна реальная потребность «сохранить колоду» у пользователя.

Допустим локальный эксперимент (например только в твоём репо или за флагом), без обещания продукта и без расширения публичного контракта — если так быстрее итерировать. В общий канон и обязательный путь настройки декларативный deck попадает отдельным шагом/ADR, когда появятся данные и сценарии, а не «на всякий случай» заранее.

Решение

1. Ввести продуктовый термин instrument deck (рабочее русское: колода инструментов или сцена слота) — это именованная спецификация: какие инструменты (instrument_id / alias из 0050) участвуют в композиции, в каком порядке и с какой структурой (сетка на одной Page, вкладки, стек, split — перечень паттернов задаётся реализацией и политикой 0046). Типичный случай при ContentRepresentation.Page: несколько приборов на одном экране якоря — см. § Page + deck.

Граница: один deck привязан к ровно одному семантическому якорю внимания в смысле 0021 — например регион PFD или MFD в данном пресете, но не «половина экрана произвольно». Не описывает перенос инструмента из PFD в MFD без смены пресета (это по-прежнему политика пресета / UiMode).

2. Отличие от [instrument_routing] (0050): маршрутизация v1 отвечает на вопрос «какой один инструмент занимает семантический слот pfd_primary / mfd_primary». Deck — уровень тоньше: несколько инструментов и их внутренняя композиция внутри того же якоря/слота, когда продукт это поддерживает. Конкретный merge (deck поверх routing или отдельный ключ) — не фиксируется в этом ADR до появления реализации; инвариант только семантический.

3. Оси A и B не подменяют друг друга: Strip vs Page — про контейнер; deck — про наполнение и раскладку. Для канала IDE Health DedicatedPage / bottom_strip — это только выбор формы для IDE Health (выше); это не отменяет того, что для якоря целиком Page + instrument deck — нормальный способ описать несколько инструментов на одном экране (§).

4. Отличие от пресета UiMode (0010): пресет задаёт глобальную картину (окна, якоря, топология 0017). Deck — локальная именованная композиция внутри одного контекста якоря; переключение deck’ов (если будет) не должно подменять смену пресета целиком, если только продукт явно не введёт «над-пресет» — это вне минимального определения.

5. Именование в документации: в русских текстах избегать голого «страница» без уточнения. Для оси A«форма Page» / «режим Strip» или ContentRepresentation.Page, для оси Bdeck / колода / композиция слота. Для IDE Health явно: «IDE Health в режиме Page (DedicatedPage)» vs «полоса IDE Health (Strip)» — не смешивать с deck целого якоря.

Deck страницы MFD (вложенный уровень)

Оболочка Mfd (0017, MfdShellView / MfdShellPageStack) в продукте v1 переключает одну активную страницу из перечисления MfdShellPage (чат, терминал, сборка, …) — это навигация верхнего уровня внутри якоря Mfd, а не сам по себе instrument deck всего региона.

Deck страницы MFD — отдельная ось: именованная композиция инструментов внутри выбранной страницы (сетка сегментов, вкладки внутри страницы, порядок ячеек — ось B по смыслу § две оси), ортогонально смене MfdShellPage. Якорь внимания по-прежнему регион Mfd в смысле 0021; вложенность — «страница оболочки → при необходимости свой deck».

Уже в коде (частные случаи): на странице Workspace Health — композитор сегментов IDE Health и IdeHealthInstrumentDeck; на странице Environment Readiness — EnvironmentReadinessInstrumentDeck. Направление реализации: явно моделировать «у страницы MFD опционально свой InstrumentDeckDescriptor» и не смешивать в доках смену страницы с колодой внутри страницы. Таксономия host / slot / region / cell при детализации ячеек — 0088.

Пресеты каталога оболочки Mfd (какие MfdShellPage доступны, порядок в палитре, страница по умолчанию) — технически допустимы, но по тем же причинам отсрочки, что и декларативный instrument deck в пользовательском TOML (§ deck в пресетах): merge, валидация, версия схемы, UI — пока не стабилизирована страница → deck в коде и не ясны сценарии. Публичный контракт на «сборку страниц MFD из пресета» — отдельный шаг, не обязательство этого ADR.

Не-цели (на момент Proposed)

  • Зафиксировать синтаксис TOML или ключи для deck (отдельный ADR или расширение 0050 после прототипа).
  • Требовать drag-and-drop между якорями или произвольную геометрию вне политики пресета.
  • Заменять CDS (0036) или слой топологии дисплеев (строка размещения якорей; см. 0017 §).

CDS и топология дисплеев — не путать: CDS (0036) — контур канал → контракт кабины → композитор → поверхность, наблюдаемость и согласованный кадр для MCP; это не слой «как нарисовать всю презентацию UI» и не то же самое, что топология якорей на экранах (0017, 0046). Слово presentation в имени [presentation] / политике CockpitPresentationLayout исторически смешивает эту топологию с обыденным значением «презентация» — направление имён TOML, ёмкость нотации, screen vs монитор, display.layout vs display.screens — нормативно в 0017 §. Deck, ContentRepresentation и раскладка инструментов в регионе описывают форму и состав внутри якоря; они стыкуются с композиторами и CDS как с контуром данных и кадра, без подмены CDS отдельным «движком presentation» и без лишнего параллельного контура «поверх CDS».

Альтернативы (имя абстракции)

Вариант Плюсы Минусы
Оставить только «страница» Привычно Коллизия с IDE Health Page и с веб-терминологией
Deck / колода Коротко, авиа-кокпит метафоры не противоречит; отдельно от Page Новый жаргон — нужен глоссарий
CompositionPage (составная «страница» слота) Понятно «это про композицию», не про Strip/Page Слово Page тянет путаницу с ContentRepresentation.Page и с IDE Health DedicatedPage — в ADR не канон
Scene / сцена Понятно «состав кадра» Пересечение с «сценой» 3D/игр
Layout bundle Технически ясно Длинно, «bundle» уже занят UiModes

Выбор для ADR: зафиксировать англ. instrument deck как каноническое имя абстракции; русский эквивалент в UI/доках — по согласованию продукта («колода», «композиция слота»).

CompositionPage и deck: если CompositionPage означает именованную упорядоченную композицию содержимого слота (инструменты, порядок, вкладки/стек — ось B), это то же самое, что instrument deck; отличие только в имени. Канон в нормативных текстах — deck, чтобы не смешивать с Page на оси формы (ContentRepresentation) и с DedicatedPage у канала IDE Health.

Типы индикаторов в составе deck (направление)

Чтобы deck давал плотные, читаемые экраны без «второго монитора текста», имеет смысл заранее договориться о небольшом наборе визуальных примитивовкак клетка deck’а или фрагмент инструмента показывает состояние. Это не замена оси ContentRepresentation (Strip/Page): примитивы живут внутри ячейки композиции или внутри Skia-инструмента. Связь с иерархией внимания — 0021 (канал EICAS, W/C/A, Dark Cockpit): тип индикатора задаёт геометрию сигнала, не семантику канала.

Примитив vs инструмент: примитив (в т.ч. Lamp / Bar / Sign ниже) — атомарный glance: один визуальный ответ на «что сейчас?» без полноценного сценария навигации и без обязательной модели взаимодействия как у целого слота. Инструмент кабины (0047) — сценарий с состоянием: дескриптор слота, данные, команды, контекст использования. Примитивы собирают картинку внутри инструмента или в ячейке deck и не подменяют инструмент целиком; разрастание примитивов до «мини-приложений» — признак сдвига границы в сторону нового инструмента или новой ячейки deck.

Предлагаемая таксономия (имена — ориентиры, не обязательные идентификаторы в коде v1):

Тип Роль Заметка
Lamp Дискретное состояние, «зажёгся / погас», latch внимания Annunciator / master caution
Bar Величина или отклонение на оси (заполнение, позиция маркера); линейная полоса Glideslope / deviation / progress
Sign Краткая маркировка категории (иконка, бейдж, Warning/Error) Не путать с Readout и Caption
Readout Табло: крупная цифра или моноширинная строка-значение (время, счётчик, версия) Отдельный режим чтения, чем иконка-Sign
Trend Микро-график (sparkline) по времени «Куда движется», не только мгновенное значение Bar
Gauge Скаляр в диапазоне на дуге/кольце Когда линейный Bar в ячейке неудобен; кольцо можно трактовать как вид Bar или отдельный тип — решение реализации
Stack Несколько долей в одной полосе (разбиение 100%) Модель данных иная, чем у одного значения Bar; допустимо как вариант Bar, если API обобщают
Caption Одна строка текста с жёстким truncate (ветка, файл, команда) Контекст-указатель, не «категория» как у Sign
Presence / Activity Семантика роли в продукте (связь, ожидание, ход работы), не обязательно отдельная «форма» примитива По геометрии см. ниже; политика — §

Статический Presence и Lamp: да — дискретный статус «в сети / нет / деградация» по смыслу это Lamp (несколько устойчивых состояний, без обязательной анимации) или, если удобнее метафора иконки, стабильный Sign (две иконки / одна с вариантом). Отдельный тип «Presence» в таблице не дублирует Lamp: это роль данных, которую обычно рисуют через Lamp/Sign; путаница возникает, если назвать отдельным примитивом то, что визуально уже покрыто Lamp.

Activity тоже не обязана быть отдельной геометрией: «busy» часто — Lamp с другим состоянием или кратковременная смена; ход с долей выполнения — Bar / Trend; бесконечный спиннер без семантики — скорее анти-паттерн (§). Риск Dark Cockpit — у анимации и яркости в штате, не у слова Presence.

Зачем: одна и та же компактная страница (deck в режиме плотной сетки) может собираться из ячеек с разными примитивами — без обязательного полного текста в каждой клетке. Это усиливает glanceability в 0021 и согласуется с общим Skia pipeline (0055), не дублируя его.

Presence / Activity и Dark Cockpit (0021 §6): в продуктовом языке Presence — сигнал «есть связь / агент на линии / синхронизация»; статически его обычно выражают Lamp/Sign, см. абзац выше. Activityход работы (сборка, запрос), часто с пульсацией, спиннером, бегущим акцентом — те же примитивы в других режимах, плюс политика не шуметь.

Такой примитив может нарушить Dark Cockpit, если сделать постоянное движение или яркий цвет в штатной тишине («всё ок, но точка мигает каждые две секунды ради красоты»). Тогда внимание тратится на шум, а не на реальную эскалацию — против идеи §6.

Как согласовать:

  1. Номинал / нет активной работы — Presence приглушён, статичен или скрыт (как «невидимый» хром, пока нечего говорить оператору). Не декоративный pulse «мы онлайн».
  2. Идёт значимая работа (сборка, долгий MCP, блокирующая операция) — Activity допустим как кратковременный или привязанный к реальному прогрессу сигнал; предпочтительнее устойчивое состояние (Lamp «busy») или Bar/Trend с реальной динамикой, чем бесконечный спиннер без семантики.
  3. Отклонение от штатного — уводить в иерархию W/C/A и канал EICAS (0021 §5), а не размножать «живые» пиксели в deck: эскалация заметна, штат — тихо.
  4. Развести семантику: статический Presence (подключено / нет) — по примитивам это Lamp/Sign, не отдельная геометрия; временной Activity (работа идёт) — строже политика по умолчанию (показывать только пока есть факт хода работы), визуально чаще Lamp busy, Bar/прогресс или Trend, не декоративный вечный спиннер.

Итог: Presence/Activity не запрещены — они запрещены в режиме вечного маркетингового мерцания. Политика та же, что для EICAS-зоны: в норме не отвлекать (0021, пример про появление блока только при активных оповещениях — по духу сопоставимо).

Границы (Proposed): не фиксируем здесь enum в репозитории, размеры в DP, ни привязку к конкретному контролу Avalonia — только направление. Публичный контракт примитивов для сторонних авторов не цель текущей фазы (см. § открытые вопросы). Отдельно решать, когда появится необходимость: общий слой токенов (цвет/толщина по severity), a11y (не только цвет), связь с intent (0051), продуктовые правила для Presence/Activity по разным UiMode — актуально, когда в продукте снова будет несколько режимов; на текущей линии разработки один режим — Flight, остальное намеренно вне scope (§ открытые вопросы, 0017 § режимы UI).

Intent routing и deck

Intent routing и deck (0051; вопрос уточнён): intent задаёт политику внимания (какой якорь, какой профиль, какие подсказки) — не «заменяет» deck. Внутри deck поведение зависит от режима композиции: при сетке на одной Page (все ячейки видны, образ PFD) intent может подсвечивать ячейку или поток данных, а не «вкладку». При вкладках/стеке (один видимый инструмент) отдельно задаётся, может ли intent переключать активную вкладку или только поднимать якорь — это продуктовое правило после появления такой композиции в коде, не догма ADR.

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

Контекст: внешней аудитории и публичного контракта примитивов пока нет — разрабатываем так, как удобно внутри репозитория; при смене решения переложить код проще, чем ломать чужих потребителей. Плагины и сторонние авторы инструментов отложены; вопрос «стабильный enum в Contracts» не блокирует текущую работу.

Режимы UI: на текущей линии разработки один продуктовый режим — Flight; прочие семейства / пресеты UiMode намеренно не ведём (переработка Power, Balanced и т.д. — отдельная дорожная карта, см. 0017 § «Уточнение: режимы UI»). Продуктовая формулировка «актуальная линия (ветка Skia, ~2026), один режим Flight, старые референсы Focus/Balanced/Power — архив» — в docs/ui-ux/README.md. Ветка feature/skia и работа по инструментам не обязаны заранее согласовывать политику Presence по несуществующим режимам. Вопрос дифференциации Presence/Activity по разным UiMode (Focus / Power / …) и отдельной нормативки против «вечной» анимации снят для текущей фазы: достаточно общих принципов § Presence / Dark Cockpit; вернуться к пресетам по режимам или отдельному ADR — если снова появится несколько продуктовых режимов или явная потребность.

  • Публичный enum / контракт по расширенному набору примитивов (в т.ч. Readout, Trend, Gauge, Stack, Caption, Presence/Activity) и где ровно граница с произвольной отрисовкой инструмента и с § примитив vs инструмент — оставить на фазу перед плагинами и публичной поверхностью; сейчас достаточно таксономии в этом ADR и внутренних типов по мере надобности.

Последствия

  • Вопрос «вводить ли ContentRepresentation в код» считается снятым по смыслу ADR: канон имени оси формы — ContentRepresentation; IdeHealthUiSurface — текущая привязка IDE Health; обобщение на другие каналы данных — та же ось формы, не «вторая ось канала» — см. §.
  • Вопрос «deck в пресетах vs только внутри композитора» закрыт эволюционно: сначала внутренний чертёж; декларативные именованные колоды — позже и отдельным контрактом; локальный эксперимент допустим — см. §.
  • Связка ContentRepresentation.Page + instrument deck зафиксирована как образ одного экрана с несколькими приборами (PFD); узкий случай IDE Health — см. §. Сочетание intent и deck — см. §.
  • MFD: навигация между страницами оболочки (MfdShellPage) и deck внутри страницы разведены нормативно — см. § deck страницы MFD; декларативные пресеты каталога страниц Mfd отложены в той же логике, что § deck в пресетах.
  • Документация и ADR, где фигурирует «страница» в смысле композиции инструментов, могут со временем сослаться на этот ADR и уточнить, речь о deck или о IDE Health Page.
  • Реализация композиции в слоте (сетка на Page, вкладки, порядок) получает стабильное имя для обсуждения и тестов без смешения с маршрутизацией 0050.
  • Появляется общий словарь для компактных deck-экранов: какие виды индикаторов допустимы в ячейке, не смешивая с формой канала (Strip/Page) и с deck как списком инструментов.
  • Зафиксировано правило: примитив = атомарный glance, инструмент = сценарий с состоянием — см. §.
  • Зафиксировано: CDS не есть presentation UI; граница с топологией дисплеев и со deck — см. §. Направление снятия путаницы presentation (ключи display.screens, topology) — нормативно 0017 §.
  • На фазе только Flight вопрос отдельной политики Presence/Activity по UiMode не ставится (см. § открытые вопросы); при возврате мультирежимности — заново по необходимости.

История изменений

Дата Изменение
§ CDS не presentation.
§ ContentRepresentation и код — вопрос про enum закрыт формулировкой ADR.
§ Page + deck — один экран региона, несколько инструментов (образ PFD).
§ deck в пресетах — эволюционно, без обязательной сущности в TOML на старте.
§ примитив vs инструмент.
§ типы индикаторов — направление Lamp / Bar / Sign для компактных deck-страниц.
ключи топологии дисплеев / display.screens — нормативно 0017 §.
расширенная таксономия примитивов + § Presence и Dark Cockpit.
статический Presence по геометрии — Lamp/Sign, не отдельный примитив.
то же по смыслу, что неформальное имя CompositionPage (см. § синоним).
2026-04-18 согласовано: instrument deck остаётся отдельной осью (композиция инструментов / порядок во вкладках и т.д.), ортогонально оси ContentRepresentation (Strip/Page).
2026-04-24 § deck страницы MFD: композиция внутри одной страницы оболочки Mfd, ортогонально навигации между MfdShellPage.