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 — ортогонально навигации между страницами.
Контекст¶
В разговоре о кокпите раньше смешивались две оси:
- Форма представления — как показать контент в разметке: полоса (Strip), блок «страницы» региона (Page), компактный индикатор и т.д.
- Композиционная единица — что и в каком порядке: набор инструментов / сегментов канала / индикаторов (вкладки, стек, split, порядок в композиторе).
В текущем продукте DedicatedPage / bottom_strip в пресете канала IDE Health (ide_health_surface → IdeHealthUiSurface.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_strip ↔ Strip, dedicated_page ↔ Page. В коде — 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, для оси B — deck / колода / композиция слота. Для 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.
Как согласовать:
- Номинал / нет активной работы — Presence приглушён, статичен или скрыт (как «невидимый» хром, пока нечего говорить оператору). Не декоративный pulse «мы онлайн».
- Идёт значимая работа (сборка, долгий MCP, блокирующая операция) — Activity допустим как кратковременный или привязанный к реальному прогрессу сигнал; предпочтительнее устойчивое состояние (Lamp «busy») или Bar/Trend с реальной динамикой, чем бесконечный спиннер без семантики.
- Отклонение от штатного — уводить в иерархию W/C/A и канал EICAS (0021 §5), а не размножать «живые» пиксели в deck: эскалация заметна, штат — тихо.
- Развести семантику: статический 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. |