Forge
markdowndeeb25a2
1# ADR 0079: IDS (Ide Display System) — пайплайн оверлеев IDE, ортогонально CDS
2
3**Статус:** Accepted
4**Дата:** 2026-04-20
5
6## Связанные ADR
7
8| ADR | Роль |
9|-----|------|
10| [0036](0036-cds-channel-compositor-surface-pipeline.md) | CDS: кабина, канал → CDS → композитор → поверхность |
11| [0066](0066-cockpit-ui-vs-ide-presentation-layer.md) | Cockpit UI vs presentation IDE: хром и оверлеи |
12| [0070](0070-command-palette-direct-overlay-surface.md) | Command Palette как прямой overlay в активном `TopLevel` |
13| [0057](0057-chat-surface-pipeline-adoption.md) | чат: композитор снимка поверхности; аналогия по слою «композиция» |
14| [0013](0013-command-surface-and-discoverability.md) | палитра и discoverability |
15| [0115](0115-cds-graph-backed-shared-layer.md) | CDS — общий слой graph-backed приборов (реализация в кабине, не IDS) |
16
17## Резюме
18
19- **IDS** — пайплайн IDE-оверлеев (intent → композитор → снимок → поверхность).
20- Ортогонально CDS [0036](0036-cds-channel-compositor-surface-pipeline.md); Roslyn CASCOPE013–016.
21
22
23---
24## Контекст
25
26[0036](0036-cds-channel-compositor-surface-pipeline.md) задаёт цепочку для **семантики кабины** (PFD/MFD/инструменты, `CockpitSurfaceState`, слоты приборов). Она **не должна** разрастаться до «всех пикселей IDE», иначе CDS станет God-слоем и смешается с [0066](0066-cockpit-ui-vs-ide-presentation-layer.md).
27
28Параллельно продукту нужны **глобальные IDE-оверлеи**: командная палитра (`Ctrl+Q`), позже — toast, блокирующие диалоги, иные «поверх всего workspace» поверхности. У них другие инварианты:
29
30- привязка к **активному `TopLevel`** и возврат фокуса ([0070](0070-command-palette-direct-overlay-surface.md));
31- **keyboard-first** и предсказуемый перехват ввода;
32- по возможности — **снимки** для тестов и наблюдаемости агента без привязки к конкретному дереву `Control`.
33
34Без явного имени и границ этот контур расползается по `Views/*` и `*ViewModel`, дублируя логику «кто сверху» и «кто ест клавиши».
35
36---
37
38## Решение
39
40Вводится отдельный продуктовый контур **IDS — Ide Display System** (неймспейс и типы в коде: `CascadeIDE.IdeDisplay.*`).
41
42### 1. Назначение IDS
43
44**IDS** описывает **presentation IDE** для **модальных и полумодальных оверлеев** (и в перспективе — других IDE-surfaces, которые не являются приборами кабины): отделение **данных/намерения** и **композиции снимка** от конкретного рендера (Avalonia `Control`, Skia-хост, гибрид).
45
46**CDS** остаётся каноном **кабины**; **IDS** — канон **оверлеев IDE**. Смешивать семантику слотов кабины и стек IDE-оверлеев в одном типе — анти-паттерн; при необходимости общ only на уровне слов «канал / композитор / снимок», не на уровне одного DTO.
47
48<a id="adr0079-cds-vs-ids"></a>
49
50### Различение CDS и IDS (одно приложение, два домена)
51
52Оба контура выполняются **внутри одного процесса** CascadeIDE (географически «всё это IDE»). Путаница снимается вопросом **домена смысла**, а не exe-файла:
53
54| | **CDS (и кабина вокруг него)** | **IDS** |
55| --- | --- | --- |
56| **Вопрос** | Куда в **модели внимания кабины** попадает содержимое: PFD / Forward / MFD, слот прибора, страница вторичного контура? | Как показать **оверлей оболочки** поверх workspace: палитра, модалка, toast; фокус, z-order, перехват ввода? |
57| **Типичный тест** | «На какой странице MFD / в какой зоне deck / в каком слоте прибора?» | «Модально поверх всего окна, как в обычном приложении, без семантики прибора?» |
58| **Норматив** | [0036](0036-cds-channel-compositor-surface-pipeline.md), [0021](0021-pfd-mfd-cockpit-attention-model.md) | этот ADR, [0070](0070-command-palette-direct-overlay-surface.md) |
59| **Слои «прибор vs хром»** | Семантика **приборов и зон** ([0036](0036-cds-channel-compositor-surface-pipeline.md)) | **Не-приборный** presentation shell ([0066](0066-cockpit-ui-vs-ide-presentation-layer.md)) |
60
61**Мнемоника:** решаешь «**куда в кабине**» → **CDS**; «**глобально поверх workspace**, не слот прибора» → **IDS**. Границу закрепляет **CASCOPE016**: `Cockpit/` не импортирует `IdeDisplay`.
62
63### 2. Та же дисциплина цепочки, что у 0036 (по смыслу, не по типам)
64
65Для каждого оверлея в IDS соблюдается цепочка:
66
671. **Канал / состояние** — что пользователь ввёл, что отфильтровано, какой режим (команды / go-to / melody), без координат пикселей.
682. **Композитор поверхности** — чистая функция (или близко): из канала строит **снимок** для рендера и навигации (строки, выделение, подсказки, opacity).
693. **Поверхность** — Avalonia/Skia: фокус, hit-test, анимации; не источник семантики оверлея.
70
71Обобщающий контракт композиторов: `IIdsSurfaceCompositor<TIntent, TSnapshot>` с методом `TSnapshot Compose(TIntent intent)` (параметр **без** `in` при контравариантном `TIntent` — ограничение языка C#).
72
73### 3. Единый хост ввода (input capture)
74
75Инвариант **направления**: перехват клавиатуры/фокуса для **стека оверлеев IDE** сходится к **одному месту** — условный **`IdsOverlayHost`** / **input router** на корне активного host, а не к разрозненным `PreviewKeyDown` в каждом оверлее без политики.
76
77На момент принятия ADR полная реализация хоста может быть **strangler**; палитра может временно оставаться self-contained ([0070](0070-command-palette-direct-overlay-surface.md)), но **новые** оверлеи не должны добавлять третий независимый «глобальный перехват» без явного согласования в этом ADR или отдельном ADR.
78
79### 4. Слоты (`SurfaceSlot`) — опционально
80
81**`SurfaceSlot` (или `IdsSurfaceSlot`)** вводится, когда появляется **несколько** одновременно конкурирующих IDS-поверхностей или нужен явный **z-order / mount id** для наблюдаемости и тестов.
82
83Для **одной** палитры как единственного верхнего оверлея слот не обязателен. Для «палитра + toast + блокирующий диалог» — слот или эквивалентный **стек** становится частью IDS-хоста.
84
85Именование: по умолчанию **`Ids*`** в коде, чтобы не путать с **`CockpitInstrumentDescriptor`** и слотами CDS ([0047](0047-cockpit-instrument-descriptor-and-slot-composition.md)).
86
87### 5. Наблюдаемость агента
88
89Снимки IDS (например, состав строк палитры и выбранный индекс) могут поставляться в MCP/контракт агента **отдельно** от `cockpit_surface`, либо тонким полем «overlay» в общей сводке — решение по полю JSON не фиксирует этот ADR; фиксируется только **разделение семантики** CDS vs IDS.
90
91### 6. Roslyn-guardrails (CASCOPE013–016)
92
93На сборке [`CascadeIDE.ArchitectureAnalyzers`](../../CascadeIDE.ArchitectureAnalyzers/README.md):
94
95- **CASCOPE013** / **CASCOPE014** / **CASCOPE015** — в каталоге `IdeDisplay/` запрещены зависимости от `CascadeIDE.Cockpit…`, от Avalonia UI и от `CascadeIDE.Features.UiChrome` (в т.ч. типы в членах классов в `CascadeIDE.IdeDisplay.*`).
96- **CASCOPE016** — в `Cockpit/` запрещён `using CascadeIDE.IdeDisplay…` (кабина не тянет IDS).
97
98Полные формулировки и уровни — в README анализаторов.
99
100---
101
102## Состояние реализации (фиксация на дату ADR)
103
104- **Сделано:** контракт `IIdsSurfaceCompositor<TIntent, TSnapshot>`; для палитры — `CommandPaletteSurfaceIntent`, `CommandPaletteSurfaceSnapshot`, `CommandPaletteSurfaceCompositor`; обновление снимка из `MainWindowViewModel` при открытой палитре; тесты композитора; Roslyn **CASCOPE013–016** (см. §6).
105- **По плану (strangler):** единый `IdsOverlayHost` / router ввода; опциональные `IdsSurfaceSlot` при втором оверлее; при необходимости — проекция в MCP без смешения с CDS.
106
107---
108
109## Последствия
110
111- Новые IDE-оверлеи по умолчанию проектируются через **IDS** (intent → compositor → snapshot → surface), а не «сразу в AXAML логикой наполовину в VM».
112- CDS и реестр приборов кабины **не раздуваются** ответственностью за глобальные IDE-модалки.
113- Тесты могут опираться на **снимок IDS** там, где важна семантика списка/выбора, без хрупкой привязки к визуальному дереву.
114
115## Не цели
116
117- Замена Avalonia как host для оверлеев.
118- Переименование или перепрофилирование **CDS** под IDE-chrome.
119- Полная спецификация JSON для агента в этом ADR.
120
121## Отклонённые альтернативы (кратко)
122
123- **Всё в CDS:** отклонено — смешивает кабину и IDE-shell, ломает [0066](0066-cockpit-ui-vs-ide-presentation-layer.md).
124- **Отдельный ADR на каждый оверлей без общего IDS-имени:** допустимо как временная мера, но ведёт к дублированию политики input/stack.
125
View only · write via MCP/CIDE