Forge
markdowndeeb25a2
1# ADR 0037: PFD — инварианты поверхности и проверка Roslyn (weight, input lock, каналы)
2
3**Статус:** Proposed
4**Дата:** 2026-04-12
5**Обновлено:** 2026-04-16 — [канон имён](#adr0037-naming) для строгой поверхности: `[PfdStrict]`, `PfdStrictControl`. Подробности — [§ История](#adr0037-history).
6## Связанные ADR
7
8| ADR | Роль |
9|-----|------|
10| [0021](0021-pfd-mfd-cockpit-attention-model.md) | зона PFD в модели внимания |
11| [0036](0036-cds-channel-compositor-surface-pipeline.md) | канал → CDS → композитор → поверхность |
12| [0025](0025-sdk-attention-zones-and-capabilities.md) | capabilities и зоны |
13| [0039](0039-workspace-navigation-affordances.md) | формы навигации в зоне внимания |
14
15## Резюме
16
17- **PFD strict surface:** инварианты weight/input lock; Roslyn-анализаторы.
18- Канон **`[PfdStrict]`** / `PfdStrictControl` — география зоны vs строгая поверхность ([0021](0021-pfd-mfd-cockpit-attention-model.md#adr0037-zone-vs-surface)).
19
20### Вне ADR
21
22| Документ | Роль |
23|----------|------|
24| [`CascadeIDE.ArchitectureAnalyzers/README.md`](../CascadeIDE.ArchitectureAnalyzers/README.md) | CASCOPE*; расширение — по этому ADR |
25
26---
27## Контекст
28
29В авиационной метафоре **PFD** — первичный «прибор»: плотная, авторитетная картина контекста без охоты по вкладкам ([0021](0021-pfd-mfd-cockpit-attention-model.md)). На уровне **чистого кода** Roslyn **не знает**, «лёгкий» ли виджет: тяжесть — это политика продукта, а не свойство IL.
30
31Чтобы **формализовать** дисциплину PFD в коде, нужны **явные контракты** (атрибуты, базовые типы, узкие интерфейсы подписок на каналы). Тогда анализаторы становятся **охранниками инвариантов**, а не эвристикой по имени класса.
32
33Уже зафиксировано: границы слоёв **канал / CDS / композитор** без Avalonia в `Cockpit/Channels`, `Cds`, `Composition` ([0036](0036-cds-channel-compositor-surface-pipeline.md), CASCOPE001/002). Этот ADR задаёт **дополнительный** слой — **именно для компонентов, декларированных как строгая PFD-поверхность** (см. раздел ниже: это **не** вся география региона PFD).
34
35<a id="adr0037-zone-vs-surface"></a>
36
37## Зона внимания и строгая поверхность (0021 vs 0037)
38
39**Две оси, которые нельзя смешивать:**
40
41| Ось | Что это | Где зафиксировано |
42|-----|---------|-------------------|
43| **Зона внимания (география экрана)** | Какой **регион** окна — якорь взгляда: лобовое, **PFD**, MFD, EICAS как канал и т.д. Что **физически** стоит слева/рядом с редактором по пресету. | [0021](0021-pfd-mfd-cockpit-attention-model.md) («Архитектура зон», якоря vs attention flow). |
44| **Строгая PFD-поверхность (инженерный контракт)** | Какой **компонент кода** добровольно берёт на себя роль «приборной части» первичного контура: только индикаторы, допустимый вес, допустимые каналы данных. | Этот ADR (§1–§3), явные маркеры в коде. |
45
46**Зачем разделять:** авиационная строгость не должна превращать IDE в аскетичный терминал, где «в регионе PFD нельзя даже кликнуть по файлу». Навигация по решению — **контекст «где я»**; если выселить её только в MFD ради формального «PFD = read-only», вырастет **налог** на переключение взгляда и контекста ([0021](0021-pfd-mfd-cockpit-attention-model.md) — переключения как цена продуктивности).
47
48**Гибридная картина («слоёный пирог»):** в **одном** регионе внимания **PFD** на экране могут сосуществовать:
49
50- **Интерактивная навигация** (например обозреватель решения, «якорь» workspace): пользователь **кликает, раскрывает узлы, выбирает файл** — это остаётся **навигационным контекстом**, а не «вторым лобовым». На эти компоненты **не** вешается обязательный маркер строгой PFD-поверхности **0037**; **Roslyn-анализатор по этому ADR их не трогает** (нет маркера — нет контракта §1–§3).
51- **Строгие PFD-surfaces** — индикаторы критического контура: статус агента, EICAS/оповещения, компактное здоровье workspace и т.п. Их помечают атрибутом **`[PfdStrict]`** и/или базовым типом **`PfdStrictControl`** ([канон имени](#adr0037-naming)). **Внутри** таких типов анализатор **запрещает** произвольный ввод, **WebView** и иные нарушения **Input Lock** и **Weight** (§1–§2): «бьёт по рукам» за лишний интерактив и тяжёлые встраивания там, где политика требует только «авионики».
52
53**Итог одной фразой для контрибьюторов:** зона внимания **PFD** может содержать **интерактивные** элементы навигации; компоненты, **явно** помеченные как строгая PFD-поверхность (**`[PfdStrict]`** или наследование от **`PfdStrictControl`**), **обязаны** соблюдать инварианты **Input Lock** и **Weight Limit** этого ADR. Анализатор действует **только** по маркеру, а не по факту «компонент нарисован слева».
54
55<a id="adr0037-glossary-pfd-dual"></a>
56
57### Глоссарий (два смысла «PFD»)
58
59| Термин | Одна строка |
60|--------|-------------|
61| **PFD как зона внимания** | Регион экрана в пресете ([0021](0021-pfd-mfd-cockpit-attention-model.md)): *где* лежит якорь «контекст полёта». Сама география **не** включает автоматически строгие инварианты 0037. |
62| **Строгая PFD-поверхность** | Компонент в коде с явным маркером [`[PfdStrict]`](#adr0037-naming) или базовым типом `PfdStrictControl`: на него распространяются §1–§3 и Roslyn. Это **не** синоним «всё, что нарисовано в колонке PFD». |
63
64**Связка для ссылок:** «лежит в зоне PFD» ≠ «подпал под контракт 0037», пока тип не помечен как строгая поверхность.
65
66**Навигация «где я в коде»:** в примерах выше фигурирует **обозреватель решения** как знакомый ориентир; это **не** требование единственной формы. Навигация по **символам**, **иерархии типов**, **хлебным крошкам**, **структуре файла** и т.п. может быть для части задач **эффективнее** классического дерева — и по-прежнему относится к **якорю «где я»** в смысле [0021](0021-pfd-mfd-cockpit-attention-model.md), а не к «приборам» [0037](0037-pfd-surface-invariants-and-roslyn-enforcement.md), пока на виджет не повешен маркер строгой поверхности. Конкретный набор инструментов и пресетов — **продуктовый** выбор; этот ADR только фиксирует развод **географии зоны** и **контракта по маркеру**. Продуктовое направление «несколько представлений и связанные файлы» — [0039](0039-workspace-navigation-affordances.md).
67
68## Решение
69
70Инварианты PFD-поверхности задаём **тремя** классами правил. Конкретные **идентификаторы диагностик**, списки запрещённых типов и **исключения** вводятся при реализации (отдельные коммиты), но **смысл** инвариантов фиксируется здесь.
71
72<a id="adr0037-naming"></a>
73
74### Канон имён для строгой поверхности (для кода в репозитории)
75
76**Принято для реализации:**
77
78| Элемент | Имя | Заметка |
79|---------|-----|---------|
80| Атрибут (использование) | **`[PfdStrict]`** | Полное имя типа в C#: **`PfdStrictAttribute`**, PascalCase; **не** `[PFD_Strict]` — так единообразнее с идиомой .NET и с остальными атрибутами в репо. |
81| Базовый тип (опционально) | **`PfdStrictControl`** | Базовый класс для Avalonia-`Control`, наследники которого считаются строгой PFD-поверхностью **без** дублирования атрибута на каждом подтипе (анализатор учитывает **атрибут на типе** или **наследование от `PfdStrictControl`** — семантика одна). |
82| Не путать с | **`PfdSurface`** | Слово «surface» в тексте ADR — про **роль** в UI; отдельного атрибута **`[PfdSurface]`** для «любой панели в зоне» не вводим: без маркера строгого контракта анализатор не применяется. |
83
84**Глоссарий в коде:** XML-доки на `PfdStrictAttribute` и `PfdStrictControl` должны ссылаться на этот ADR и кратко повторять [двойной смысл PFD](#adr0037-glossary-pfd-dual) (зона внимания ≠ автоматический контракт).
85
86<a id="adr0037-p1"></a>
87
88### 1. Контроль «веса» (Weight / dependency allowlist)
89
90**Правило:** компонент или класс представления, **явно помеченный** как **строгая** PFD-поверхность (см. [раздел выше](#adr0037-zone-vs-surface); [`[PfdStrict]`](#adr0037-naming) или базовый тип [`PfdStrictControl`](#adr0037-naming)), **не должен** напрямую использовать заведомо тяжёлые контейнеры и встраивания: например **таблицы с виртуализацией как замена смысла PFD**, **WebView**, **богатые ItemsControl** с произвольными шаблонами там, где политика требует только примитивов.
91
92**Логика:** PFD в продукте — **плотный индикатор** (текст, иконки, простые формы, компактные прогресс-индикаторы), а не вторичная рабочая область. Анализатор **не оценивает FPS**; он проверяет **запрещённые типы/пространства имён** в пределах помеченного типа и связанного AXAML (если подключается анализ `.axaml` / codegen).
93
94**Оговорка:** универсальный **`Grid`** как layout часто необходим; запрет «всего Grid» не является целью — только **конкретный список** тяжёлых типов и сценариев, согласованный с командой (белый список разрешённых контролов — опционально во второй фазе).
95
96<a id="adr0037-p2"></a>
97
98### 2. Запрет ввода (Input lock / read-only display)
99
100**Правило:** для **строгой** PFD-поверхности (по маркеру) в авиационной аналогии — **дисплей для чтения** в типичном сценарии; произвольный ввод и перехват фокуса в таком компоненте **конкурирует** с **лобовым** (редактор, терминал) и ломает модель внимания. (Навигация в регионе PFD **без** маркера — вне этого правила; см. [выше](#adr0037-zone-vs-surface).)
101
102Для **так помеченных** компонентов анализатор **должен** диагностировать явные обработчики **указателя, клавиатуры и фокуса** (например подписки на события ввода Avalonia), за исключением **явно перечисленных** исключений в политике продукта (одна кнопка подтверждения, safety — по отдельному ADR/чеклисту).
103
104**Зачем:** сохранить **строгую** PFD-поверхность **индикатором**, а не интерактивной панелью, которая отнимает ввод у первичной рабочей поверхности.
105
106<a id="adr0037-p3"></a>
107
108### 3. Ограничение графа данных (каналы / потоки)
109
110**Правило:** **строго помеченный** PFD-компонент **может** подписываться только на **разрешённые** для первичного контура потоки данных (рабочие имена: например каналы **состояния здоровья workspace**, **статуса агента**, **следующего шага** — точный перечень типов и интерфейсов фиксируется в коде и в [cds-contract-v0](../design/cds-contract-v0.md) по мере стабилизации).
111
112Подписка на потоки **вторичной** насыщенности (условно: длинная **история git**, **полное дерево решения как единственный источник данных прибора**, **полный дамп файловой системы** как основной источник **именно строгой** PFD-поверхности) считается **несоответствием роли прибора**: это контент **MFD / навигации без маркера** / боковых панелей. (Отдельно: **обозреватель решения** в регионе PFD без маркера 0037 **не** обязан ограничиваться этим списком каналов — он не претендует на роль «прибора».)
113
114**Логика:** анализатор проверяет **типы** вызовов подписки / конструкторов каналов в пределах помеченного компонента, **если** каналы выражены как **стабильные compile-time API** (интерфейсы, обобщённые фабрики). Строковые ключи DI, рефлексия и «общий» bus без типизации **вне зоны** этого ADR — там нужны обзорные тесты и ревью, а не Roslyn-only.
115
116## Последствия
117
118- Разделение **[0021](0021-pfd-mfd-cockpit-attention-model.md) (география зоны)** и **0037 (строгий контракт по маркеру)** снимает ложное противоречие «PFD интерактивен vs PFD только read-only»: интерактив допустим в регионе внимания, **строгость** — только у явно помеченных «приборов».
119- Появляется **явная** дисциплина «строгая PFD-поверхность в коде»: без маркера анализатор молчит — это **осознанный** контракт.
120- Правила **порционно** переносятся в [`CascadeIDE.ArchitectureAnalyzers`](../CascadeIDE.ArchitectureAnalyzers/README.md) (новые ID рядом с CASCOPE*) и **юнит-тесты** на диагностики по образцу существующего проекта тестов.
121- Конфликты с UX (например одна кнопка «OK» на PFD) разрешаются **списком исключений** или отдельным подтипом атрибута, не отменяя базовый инвариант.
122
123## Не цели
124
125- Сертификация авионики или полное воспроизведение **ARINC 661** / **CDS** железа.
126- Замена **человеческого** ревью дизайна: анализатор ловит **известные классы нарушений**, не «красиво/некрасиво».
127- Автоматический запрет **`Grid`** без исключений и без согласованного списка типов.
128
129## Открытые вопросы (до статуса Accepted)
130
1311. Минимальный **allowlist** разрешённых каналов для PFD v1 и маппинг на существующие `Cockpit/Channels`.
1322. Нужен ли **отдельный** анализ `.axaml` или достаточно partial-класса и codegen.
133
134**Снято с повестки именования:** канон — [`[PfdStrict]` / `PfdStrictAttribute`](#adr0037-naming) и опционально [`PfdStrictControl`](#adr0037-naming); см. таблицу в том же разделе.
135
136---
137
138## История изменений
139
140<a id="adr0037-history"></a>
141
142| Дата | Изменение |
143|------|-----------|
144| — | [глоссарий](#adr0037-glossary-pfd-dual); навигация и [0039](0039-workspace-navigation-affordances.md). |
145| — | раздел «Зона внимания vs строгая поверхность» ([0021](0021-pfd-mfd-cockpit-attention-model.md)). |
146| 2026-04-16 | [канон имён](#adr0037-naming) для строгой поверхности: `[PfdStrict]`, `PfdStrictControl`. |
147
View only · write via MCP/CIDE