ADR 0103: субстрат Editor HUD — семантическая проекция, адаптер поверхности, границы DAL / CCU / DataBus¶
Статус: Accepted (strangler)
Дата: 2026-04-26
Связанные ADR¶
| ADR | Роль |
|---|---|
| 0006 | Слои, вертикальные срезы и роль MainWindowViewModel |
| 0009 | Strangler-миграция и когда допускаются отклонения от политики |
| 0021 | PFD / MFD — модель внимания кокпита Cascade IDE |
| 0032 | HUD над редактором — настраиваемое содержимое и грамматика (как у presentation) |
| 0035 | Встроенный браузер в MFD, внешние веб-LLM и граница с MCP |
| 0036 | Канал → CDS → композитор поверхности → поверхность (Agent-first отображение) |
| 0039 | Навигация по workspace — несколько представлений и «текущий файл + связанные» |
| 0066 | Cockpit UI и слой presentation IDE — раздельные опоры |
| 0067 | Graph-backed surfaces — общий контракт для семейства графовых экранов |
| 0084 | Правки агента в редакторе как единственный текстовый источник правды; чат — намерение и статус; слой присутствия (GDocs-like, без обязательного CRDT) |
| 0085 | Editor HUD — inline-слой в редакторе и отличие от HUD banner |
| 0094 | Шина доставки событий в UI (аналогия AFDX) и System.Threading.Channel<T> |
| 0097 | Вычислительные блоки кабины (CCU; аналог LRU Unit) — слой между транспортом, смыслом и каналом |
| 0098 | Семантика первична; документ и репозиторий — проекции (Semantic-First) |
| 0099 | IDE DataBus — типизированные события и проекции состояния |
| 0102 | Data Acquisition Layer — граница внешних интерфейсов и адаптеров |
Резюме¶
- Субстрат Editor HUD:
SemanticProjectionPipeline/EditorHudEngine/IEditorSurfaceAdapter. - DAL / CCU / DataBus; hi-freq bounded-контур отдельно от CDS.
- Baseline AvaloniaEdit; roadmap UI в
ui-ux/, сравнение хостов вdesign/.
Вне ADR¶
| Документ | Роль |
|---|---|
| чертеж: data-acquisition-layer-boundaries-v1 | чертеж: data-acquisition-layer-boundaries-v1 |
| чертеж: сравнение кандидатов поверхности редактора | чертеж: сравнение кандидатов поверхности редактора |
| чертеж: analyzer-rollout-dal-ccu-v1 | чертеж: analyzer-rollout-dal-ccu-v1 |
| ux: roadmap полировки Forward | ux: roadmap полировки Forward |
Состояние реализации (v1 слоя «закрыт» в пределах strangler): Features/Editor — IEditorSurfaceAdapter / AvaloniaEditSurfaceAdapter, hi-freq EditorStabilizedInputThrottler (один на окно) + EditorInputDelta → guard по CurrentFilePath → EditorDocumentHudLayer (per document: EditorHudEngine + EditorHudStabilizedContext) → SemanticProjectionPipeline / EditorSemanticSnapshot из DAL-полосок; презентация file-level HUD banner в Application/Presentation/EditorHudBannerTextComposer (0085: не путать с EditorInlineHudLayer-зарезервированным inline); VM только оркестрирует Roslyn-вхождения и присваивает EditorHudBannerText, при DiagnosticsChanged снимок инвалидируется. Вне v1: перенос inline-рендера (squiggles, tooltips) из DockDocumentView в тот же слой данных — editor-hud-inline-migration-inventory-v1, политика баннер/inline — editor-hud-banner-inline-policy-v1, визуальная политика MFD/Forward — editor-forward-ui-cleanup-roadmap-v1. |
1. Контекст¶
DockDocumentView и связанные view models уже реализуют фрагменты Editor HUD (adorners, LSP, всплывающие подсказки) и HUD banner в духе 0085, но inline-опыт не оформлен как единый именованный субстрат: контракты Quick Info, inlays, ghost text, gutter разбросаны. Параллельно в стеке закреплены явные слои — CCU 0097, DAL 0102, IDE DataBus 0099, ingestion 0094 — и направление semantic-first 0098.
Без единого ADR новая работа по HUD рискует:
- свалить LSP I/O и чтение файлов в view models или в CCU (конфликт с 0102 и analyzer-rollout-dal-ccu-v1);
- публиковать трафик «на каждую клавишу» в DataBus (конфликт с 0099: типизированные события домена, а не поток high-frequency ввода);
- смешать транспорт (0094) с прикладными событиями и ad-hoc свёрткой в UI.
2. Решение¶
2.1 Имя субстрата: три согласованных контура¶
-
SemanticProjectionPipeline— агрегирует нормализованные сущности для зоны Forward-редактора: диагностики, полезная нагрузка hover, контекст символа/связей, флаги присутствия агента, метаданные версии/актуальности. Не владеет долгосрочно LSP stdio, сырым JSON как «домом» и UX раскладки графа (0067 остаётся на graph-backed surfaces). -
EditorHudEngine— политика и композиция: что показывать inline, что в HUD banner, что отдать PFD/MFD 0036 / 0039. Потребляет стабилизованные или прореженные (throttle) входы, а не неограниченный «шум на символ». -
IEditorSurfaceAdapter(или эквивалентное имя) — граница реализации фактического текстового контрола: основной baseline в этом репозитории остаётся AvaloniaEdit (см. concept-to-implementation-map-v1, LANGUAGE-SERVICES-PLAN.md). Адаптер отдаёт координаты документа, каретку, selection и affordances хоста, нужные движку HUD, без размазывания типов редактора по приложению.
Термины 0085 не меняются: Editor HUD = inline + привязка к документу; HUD banner = полоса уровня файла; IDS = глобальные оверлеи IDE, не Editor HUD 0066.
2.2 Раскладка: DAL, CCU, DataBus, high-frequency¶
| Вопрос | Слой | Примечание |
|---|---|---|
| LSP stdio, чтение файла/настроек, запуск процессов | DAL 0102 в Features/*/DataAcquisition |
Не CCU, не «толстый» MainWindowViewModel 0006 |
Осмысленные снимки Editor HUD / Forward (дедуп, приоритет error > warn, DocumentId + диапазоны, версия) |
CCU 0097 и/или оркестраторы Features/.../Application |
кандидаты имён, например EditorSemanticSnapshot / ForwardHudSnapshot |
Сессия и после debounce факты домена (CSharpLspRestarted, ActiveDocumentChanged, сценарий вроде «диагностики стабилизировались») |
IDE DataBus 0099 | Не на каждое нажатие клавиши |
| Каретка, указатель, скролл в масштабе кадра/клавиш | Отдельный in-process путь: например System.Threading.Channels ёмкость 1 + BoundedChannelFullMode.DropOldest (или SPSC latest slot) |
Не второй глобальный «продуктовый bus»; не подмена 0094 как сквозного транспорта. Один consumer прореживает и при необходимости публикует реже в DataBus / входы CCU. |
| Ingestion / потоки «как лог» в UI | 0094 | Ортогонально DataBus 0099 |
2.3 Веб-стек и нативный редактор Forward¶
- WebView2 в хосте Avalonia/Win32 не равен «втаскиваем Electron» (нет оболочки Chromium+Node как приложения). Иная ведомость: встроенный рендерер, interop, доверие.
- Продуктовый baseline для редактора кода во Forward остаётся нативный (AvaloniaEdit). Monaco в WebView2 (и аналоги) не молчаливый default: сравнение / отклонён для Forward по политике продукта; см. editor-surface-candidates-comparison-v1.
- Опциональные веб-поверхности MFD — по 0035 / 0093; вторичные инструменты, не тезис «редактор = браузер».
2.4 Инварианты (не ломать)¶
- 0084: при применении правок агента буфер редактора — источник применяемой правды; чат — намерение/статус; канал присутствия отдельно.
- 0085: не сливать inline Editor HUD и HUD banner в одном контроле без явных имён.
- 0098: ведущими остаются семантические пути PFD/MFD; подсказки редактора не забирают на себя всю навигацию.
- 0097 / 0102: CASCOPE020/021 и rollout analyzer-rollout-dal-ccu-v1 как «шлагбаум» границы.
2.5 Критерии выбора ядра редактора (для чертежа-аппендикса / будущего спайка)¶
- Inline hints, ghost text, inlays, gutter; rich hover / Quick Info; производительность на больших буферах; согласованность темы; API указателя/каретки/документа; интеграция с semantic-first кокпитом 0039.
3. Strangler / миграция¶
- Отвязать презентацию HUD от ad-hoc деталей
DockDocumentView: ввести три контура выше без big-bang заменыAvaloniaEdit. - Спайк (по умолчанию):
AvaloniaEditSurfaceAdapter+ bounded high-frequency путь + один срезSemanticProjectionPipeline/EditorHudEngine(например диагностики + одна ветка hover). Подробнее — §5 — объём spike. - Второй адаптер хоста (например веб) — только при явном принятии риска веб-стека во Forward; для первого спайка не обязателен.
- После стабилизации — при необходимости graph-backed surfaces 0067 для навигации, которой не место в текстовом хосте.
4. Не цели (v1 этого ADR)¶
- Фиксировать окончательные имена типов и расклад папок (strangler: интерфейсы рядом с
Features/Editorили по согласованию в реализации). - Подменять CDS 0036 или переопределять канал в смысле кокпита.
- Внешние message broker’ы или сведение всех потоков в один envelope.
5. Объём technical spike (по умолчанию)¶
| Пункт | Объём |
|---|---|
| Адаптер | IEditorSurfaceAdapter для AvaloniaEdit; сопоставление каретки/selection/смещений в документе для одного типа документа (например C#) |
| Hi-freq | Продюсер(ы) на событиях редактора → Channel<EditorInputDelta> (ёмкость 1, drop-oldest) → один consumer с throttle (например 16–50 ms) до касаний CCU/DataBus |
| Пайплайн | Один вертикальный срез: LSP/диагностики из DAL → снимок в духе CCU или тонкий оркестратор в Application → EditorHudEngine → адаптер |
| Вне спайка | полный адаптер Monaco/WebView2; полный охват CASCOPE по всем типам HUD |
Критерии успеха: нет нового LSP I/O в Cockpit/ComputingUnits/*; нет неограниченного per-key Publish на IDataBus; баннер vs inline 0085 остаётся явным.
6. Сопутствующие документы¶
- Сравнение хостов (аппендикс): editor-surface-candidates-comparison-v1
- Roadmap полировки UI (Forward, баннер, всплывающие подсказки, MFD): editor-forward-ui-cleanup-roadmap-v1
7. Последствия¶
- Плюс: единая точка расширения Quick Info, inlays, gutter без запутывания DAL, DataBus и сырых событий редактора; согласование с 0097/0102/0099/0094.
- Минус: предварительная проработка дизайна и адаптера до каждой косметической правки; дисциплина, чтобы hi-freq не уезжал в DataBus.
- Риск при игнорировании: возврат к god-
MainWindowViewModel, event spaghetti на DataBus, нарушения CASCOPE между DAL и CCU.