Forge
markdowndeeb25a2
1# ADR 0024: SDK для CascadeIDE — стабильные контракты для внутреннего расширения и будущих плагинов
2
3**Статус:** Proposed
4**Дата:** 2026-04-08
5
6## Связанные ADR
7
8| ADR | Роль |
9|-----|------|
10| [0005](0005-defer-dynamic-plugins-mef.md) | плагины deferred |
11| [0006](0006-presentation-layers-and-feature-slices.md) | границы слоёв/срезов |
12| [0008](0008-mcp-contracts-and-testable-infrastructure.md) | контракты и тестируемая инфраструктура |
13| [0013](0013-command-surface-and-discoverability.md) | поверхность команд |
14| [0019](0019-shared-git-core-ide-and-git-mcp.md) | общий core как прецедент |
15| [0023](0023-markdown-diagrams-language-tooling.md) | внешние инструменты/LSP как контракты |
16| [0026](0026-markdown-preview-surfaces-and-placement.md) | геометрия превью Markdown в TOML |
17| [0025](0025-sdk-attention-zones-and-capabilities.md) | зоны внимания PFD/MFD/… в SDK и capabilities |
18
19## Резюме
20
21- **CascadeIDE SDK** — стабильные контракты для внутреннего расширения и будущих плагинов.
22- Версионирование публичных API; граница с «всё internal».
23- Связь с зонами внимания — [0025](0025-sdk-attention-zones-and-capabilities.md).
24
25---
26## Контекст
27
28CascadeIDE активно развивается “изнутри”: добавляются новые панели, инструменты, каналы диагностики, режимы UI и интеграции с внешними процессами (LSP/DAP/MCP). При этом:
29
30- Удобство разработки упирается в **ментальную модель**: где границы, какие зависимости допустимы, что считается “ядром”, что — “фича”.
31- `MainWindowViewModel` и UI-shell неизбежно становятся местом, куда “просится всё”, если нет явных контрактов.
32- Плагины (динамическая загрузка DLL/MEF) пока **отложены** ([0005](0005-defer-dynamic-plugins-mef.md)), но когда мы к ним вернёмся, нужен будет “куда вставлять”, иначе plugin-host появится раньше, чем стабилизируется форма слотов/контрактов.
33
34Нужен “SDK” — но в первую очередь **для нас же**, чтобы:
35
36- уменьшить связность между фичами,
37- обеспечить расширяемость без хаоса,
38- подготовить базу под будущие плагины без преждевременного plugin-host.
39
40---
41
42## Решение
43
44Принять подход: **SDK = стабильные контракты расширения IDE**, а не обязательная система плагинов сегодня.
45
46SDK в v1 включает:
47
481. **Явные публичные интерфейсы/контракты** между shell и фичами (и между фичами), оформленные как отдельный слой (папка/проект), с минимальными зависимостями.
49 - Формат поставки: **отдельный проект** `CascadeIDE.Contracts` (или близкое имя), а не папка внутри `cascade-ide`.
50
512. **Capability-модель** (объявление возможностей), чтобы фича могла “подключаться” к shell и друг к другу без прямых ссылок на конкретные реализации.
52
533. **Capability registry — hybrid (следует из текущей логики IDE):**
54 - **Code-first регистрация** capabilities фичами при старте (без MEF/рефлексии “на вырост”).
55 - **Data overlay для презентации**: UI-режимы/раскладки (TOML) могут включать/выключать или менять presentation capabilities, но не подменяют их семантику.
56 - **Introspection**: shell умеет собрать “карту возможностей” для диагностики/телеметрии/агента.
57
584. **Command surface как контракт**: команды (и их discoverability) оформляются не через “познавание внутренностей” фичи, а через общий контракт регистрации/метаданных (в духе [0013](0013-command-surface-and-discoverability.md)).
59
605. **Out-of-proc как норма для интеграций** (LSP/DAP/MCP/CLI): протоколы и DTO — часть “SDK” в смысле стабильных контрактов (см. [0008](0008-mcp-contracts-and-testable-infrastructure.md)). In-proc расширения не запрещены, но должны входить в рамки контрактов.
61
626. **Маркировка контрактов `Experimental`/`Stable` — внутренняя ясность, не публичное обещание.**
63 На стадии active-dev (далеко до alpha) цель — не “совместимость навсегда”, а дисциплина границ: по умолчанию всё `Experimental`, а `Stable` появляется только там, где команда осознанно хочет опираться на контракт. Ломать `Experimental` можно свободно; ломать `Stable` — осознанно (через ADR/заметку о миграции), SemVer — когда появится продуктовая потребность.
64
657. **Отложенный plugin-host**: динамическая загрузка плагинов остаётся deferred (см. [0005](0005-defer-dynamic-plugins-mef.md)), но будущий plugin-host обязан подключаться через те же контракты SDK, что и “внутренние” фичи.
66
67### Модель внимания кокпита (PFD / MFD / Forward / EICAS / HUD) и SDK
68
69Семантика зон описана в [0021](0021-pfd-mfd-cockpit-attention-model.md). **Явная привязка UI‑capabilities к зонам внимания на уровне `CascadeIDE.Contracts`** — отдельное решение и поэтапная реализация: [0025](0025-sdk-attention-zones-and-capabilities.md). Так [0024](0024-ide-sdk-and-stable-contracts.md) остаётся про общий SDK, а кокпитная ось не смешивается с registry/plugin‑обсуждением.
70
71---
72
73## Capability registry / capability-map (API и принципы)
74
75Цель: capability-слой должен быть достаточно строгим, чтобы удерживать границы и ментальную модель, и достаточно простым, чтобы им реально пользовались.
76
77### Что считаем capability
78
79- **Service capability**: “я предоставляю сервис” (контракт/интерфейс + реализация).
80- **Command capability**: “я предоставляю команду” (discoverability, категория, горячие клавиши, доступность).
81- **UI surface capability**: “я предоставляю UI‑слот/поверхность” (панель/страница/вкладка), при этом включаемость/раскладка остаются overlay’ем (TOML).
82
83### Code-first регистрация модулей (без MEF/рефлексии)
84
85- Реестр модулей формируется **явно кодом** (ручной список), без сканирования сборок.
86- Каждая фича имеет одну точку входа регистрации, например `ICascadeFeatureModule` → `Register(ICapabilityRegistry registry)`.
87
88### Ключи и зависимости
89
90- Capability идентифицируются **строковыми id** (константы в SDK/контрактах), например: `git.core`, `docs.markdown.exportExpanded`.
91- В capability‑descriptor поддерживаются **явные зависимости** (`Requires`) для объяснимости (“почему capability не активна/не видна”).
92
93### Capability-map (introspection)
94
95Регистрирующий слой обязан собирать “карту возможностей” (`CapabilityMap`) как неизменяемое описание:
96
97- список service/command/ui capabilities с метаданными (id, owner module, stability, tags, requires);
98- состояние “доступно/включено” может вычисляться shell’ом с учётом overlay (например UiMode TOML) и рантайм условий.
99
100Capability-map используется для:
101
102- диагностики и объяснимости (“почему кнопка/панель отсутствует”),
103- телеметрии и снимков UI/агента (introspection),
104- будущего plugin-host (внешний модуль должен регистрироваться тем же способом).
105
106### TOML overlay (presentation)
107
108UI-режимы/раскладки (TOML) должны ссылаться на capabilities **по id**, управляя presentation (видимость/размещение), но не подменяя семантику capabilities.
109
110---
111
112## Минимальный API (черновик контрактов)
113
114Ниже — минимальная форма контрактов для `CascadeIDE.Contracts` (без привязки к DI-контейнеру/фреймворку):
115
116- `ICascadeFeatureModule`
117 - `string Id { get; }`
118 - `void Register(ICapabilityRegistry registry)`
119
120- `ICapabilityRegistry`
121 - `void RegisterService(ServiceCapabilityDescriptor descriptor)`
122 - `void RegisterCommand(CommandCapabilityDescriptor descriptor)`
123 - `void RegisterUiSurface(UiSurfaceCapabilityDescriptor descriptor)` *(опционально для MVP)*
124 - `CapabilityMap BuildMap()` *(для introspection/диагностики)*
125
126- `CapabilityMap`
127 - `IReadOnlyList<ServiceCapabilityDescriptor> Services`
128 - `IReadOnlyList<CommandCapabilityDescriptor> Commands`
129 - `IReadOnlyList<UiSurfaceCapabilityDescriptor> UiSurfaces`
130
131- Общие поля дескрипторов:
132 - `string Id` (строгий идентификатор)
133 - `string OwnerModuleId`
134 - `ApiStability Stability` + `[ApiStability]`
135 - `string[] Tags`
136 - `string[] Requires`
137
138Пояснение: `CapabilityMap` описывает “что зарегистрировано”, а “включено ли” и “как размещено” вычисляется shell’ом с учётом TOML overlay и рантайм условий.
139
140---
141
142## Что НЕ является целью (v1)
143
144- Не вводить сейчас обязательный механизм “плагины из папки DLL”.
145- Не обещать бинарную совместимость для сторонних расширений “навсегда”.
146- Не превращать SDK в “бог-API” без границ (наоборот, цель — уменьшить поверхность).
147
148---
149
150## Практические принципы проектирования SDK
151
152- **Минимальная поверхность**: контракты должны описывать “что нужно”, а не “как сделано”.
153- **Зависимости направлены наружу**: фичи зависят от контрактов, а не от конкретных фич.
154- **DTO отдельно от UI**: переносимые модели данных не зависят от Avalonia-контролов.
155- **Тестируемость**: контракты легко мокать; выполнение выносится в сервисы.
156- **Безопасность по умолчанию**: всё, что запускает код/процессы/сетевые запросы — через явные шлюзы и настройки.
157
158---
159
160## Как отражаем `Stable`/`Experimental` в коде и документации
161
162Минимальный договор (без бюрократии, полезный уже в active-dev):
163
164- **Namespace-сигнал**: в `CascadeIDE.Contracts` два “корня”:
165 - `CascadeIDE.Contracts.Experimental.*` — по умолчанию всё новое.
166 - `CascadeIDE.Contracts.Stable.*` — то, на что команда осознанно опирается.
167- **Атрибут-маркер**: единый `ApiStabilityAttribute` + enum (`Experimental`, `Stable`) для быстрых поисков/анализа и расширения в будущем (например `Deprecated`).
168- **Зачем оба**: namespace даёт “видимость по умолчанию” (и упрощает правила зависимостей), атрибут даёт точечную метку и основу для будущих анализаторов/отчётов.
169- **Документация**: в ADR и/или в README проекта контрактов фиксируем правило “по умолчанию Experimental”, критерии перевода в Stable и ожидание миграции при breaking-change.
170
171---
172
173## Последствия
174
175- Новые фичи добавляются через понятные слоты/контракты, меньше “скрытых” связей.
176- Ускоряется разработка: проще понять куда добавить логику, проще тестировать, меньше регрессий от случайных зависимостей.
177- Появляется ровная база для будущих плагинов: когда plugin-host перестанет быть deferred, “SDK-форма” уже будет существовать.
178
179---
180
181## Отклонённые альтернативы
182
183- “SDK = сразу plugin-host (MEF/загрузка DLL)” — отклонено как преждевременное усложнение ([0005](0005-defer-dynamic-plugins-mef.md)).
184- “Никакого SDK, всё через прямые ссылки” — отклонено: ухудшает ментальную модель, ускоряет рост связности и размеров shell-композитора.
185
186---
187
188## Открытые вопросы
189
190## Визуализация и документация capability-map (принятое направление)
191
192Минимальный путь (v1), без отдельного UI:
193
194- **Принцип “тонких снапшотов”** (применимо и к capability-map, и к UI snapshot’ам/прочим дампам):
195 - по умолчанию возвращаем **summary + hash** (и, при необходимости, короткий список id/счётчики);
196 - “толстые” данные получаем **по запросу** (фильтры/пагинация) или через **dump‑файл**.
197- **JSON dump‑файл** capability-map доступен в diagnostics/логах (для объяснимости и отладки интеграций), с возвратом `path + hash`.
198- Capability-map может быть включён в **MCP/UI snapshot** только в виде **summary**; детали — отдельной командой или через dump‑файл (чтобы не раздувать контекст).
199
200Следующий шаг (когда появится потребность):
201
202- Страница/таб **Capabilities** в Debug/Power (или отдельный документ в `docs/`) с группировкой по `OwnerModuleId` и фильтром по `Stable/Experimental`.
203
204
View only · write via MCP/CIDE