| 1 | # P/F/M: геометрия зон и Skia-волны (1–3) |
| 2 | |
| 3 | **Статус:** Wave 1–2 — в продукте как основа и опциональный отладочный слой; Wave 3 — *in progress* (mount-инструмент и style). |
| 4 | |
| 5 | Один сюжет: от **топологии зон** из строки презентации до **Skia-слоя** с контентом инструмента — без смешивания с «мультиоконностью как таковой» (это [ADR 0017](../adr/0017-multi-window-workspace-and-agent-surfaces.md)) и без дублирования [черновика про оверлеи vs поверхности](../design/skia-surfaces-vs-overlays-v1.md). |
| 6 | |
| 7 | --- |
| 8 | |
| 9 | ## Обзор волн |
| 10 | |
| 11 | | Волна | Что даёт | Ключи / точки входа | Примечание | |
| 12 | |-------|-----------|---------------------|------------| |
| 13 | | **1** | Топология колонок **P / Forward / M** на главном окне: видимость регионов, ширины, связь с пресетом и хостом MFD | `[display].presentation` / `zone_screen_layout`, грамматика `[presentation_grammar]`, разбор в `PresentationParser`, колонки `MainGrid` через `PresentationMainGridColumnDefinitions` и композитор shell | Источник истины — **ADR 0017**; Skia здесь **не обязателен** — это Avalonia-layout и модель намерений (expand/collapse регионов). | |
| 14 | | **2** | **Отладочные контуры** зон поверх текущего layout — проверить геометрию без смены контента слотов | `[display].show_skia_zone_geometry_overlay` → `DisplaySettings.ShowSkiaZoneGeometryOverlay`, привязки `IsSkiaZoneGeometryOverlayPfdVisible` и т.д., оверлеи `SkiaZoneGeometryOverlayPfd` / `Forward` / `Mfd` в `MainWindow.axaml`, аналог в `MfdHostWindow.axaml` | Включено временно для валидации; по умолчанию выключено. | |
| 15 | | **3** | **Mount-слой** инструмента (контент карточки и т.п.) в зоне **поверх** базового контента слота, плюс декларативный style/registry | `[display].use_skia_instrument_mount`, `instrument_mount_style`, `[[display.instrument_mount_style_rules]]` — см. раздел ниже | Ортогонально карте «какой `instrument_id` в слоте» ([ADR 0050](../adr/0050-declarative-instrument-zone-placement-toml.md)). | |
| 16 | |
| 17 | Волны **накладываются**: 1 задаёт *где* рамки зон; 2 — *нарисовать рамки для глаз*; 3 — *что показать в mount поверх* при уже разрешённой геометрии. |
| 18 | |
| 19 | --- |
| 20 | |
| 21 | ## Волна 1 — топология зон (без Skia-инструмента) |
| 22 | |
| 23 | - Строка **`presentation`** (и синоним `zone_screen_layout`) задаёт **сколько групп экранов** и **какие якоря** в каждой; парсер и инварианты — ADR 0017, код: `Services/Presentation/PresentationParser.cs`, `PresentationMainGridColumnDefinitions`. |
| 24 | - **Композитор shell** (`MainWindowShellSurfaceCompositor` и связанный ввод) определяет, **видны ли** колонки PFD / Forward / MFD в `MainGrid`, ширины MFD и т.д. — это *intent геометрии*, не CDS и не mount. |
| 25 | - Топология **main + отдельный MFD-хост** (`AttentionLayoutSurfaceKind`, подавление колонки MFD в main при открытом `MfdHostWindow`) — всё ещё волна 1, см. ADR 0017 §про хост. |
| 26 | |
| 27 | --- |
| 28 | |
| 29 | ## Волна 2 — overlay контуров зон (отладка геометрии) |
| 30 | |
| 31 | - Назначение: **визуально сверить** границы P/F/M с моделью презентации**, не меняя** привязанный к слотам контент. |
| 32 | - Реализация: полупрозрачные **Border**-оверлеи и флаги видимости из VM (`ShowSkiaZoneGeometryOverlay`, `IsSkiaZoneGeometryOverlay*`). |
| 33 | - Не путать с **волной 3**: контуры — только рамки; mount — данные инструмента (IDE Health и т.д.). |
| 34 | |
| 35 | --- |
| 36 | |
| 37 | ## Волна 3 — mount-инструмент и style (*реализовано / in progress*) |
| 38 | |
| 39 | ### Цель волны 3 |
| 40 | |
| 41 | Перенос не только геометрии shell, но и **содержимого инструмента** в управляемый mount-слой (Skia-style пайплайн и общий host), с **минимально безопасным** шагом и фичей по умолчанию выключенной. |
| 42 | |
| 43 | ### Реализовано |
| 44 | |
| 45 | 1. Первый реальный **instrument-content** в mount-слое: |
| 46 | - `Views/MainWindow.axaml` |
| 47 | - компактная PFD-карта на живых данных VM (`build/tests/debug/safety`). |
| 48 | 2. Интеграция в PFD зону: |
| 49 | - `Views/MainWindow.axaml` |
| 50 | - overlay поверх текущего контента (`SolutionExplorerView`), без замены базовой панели. |
| 51 | 3. Флаг в пользовательских настройках: |
| 52 | - `[display].use_skia_instrument_mount` |
| 53 | - модель: `DisplaySettings`, прокси в VM: `UseSkiaInstrumentMount`. |
| 54 | 4. Второй реальный mini-instrument в mount-слое для MFD: |
| 55 | - `Views/MfdHostWindow.axaml` |
| 56 | - компактная MFD-карта на тех же живых данных VM для проверки паритета отдельного MFD-хоста. |
| 57 | 5. Единый **mount-layer host**: |
| 58 | - `Views/ZoneInstrumentMountView.axaml(.cs)` |
| 59 | - PFD и MFD монтируют один и тот же host-control с параметрами темы. |
| 60 | 6. Декларативный выбор mini-инструмента: |
| 61 | - `instrument_id` + `slot_id` + `mount_style` в `ZoneInstrumentMountView`. |
| 62 | - `Views/MainWindow.axaml` и `Views/MfdHostWindow.axaml` передают декларативные параметры. |
| 63 | - `ZoneInstrumentMountPolicy` резолвит скин/заголовок по style (`instrument_mount_v1`) и slot. |
| 64 | 7. Источник `mount_style` в настройках: |
| 65 | - `[display].instrument_mount_style` |
| 66 | - VM-proxy: `MainWindowViewModel.InstrumentMountStyle` |
| 67 | - `MainWindow` и `MfdHostWindow` bind-ят `MountStyle` из VM. |
| 68 | 8. Style-registry: |
| 69 | - `[[display.instrument_mount_style_rules]]` c полями `surface_id`, `slot_id`, `instrument_id`, `mount_style`. |
| 70 | - резолв в VM: `ResolveInstrumentMountStyle(surface_id, slot_id, instrument_id)` с приоритетом поверхности, затем global `*`, внутри слоя: `exact -> slot/* -> */instrument -> */* -> fallback`. |
| 71 | - `MainWindow`/`MfdHostWindow` bind-ят slot-specific style (`PfdInstrumentMountStyle`, `MfdInstrumentMountStyle`). |
| 72 | 9. Резолв style: **Strategy + Specification**: |
| 73 | - `IInstrumentMountPolicyResolver` + `SettingsBackedInstrumentMountPolicyResolver`. |
| 74 | - `InstrumentMountPolicyRuleMatchesSpecification`. |
| 75 | 10. Eligibility-gate для rollout по метрикам: |
| 76 | - `RolloutMetricsEligibilitySpecification` и поля `[display]` (`enforce_instrument_mount_style_eligibility`, score-пороги, `require_instrument_mount_style_scores`). |
| 77 | 11. Placement-spec для host-surface: |
| 78 | - `InstrumentPlacementSpecification` + `CockpitInstrumentPlacementRules`. |
| 79 | - `MainWindowHostSurfaceCompositor` монтирует инструмент только при прохождении placement-rule. |
| 80 | 12. Валидация конфигурации: |
| 81 | - `DisplaySettingsValidationSpecification` при `SettingsService.Load()`. |
| 82 | |
| 83 | ### Принцип rollout (волна 3) |
| 84 | |
| 85 | - Не ломаем текущий UX: mount **поверх** существующего содержимого слота. |
| 86 | - Фича **выключена по умолчанию** (`use_skia_instrument_mount`). |
| 87 | - Цель итерации — отладить pipeline контентного overlay на реальных данных, не ломая маршрутизацию инструментов в shell. |
| 88 | |
| 89 | ### Следующий шаг (волна 3) |
| 90 | |
| 91 | 1. Перевести content-binding с фиксированных VM-полей на декларативный контракт payload (через `instrument_id` и typed data-source), чтобы mount не знал про конкретные поля `IdeHealth*`. |
| 92 | 2. Перенести resolver из VM в отдельный surface/style service рядом с `CockpitInstrumentDescriptor`, а не только в UI binding. |
| 93 | |
| 94 | --- |
| 95 | |
| 96 | ## История файла |
| 97 | |
| 98 | | Было | Стало | |
| 99 | |------|--------| |
| 100 | | `pfm-zone-geometry-wave3.md` (только волна 3) | Этот документ: **волны 1–3** в одном месте, чтобы не плодить три черновика по одной оси. | |
| 101 | |