Перейти к содержанию

ADR 0010: Данные UI-режимов (Focus / Balanced / …) в TOML

Статус: Accepted · Implemented
Дата: 2026-04-02
Обновлено: 2026-04-25 — в [capabilities] ключи IDE Health: ide_health_*. Подробности — § История.

Связанные ADR

ADR Роль
0003 Отдельный UI-режим Debug (не кокпит Power)
0006 Слои, вертикальные срезы и роль MainWindowViewModel
0017 мультиоконность и топология
0022 канон имён и эволюция для IDE Health (пересечение с таблицей ide_health_* ниже).

Вне ADR

Документ Роль
attention-zone-panel-playbook-v1.md зона ↔ панель ↔ топология

Снимок реализации

Элемент Значение
загрузчик TOML, UiModeCatalog, capabilities, bundle UiModes/
override и docs/ui-ux — по мере нужды

Резюме

  • Режимы UI (Focus/Balanced/…) — данные в TOML (UiModes/), не только константы в C#.
  • Bundle + merge с .cascade/workspace.toml; override без обратной записи динамики в шип.
  • [capabilities] и ключи ide_health_* — контур IDE Health в том же каталоге режимов.
  • Tomlyn, snake_case; JSON не дублируем как второй канон конфигов.

Контекст

Сейчас спеки режимов (видимость панелей, группы редактора, слот темы, ширина развёрнутого чата и т.д.) зашиты в C# (UiModeLayoutRegistry, связанные константы). Глобальные размеры хрома (сплиттеры, минимумы строк и пр.) собраны в UiWorkspaceLayoutDimensions и применяются через UiWorkspaceLayout.

Потребность: менять раскладку режимов без пересборки (дизайн, пресеты, эксперименты), в одном стиле с уже принятым в продукте хранением настроек в settings.toml (Tomlyn уже в зависимостях).

JSON для этого не предлагается как основной формат: пользовательские настройки уже TOML; дублировать второй «официальный» текстовый формат для конфигов режимов нежелательно.

Решение

1. Источник данных режимовнесколько файлов TOML: индекс задаёт порядок и полный список id режимов в меню (включая встроенные и дополнительные, см. ниже) + отдельный файл на режим (Focus.toml, Balanced.toml, …; шипнутый набор дублирует дефолты из UiModeLayoutRegistry / DefaultsForFamily), чтобы диффы и смысл «один режим — один файл» были очевидны. Если файла режима нет — загрузчик берёт те же дефолты из кода. Версионируем с приложением (как темы: копия рядом с exe или встроенный ресурс + fallback на диск). Расположение шипнутого набораподкаталог UiModes/ рядом с exe (тот же паттерн, что Themes/: копия в вывод сборки рядом с exe). Отдельный путь в настройках пользователя — возможное расширение позже, в первой версии не обязательно. 2. Глобальные метрики хрома (ширина дерева по умолчанию, толщина сплиттеров, минимумы высот нижней зоны, политика «свёрнуто» и т.п.) — один раз в отдельном файле workspace.toml рядом с индексом и режимами (не копировать в каждый Debug.toml). 3. Схема окна (инварианты): число колонок MainGrid, смысл колонок, привязка контролов к колонкам — намеренно остаются в коде/XAML в рамках этого ADR. TOML описывает режимы поверх этого каркаса (видимость, метрики, слот темы и т.д.), а не альтернативную разметку окна. Возможный вынос схемы окна в данные — отдельное ADR, если появится продуктовая необходимость (несколько каркасов, плагины и т.п.). 4. Загрузка при старте: десериализация в модель, совместимую по смыслу с UiModeLayoutSpec (+ числа вроде ширины правой колонки в развёрнутом виде для режима, если остаётся в данных). 5. Fallback: если файл отсутствует, битый или не прошёл валидацию — встроенные значения по умолчанию из кода, без падения IDE. См. ниже про роль этих дефолтов. 6. Версия схемы: поле schema_versionтолько в корне файла индекса (первый читаемый файл набора). Оно задаёт версию всего бандла UiModes/ — индекс, workspace.toml, per-mode файлы. В workspace.toml отдельного schema_version нет (избегаем двух чисел и рассинхрона). Миграции формата — по одному номеру из индекса. 7. Валидация при загрузке (минимум): неизвестный theme_slot → fallback; в шипнутом наборе отсутствует спека для обязательного id → предупреждение + встроенная спека из кода. Минимальный набор обязательных id (который продукт не имеет права «потерять» в данных) задаётся в коде — сейчас это совпадает с UiModeLayoutRegistry.OrderedModeIds. Индекс может перечислять больше id, чем этот минимум (дополнительные пользовательские или пресетные режимы). См. ниже про наследование и отдельный пункт меню без замены Debug. 8. Capabilities — тип UiModeCapabilities (Features/UiChrome/UiModeCapabilities.cs). В UiModes/<id>.toml ключи предметные (что в интерфейсе), в snake_case; десериализация через CascadeTomlSerializer (имена свойств модели в PascalCase → snake_case). Мердж: явное значение → при inherits — от родителя → иначе DefaultsForFamily. API: GetCapabilities, GetWindowTitleOverride.

Ключ TOML Смысл
active_task_strip Полоса активной задачи / Task Cockpit под тулбаром
main_window_title Полный заголовок главного окна
quick_actions Быстрые действия у задачи
agent_operations_panel Блок операций агента в чате (Balanced)
agent_trace Панель trace агента (Power)
autonomous_agent_telemetry Кокпит Power: явный доступ к выводу (терминал и подсказки); не канал IDE Health
ide_health_on_terminal_tab Дубль IDE Health на вкладке «Терминал» (Power)
ide_health_main_column_span Column span области IDE Health в основной сетке (Power)
ide_health_strip Показывать полосу IDE Health под редактором
ide_health_surface bottom_strip или dedicated_page — слой представления IDE Health
instrumentation_tabs Вкладки событий/тестов/отладки в нижнем доке
hypotheses_tab Вкладка «Гипотезы»
risk_summary_card / result_summary_card Карточки риска и результата в чате

Слои модели (шпаргалка для автора UiModes/*.toml)

Чтобы не путать id режима, раскладку, семью и capabilities, удобно держать в голове такие уровни:

Слой Что это Откуда берётся
Id режима Стабильная строка (пункт меню, ключ в каталоге, имя файла Id.toml) index.tomlmodes, плюс таблица встроенных id в коде для fallback
Раскладка Видимость панелей, число групп редактора, слот темы, флаги вроде «выбирать вкладку терминала» База: UiModeLayoutRegistry для встроенных id; мердж с полями текущего *.toml; при inherits — база = разрешённый родитель
workspace.toml Общие числа хрома (сплиттеры, ширины чата по правилу Power / AgentChat / остальные, минимумы строк и т.д.) Один файл на бандл; без копирования в каждый режим
family Продуктовая роль: Focus, Balanced, Power, AgentChat, Debug — влияет на дефолты capabilities и ветки в коде (UiModeFamily) Порядок: явный family в файле режима → при inherits — семья разрешённого родителя → для встроенных id — таблица в коде по id → иначе Balanced
Capabilities Что показывать в интерфейсе (гипотезы, quick actions, хром кокпита Power и т.д.) База: при inheritscapabilities разрешённого родителя; без inheritsDefaultsForFamily(family). Поверх — явные ключи в *.toml

Узкий ключ в том же workspace.toml про где монтировать превью Markdown (не путать с будущей общей топологией нескольких TopLevel) — 0026.

Конечный пользователь IDE в комбо «режим интерфейса» видит в основном id пресета; оси family / capabilities ему не обязательны, пока в UI нет отдельных переключателей под них.

Топология презентации зон (будущее расширение)

Сейчас в коде одна топология — MainWindowDockedGrid (AttentionLayoutSurfaceKind, одно главное окно, колонки MainGrid). Когда в продукте появятся альтернативы (несколько TopLevel, сценарии 0017), логично связывать выбранную топологию с merge слоёв 0010 и отдельным учётом персональной раскладки по мониторам (см. следующий абзац). Без обратной записи динамического ресайза окон в шипнутые файлы (см. подраздел про рантайм ниже).

Не смешивать с картой панель → зона (attention_zone_panels / AttentionZonePanelRuntime): там семантика «какая панель в какой зоне», здесь — в какой геометрии (одно окно vs несколько) воплощены регионы. Подробнее: attention-zone-panel-playbook-v1.md.

Поля presentation / zone_screen_layout (корень settings.toml) и токены грамматики в секции [presentation_grammar] (screen_markers, screen_separator, zone_separator, литералы якорей pfd_zone_identifier / forward_zone_identifier / mfd_zone_identifier) — строка раскладки по физическим дисплеям из 0017 («Несколько мониторов»), например (PFD+Forward) (MFD) или (P+F) (M) при коротких идентификаторах в TOML (таблица); между якорями внутри одной пары скобок допускается только литерал zone_separator (Z, по умолчанию +); при Z = "|" в строке — только |, без подстановки «второго стиля». EBNF0017. Где хранить: прежде всего settings.toml пользователя (0028). Репозиторный .cascade/workspace.toml (0021 §2.1) — для командных соглашений по панелям и зонам, не для обязательной для всех схемы мониторов; при merge пользовательские значения presentation и токенов перекрывают одноимённые в бандле/репо. Альтернативное имя ключаzone_screen_layout; в одном конфиге задаётся одно из двух. Перечисление значений AttentionLayoutSurfaceKind и валидация — в реализации; отдельный ADR под схему TOML не требуется, пока объём правил укладывается в этот подпункт.

inherits = "BaseId" — один родитель: наследуется весь уже разрешённый режим (раскладка, capabilities, ширина чата, полоса задачи, заголовок окна — по правилам мержа в коде). В дочернем файле задаются только отличия от родителя. Отдельная секция вроде [inherits] со списком «какие поля наследовать» не используется: при такой модели список дельт в файле и так короче, чем перечисление срезов.

Порядок разрешения family (формально)

  1. Если в Id.toml задано family = "…" (регистр не важен) — используется оно.
  2. Иначе, если задано inherits — берётся family уже разрешённого родителя (рекурсивно).
  3. Иначе — для известных встроенных id (Focus, Balanced, …) — BuiltinFamily(id) в коде.
  4. Иначе — Balanced (неизвестный id без явной семьи).

Примеры: inherits и опционально family

Дополнительный режим как Debug, но с полосой задачи и своим заголовком — без дублирования всей спеки:

index.toml (фрагмент; полный индекс см. шипнутый UiModes/index.toml):

schema_version = 1
modes = [ "Focus", "Balanced", "Power", "AgentChat", "Debug", "MySuperDebug" ]

MySuperDebug.toml:

inherits = "Debug"

active_task_strip = true
main_window_title = "CascadeIDE — мой отладочный пресет"

Поле family не нужно: семья остаётся Debug (как у разрешённого родителя), поведение гипотез/инструментирования — как у отладки.

Цепочка из двух уровней: каждый файл задаёт только дельту; корень цепочки — встроенный id с полной спекой (или другой уже разрешённый режим).

# DeepWork.toml — ответвление от Focus
inherits = "Focus"
editor_group_count = 1
main_window_title = "CascadeIDE — Deep work"

# MyDeep.toml — ответвление от DeepWork
inherits = "DeepWork"
chat_expanded_width_pixels = 400

Оба новых id должны быть перечислены в modes в index.toml.

Редкий случай: inherits от Debug и явный family (ось UiModeFamily отличается от родителя; см. пояснение после примера):

inherits = "Debug"
family = "Balanced"

Раскладка — мердж спеки Debug с полями файла. Ось family для кода (UiModeFamily, предикаты вроде IsDebugFamily) становится Balanced. Важно: при inherits базовый слой capabilities в загрузчике берётся от разрешённого родителя (parentResolved.Capabilities), а не от DefaultsForFamily(family) — то есть флаги интерфейса по умолчанию остаются «как у Debug», пока их не переопределить ключами в том же *.toml. Если когда-нибудь понадобится стартовать capabilities от DefaultsForFamily выбранной семьи при наследовании раскладки — это отдельное изменение контракта загрузчика.

См. также подраздел inherits и family: это не одно и то же ниже — там про помодульный мердж и ширину чата.

Динамический ресайз после старта и TOML (источник правды)

Файлы UiModes/*.toml, workspace.toml и индекс набора режимов — пресет: они задают раскладку и метрики на момент загрузки конфигурации (старт приложения и, если когда-нибудь появится, явная команда «перечитать конфиг»). Это не живой журнал геометрии окна.

Перетаскивание сплиттеров, изменение ширин/высот панелей и любой динамический ресайз хрома после запускарантайм-состояние в памяти. Оно ни при каком сценарии по умолчанию не записывается обратно в шипнутые рядом с exe UiModes/*.toml и workspace.toml: ни при каждом движении сплиттера, ни при смене режима, ни при выходе из IDE. Так редактор и диффы по репозиторию остаются источником дизайна режима; случайный дрейф окна пользователя не портит файлы пресета.

Если позже понадобится сохранять геометрию между сеансами, это оформляется отдельным каналом (например поля в settings.toml, отдельный пользовательский override в %LocalAppData% — см. «Границы» ниже), а не обратной записью в дистрибутивные TOML режимов.

MCP (ide_set_panel_size и аналоги) и снимки UI для тестов/агента меняют текущую раскладку в процессе работы; контракт тот же: не считать, что вызов перезаписывает TOML на диске, пока это явно не задокументировано как отдельная операция «экспорт пресета в файл».

Один и тот же Debug vs отдельный MySuperDebug (наследование)

  • Правка Debug.toml или override на Debug меняет сам режим Debug для того набора файлов, к которому относится конфиг: штатный Debug в том виде, как в дистрибутиве, рядом не живёт — это ожидаемо, если цель именно «переопределить Debug». Для сценария «и стоковый Debug доступен, и мой вариант рядом» нужны два разных id.
  • Дополнительный режим с новым id (например MySuperDebug), по смыслу близкий к Debug, но с другой раскладкой под контекст: объявляется в индексе (отдельная строка в меню, своё сохранённое значение в настройках), отдельный файл MySuperDebug.toml. Чтобы не дублировать всю спеку, в файле режима поддерживается наследование от базового id, например поле inherits = "Debug" (имя уточняется при реализации): загрузчик мержит разрешённую спеку Debug с переопределениями из MySuperDebug.toml. Так не нужно копипастить десятки полей и не нужно менять C# только ради нового id — достаточно индекса + файла режима (и при необходимости общих правил для «неизвестных» id в коде: разрешённые базы, fallback).
  • Подпись в UI для id (отображаемое имя вместо сырого MySuperDebug) — при необходимости отдельные поля в индексе/TOML или локализация; не смешивать с обязательным минимумом id из п. 7.

Семантика для кода: «family» и устаревшие флаги Is*Mode

Контекст (проблема до одной оси): проверки вроде «это Debug для гипотез?» через UiMode == "Debug" или булевы IsDebugMode ломаются для производного id (MySuperDebug): строка id другая, а продуктовый смысл «семья отладки» тот же.

Текущий код уже переведён на UiModeFamily и предикаты расширения — см. подраздел «Реализация в коде» ниже. Таблица вариантов и family в TOML — про данные после загрузчика; там family после мержа должна попадать в ту же ось, что и сегодняшний UiModeFamily.

Дополнительно, NormalizeUiMode сейчас сводит неизвестный режим к Balanced. Режимы с новыми id из индекса должны сохраняться (после проверки «id есть в загруженном списке»), иначе пользовательский MySuperDebug превратится в Balanced без предупреждения.

История обсуждения альтернатив (зафиксировано для контекста; реализован подход A):

Подход Суть Плюсы Минусы
A. Семейство (family) в данных После мержа в результирующей модели есть поле family (enum или строка: debug, power, …). В TOML — опционально family = "debug"; если не задано — наследуется от базы при inherits (у корня цепочки — как у встроенного id). Код переводит IsDebugMode на family == debug (или переименование в IsDebugFamily). Явная семантика; MySuperDebug без копипаста получает «debug» через наследование; проще тестировать. Нужна миграция существующих проверок по строке id; перечень family всё равно конечный в коде.
B. Только цепочка inherits «Отладочность» выводится обходом inherits до известного встроенного id (ResolvesToBuiltIn("Debug")). Не дублировать поле family в TOML. Сложнее рассуждать и отлаживать; глубина/циклы; неочевидно, когда оборвать цепочку для UX.
C. Явный family в каждом TOML без автонаследования Каждый режим, включая производные, пишет family руками. Максимально явно. Дублирование; легко ошибиться и задать MySuperDebug без family.
D. Только точное совпадение id IsDebugMode остаётся == "Debug"; производные режимы не считаются Debug для гипотез и т.д. Минимум кода. Противоречит сценарию «MySuperDebug как Debug»; пользователь вводит в заблуждение.

Реализовано: подход A — в результирующей модели после загрузки есть UiModeFamily; в TOML опционально family; проверки в VM/вью — по семье и capabilities, не по сырой строке id там, где нужна продуктовая роль.

inherits и family: это не одно и то же (разделение ответственности)

  • inherits задаёт разрешённого родителя: от него берутся UiModeLayoutSpec и базовый слой UiModeCapabilities (не только «каркас»); дочерний файл накладывает помодульные переопределения. Для chat_expanded_width_pixels: явное значение в файле → иначе у родителя по inherits → иначе у корневого режима — workspace.toml (через UiWorkspaceLayoutRuntimeMetrics) и правило Power / AgentChat / остальные.
  • family отвечает за продуктовую роль в коде: какие вкладки/инструменты/политики считать «режимом отладки», «power» и т.д. Это другое измерение, не дублирение inherits: теоретически можно представить раскладку, унаследованную от Debug, но явно переопределённую семантику (редкий кейс).

Чтобы не казалось, что в TOML две ручки про одно, правило умолчаний может быть таким:

  1. Для встроенных id family задаётся таблицей в коде (тот же смысл, что сейчас заложен в id).
  2. Для режима с inherits поле family в TOML не обязательно: по умолчанию family = семья разрешённого родителя (например MySuperDebuginherits = "Debug"Debug). Тогда в файле достаточно inherits, без отдельной строки family, пока семантика совпадает с базой.
  3. Явный family в TOML — когда нужно перебить вычисленную семью для UiModeFamily (редко; см. ограничение про базу capabilities при inherits в примере выше).

Так inherits не «задаёт family» сам по себе — он задаёт цепочку родителя для мержа раскладки и capabilities; family либо задаётся явно, либо наследуется от родителя, либо берётся из таблицы встроенных id, либо Balanced для неизвестного id. Разделение: мердж данных по файлу/родителю vs ось семьи для кода.

Связанные места (не исчерпывающе): MainWindowViewModel.Presentation (UiModeFamily, инструментация), UiChromeViewModel.NormalizeUiMode, bloom по строке режима, GetChatPanelExpandedWidthPixels, MCP-обработчики с особыми правилами для режима отладки.

Не плодить Is*Mode в VM

Набор булевых IsFocusMode, IsPowerMode, IsDebugMode и т.д. был типичным запахом. В коде они сняты в пользу UiModeFamily и предикатов (см. «Реализация в коде»). После загрузчика TOML предпочтительно иметь один вычисляемый контекст после загрузки: enum UiModeFamily и/или компактный объект capabilities (что показывать: гипотезы, элементы кокпита Power, …), заполняемый из резолвнутой спеки и правил по умолчанию. Не возвращать очередной IsNewThingMode и не плодить сравнения с сырой строкой id там, где нужна семья.

Реализация в коде (зафиксировано до загрузчика TOML)

Это не отдельный документ: договорённости по оси режима фиксируются здесь, в ADR про режимы и TOML, чтобы и люди, и агент не искали разрозненные заметки.

Элемент Назначение
UiModeFamily + UiModeFamilyResolver.FromNormalizedMode Одна ось после NormalizeUiMode(UiMode); производные id маппятся в семью так же, как сегодня встроенные строки.
UiModeFamilyExtensions (IsFocusFamily, IsBalancedFamily, IsPowerFamily, IsAgentChatFamily, IsDebugFamily) Симметричные предикаты вместо размножения == UiModeFamily.* по VM.
Доменное имя там, где не хватает «голого» enum Например приватное AutonomousCockpitActive в автономной сессии: смысл «кокпит автономного агента», внутри — тот же IsPowerFamily().
XAML Привязки к UiModeFamily через конвертеры UiModeFamilyEq / UiModeFamilyNe (параметр — имя члена enum).
После TOML Загрузчик мержит спеку, familyUiModeFamily, UiModeCapabilities (и опционально main_window_title), без отката к набору Is*Mode.

Fallback и встроенные дефолты (код vs TOML)

Встроенный fallback не претендует быть «главным» источником красивой раскладки: его задача — предсказуемо поднять IDE, если данных на диске нет или они битые. Нормальный путь — шипнутые TOML рядом с exe; тогда fallback срабатывает редко (чистая установка, сломанный каталог, разработка без копии файлов).

Качество текущих констант в коде (в том числе режимы вокруг Power) может быть средним — это отдельная ветка работы: доводка дефолтов, выравнивание с дизайном, возможно приближение built-in к содержимому шипнутых файлов. Это не блокирует механику «TOML + fallback из кода»: сначала надёжная загрузка и тесты, параллельно или позже — полировка встроенных значений (или генерация одного из другого в сборке — вне скоупа этого ADR, пока не понадобится).

Видимость панелей vs «0 px»

В конфиге режима и в смысле продукта первична семантика видимости (visible / hidden для панели; при необходимости позже — отдельное состояние вроде «свёрнуто с полоской», если появится политика не нулевой полоски). «Скрыто» не должно задаваться главным образом как width = 0 в режиме TOML: нулевая ширина колонки и скрытый сплиттер — производное от правил видимости и глобальных метрик из workspace.toml (и кода инвариантов). Так одна и та же идея покрывает любую сворачиваемую колонку/зону, не только чат.

Границы (что точно не входит в этот ADR)

  • Схема окна (каркас MainGrid, новые колонки/зоны из данных) — см. п. 3 решения; не входит.
  • Подсветка синтаксиса .toml в редакторе — отдельно (см. EDITOR-LANGUAGES.md: грамматики TOML в бандле нет); на загрузку конфига не влияет.
  • Пользовательский override в %LocalAppData%\… поверх шипнутого файла — возможное расширение после базовой схемы, не обязательно в первом коммите.

Последствия

  • Плюсы: единый человекочитаемый формат с настройками; правки режимов без компилятора; проще ревью диффов раскладки; дополнительные режимы с наследованием без дублирования спеки и без обязательной правки C# под каждый новый id.
  • Минусы: парсинг, ошибки на диске, тесты на fallback; документация полей TOML для контрибьюторов; загрузчик с мержем inherits; комбо режимов в UI — от загруженного индекса (код хранит минимум для валидации и fallback); family и capabilities должны оставаться согласованы с UiModeFamily и UiModeCapabilities.DefaultsForFamily; NormalizeUiMode сохраняет пользовательские id из индекса; в коде VM булевые Is*Mode сняты (см. «Реализация в коде»). Основные docs/ui-ux приведены к UiModeFamily / capabilities (обзор: docs/ui-ux/ui-modes-overview-v1.md).
  • Связь с MCP: поведение ide_set_panel_size и снимков UI не должно ломаться; контракт с диском — см. подраздел «Динамический ресайз после старта и TOML» выше (рантайм и MCP не перезаписывают UiModes/*.toml / workspace.toml по умолчанию).

Документация (в scope)

Навигационные и UX-доки должны описывать UiModeFamily, capabilities и при необходимости TOML, а не устаревшие булевы Is*Mode. Обзор для читателя: docs/ui-ux/ui-modes-overview-v1.md; макет окна и карта концепт→код — docs/ui-ux/cascade-ide-ui-layout-v1.md, docs/ui-ux/concept-to-implementation-map-v1.md. Исторические ADR (например сравнение подходов A–D) могут упоминать старые имена в прошедшем времени — это норма.

Отклонённые альтернативы

  • Только JSON — расходится с settings.toml и выбранным стеком Tomlyn для пользовательских конфигов.
  • Только код — оставляет текущее состояние; отклоняется как основной путь из-за цели «файл режима» без релиза.

Следующий шаг (опционально)

Пользовательский override каталога UiModes/ из %LocalAppData% при продуктовой необходимости; точечные правки docs/ui-ux при изменении поведения режимов в коде.


История изменений

Дата Изменение
2026-04-08 намерение задать топологию презентации зон в TOML после появления альтернатив одному MainGrid (0017); см. подраздел ниже.
2026-04-11 presentation / zone_screen_layout: прежде всего settings.toml, не командный репо — 0017, п. 4; токены грамматики — секция [presentation_grammar] (без отдельных pfd_zone_alias — короткие имена через pfd_zone_identifier и т.д.); screen_markers / screen_separator / zone_separator, EBNF0017.
2026-04-11 якоря adr0010-p1p8 в разделе «Решение» и ссылки на п. 3, п. 7; соглашение — README ADR.
2026-04-25 в [capabilities] ключи контура IDE Health в TOML: ide_health_* (свойства UiModeCapabilitiesIdeHealth*).