ADR 0046: Cockpit CDS — policy раскладки (CockpitPresentationLayoutPolicy) и инварианты P/F/M¶
Статус: Accepted · Implemented
Дата: 2026-04-14
Связанные ADR¶
| ADR | Роль |
|---|---|
| 0017 | presentation, мультиоконность |
| 0021 | Модель внимания PFD/MFD |
| 0044 | UI не источник истины по смыслу |
| 0047 | Instrument, слоты |
| 0036 | CDS → композитор → поверхность |
Снимок реализации¶
| Элемент | Значение |
|---|---|
| — | инварианты P/F/M и coercion intent в VM; CockpitPresentationLayoutPolicy / CASCOPE003 — см. § «Решение» |
Контекст¶
presentation в settings.toml задает не только декоративную геометрию, а семантическую раскладку кабины: где находятся PFD, Forward и MFD.
Проблема до фиксации правил:
- разные входы (меню, MCP, смена UI-режима, реактивные изменения) по-разному меняли видимость панелей;
- можно было получить состояние, которое противоречит якорям первого экрана;
- закрытие
MfdHostWindowвизуально влияло на раскладку так, будто пресет изменился.
Это ломало модель "кабины": пользователь видел "плавающий UI", а не устойчивую схему P/F/M.
Решение¶
- Канон правил размещается в слое CDS:
CockpitPresentationLayoutPolicy(CascadeIDE.Cockpit.Cds). - Источник правды для правил — разобранный
PresentationParseResult(первый экран). СтатическийPresentationLayoutAuthorityизServices/Presentationснят; на границе shell остаётся только тонкая запись intent (частичныйMainWindowViewModel, методыApply*— семантика «хочу», не дублирование policy). - Для первого экрана действуют инварианты:
- если есть якорь
P, нельзя скрыть левую колонку (IsSolutionExplorerVisible); - если есть якорь
M, нельзя свернуть правую колонку MFD в ноль (IsChatPanelExpanded = false); Forwardтрактуется как обязательная центральная зона; отдельный explicit toggle для отключения forward не вводится.- Любой путь изменения раскладки должен проходить через coercion policy; отображение колонок main grid — через композитор поверхности (
MainWindowShellSurfaceCompositor, ADR 0036 п.3): - relay-команды;
- MCP-команды видимости;
- применение UI-режима;
- reactive-callbacks свойств, чтобы перехватывать прямые присваивания.
- Закрытие/открытие второго
TopLevel(MfdHostWindow) меняет только surface размещения M-контента, но не пересчитывает семантикуpresentation.
Последствия¶
- Поведение UI, MCP и режимов становится детерминированным и согласованным.
- "Невозможные" состояния не накапливаются: policy возвращает их в валидную область.
- Любые новые команды, влияющие на P/F/M, обязаны согласовываться с той же coercion policy в CDS и не обходить композитор поверхности.
- На сборке: Roslyn CASCOPE003 (
CascadeIDE.ArchitectureAnalyzers) — прямые присваиванияIsSolutionExplorerVisible/IsChatPanelExpanded(и бэкинг-полей) вне белого списка файлов; новые точки — черезApply*/ расширение списка в анализаторе.
Отклоненные альтернативы¶
- Разрешить каждому входу (меню/MCP/режим) иметь собственные правила: приводит к дрейфу логики.
- Считать
presentationтолько "подсказкой layout", а не инвариантом: противоречит модели кабины. - Чинить только UI-команды, без реактивного coercion: прямые присваивания все равно обходят правила.