ADR 0154: Slash-каталог — domain · object · intent (семантика и алиасы пути)¶
Статус: Accepted · Implemented
Дата: 2026-05-28
Резюме¶
После 0153 каноническим остаётся строка path в [[command.form.slash]]. Для единообразия именования и autocomplete вводим явную тройку domain · object · intent (в UI: домен → объект → действие). Строка в composer — поверхность ввода; короткие пути (/build run) — алиасы полной семантики, а не «пустой object». Термины workspace / solution / project в slash не смешиваем с группой UI group = "Workspace".
v1 (продукт): один пользовательский путь /build run (и семейство test/debug с тем же elision); executor — implicit scope = solution (открытое .sln / контекст после load_solution). Отдельный slash /project build run и второй command_id для сборки проекта — не в v1; модель project как domain остаётся в ADR для будущего и для breadcrumb после миграции TOML.
Связанные ADR¶
| ADR | Роль |
|---|---|
| 0119 | Slash в composer, command_id, autocomplete |
| 0150 | SlashLineResolver, arg_tail, Enter/preview |
| 0153 | Резолв только по каталогу + codegen trie |
| 0125 | /file, /solution, динамический completion |
| 0039 | «Workspace» как контекст IDE / навигация — не slash-domain |
| 0136 | domain slash intercom |
Проблема¶
- Popup уже думает иерархией «домен → объект → действие → аргумент» (
ChatSlashAutocomplete.GetHierarchyContext), но в TOML задан толькоpath— глубина выводится из числа токенов, без семантики. - Короткие пути вводят в заблуждение:
/build runautocomplete помечаетbuildкак «домен», хотя по смыслу это объект при сжатом domain (см. ниже). - Смешение слов workspace / solution / project: в каталоге
group = "Workspace"для/solution openи/build run; в продукте workspace — широкий контекст открытой работы (0039), solution —.sln/.slnx, project —.csprojвнутри solution. Slash-сегментsolutionв пути не равен «всё про workspace».
Глоссарий (slash vs IDE)¶
| Термин в IDE | Что это | Пример slash | Slash domain? |
|---|---|---|---|
| Workspace (контекст) | Открытая папка и/или загруженное solution; область поиска, MCP multi-root | /search, /folder open |
Только если первый сегмент пути буквально про контекст: workspace (/workspace show) |
| Solution | Файл решения .sln / .slnx, dotnet build на solution |
/solution load, /solution new |
solution |
| Project | Проект .csproj в solution |
/solution new console (шаблон + имя в хвосте) |
Не отдельный domain: создание project — intent под solution + new + хвост |
| File | Файл на диске в контексте | /file open |
file |
| Intercom | Канал чата / темы / сообщения | /intercom topic list |
intercom |
| Build / test / debug | Сборка/тест/отладка цели в IDE — см. § «Scope: solution и project» | /build run, /test run |
Сжатый path; domain в строке не build |
Правило: group в TOML (Сборка, Workspace, Intercom) — группировка подсказок в UI, ортогональна полям domain / object / intent.
Решение¶
1. Семантическая тройка (канон)¶
| Поле | Смысл | Примеры |
|---|---|---|
| domain | Продуктовая область / цель команды (что затрагиваем) | intercom, solution, project, file, editor, map, git |
| object | Подсистема или вид операции внутри domain | topic, build, test, debug, line, type, server |
| intent | Действие (глагол, режим) | list, run, open, select, show, launch |
- Не путать
intentсcommand_id:intent— человекочитаемый сегмент пути;command_id— канон исполнения (0030). - Хвост после полного пути — не четвёртый уровень иерархии, а
arg_tail(0150): аргументы, параметрические диапазоны, пути файлов.
2. Канонический путь и алиасы (elision)¶
Канонический путь — строка, собранная из тройки (и опционально статических args в TOML):
canonical_path = "/" + domain + " " + object + " " + intent // все сегменты непустые
Алиас — отдельная запись [[command.form.slash]] с тем же command_id (и теми же handlers), у которой path короче за счёт опущенного domain (или, реже, другого согласованного сжатия):
| Канон (семантика) | Алиас (частый ввод) | Примечание |
|---|---|---|
solution · build · run |
/build run |
см. § scope — алиас, когда цель берётся из контекста IDE |
project · build · run |
(пока нет в каталоге) | явная сборка проекта (.csproj), не всего solution |
solution · test · run |
/test run |
то же сжатие scope |
solution · debug · launch |
/debug launch |
семейство /debug … |
intercom · topic · list |
/intercom topic list |
полная форма = алиас (domain не сжимается) |
map · type · set + [args] level=file |
/map type file |
file — не intent, а дискриминатор в args (см. §4) |
Loader (v2): при наличии domain/object/intent проверяет согласованность с path; при отсутствии полей — только path (как сейчас, 0153).
2a. Scope: solution и project (сборка, тесты, отладка)¶
В .NET и в IDE собрать можно и solution, и project — это разные цели (dotnet build Foo.sln vs dotnet build Foo.csproj). Slash-модель должна это различать, а не сводить всё к одному domain solution.
| Уровень | Смысл | Пример канона |
|---|---|---|
| domain | Что собираем/тестируем/отлаживаем | solution или project |
| object | Какая операция | build, test, debug |
| intent | Как выполняем | run, launch, attach, … |
/build run в composer — не «domain=build». Видимые токены build + run — это object + intent. Domain (solution или project) в короткой форме не печатается: подставляется из контекста IDE (открытое solution, startup project, выделенный .csproj — политика в command_id / executor, не в парсере пути).
| Ситуация | Канонический path (целевой) | Сегодня в каталоге (0153) |
|---|---|---|
| Сборка всего solution | /solution build run |
только /build run → command_id = build (фактически solution; см. XML-doc) |
| Сборка одного project | /project build run |
нет отдельного slash — зазор продукта |
| Частый ввод без scope | /build run |
alias; scope implicit |
v1 CIDE (принято):
| Решение | Содержание |
|---|---|
| Пользовательский path | Только /build run (и аналоги /test run, /debug …); полная форма /solution build run в UI не обязательна |
| Scope в executor | Solution по умолчанию (command_id = build); не startup project, не выделенный .csproj, пока нет отдельной политики |
/project build run |
Не добавляем в каталог и executor без явного use case (большие sln, агент «собери только X», несогласованность с debug) |
| Семантика в ADR | Канон solution · build · run + алиас /build run; domain project — зарезервирован, не «навсегда только solution» |
Опционально позже (без обязательного второго slash): scope из контекста explorer; или [command.form.slash.args] scope = project / хвост с путём к .csproj — при появлении второго поведения в executor.
3. Предлагаемая форма TOML (v2, не обязательна сразу)¶
[[command.form.slash]]
domain = "solution"
object = "build"
intent = "run"
path = "/build run" # alias; scope implicit (solution или project)
path_role = "alias"
[[command.form.slash]]
domain = "solution"
object = "build"
intent = "run"
path = "/solution build run"
path_role = "canonical"
help = "Собрать открытое solution (structured JSON)."
group = "Сборка"
arg_tail = "none"
Несколько [[command.form.slash]] на одну команду:
[[command.form.slash]]
domain = "solution"
object = "build"
intent = "run"
path = "/solution build run"
path_role = "canonical"
[[command.form.slash]]
domain = "solution"
object = "build"
intent = "run"
path = "/build run"
path_role = "alias"
Минимальный шаг без ломки v1: только документировать семантику в комментариях к path и в ADR; поля добавить, когда будет миграция каталога.
4. Особые случаи¶
| Случай | Правило |
|---|---|
| Плоские команды | /help — domain = "help" (или intercom), без object/intent; один сегмент после / |
| Два сегмента в path | Либо alias (§2), либо domain + intent без object (git + status — уточнить при добавлении) |
| Три сегмента + параметр | /editor line select — domain=editor, object=line, intent=select; хвост — parametric (0124) |
| Статический дискриминатор | /map type file и /map type controlflow: один смысл «задать уровень карты»; различие в [command.form.slash.args] level=…, не в том, что file — intent. Семантика: domain=map, object=type, intent=set (или level); path остаётся как сейчас для trie |
| Шаблон в path | /solution new console — domain=solution, object=new, intent=console или intent=new, хвост=имя project — зафиксировать одну схему при миграции (предпочтение: intent=new, object=project, template в хвосте/args) |
5. Autocomplete и breadcrumb¶
- Breadcrumb в popup показывает каноническую тройку (
solution › build › runилиproject › build › run), даже если в строке/build run; при implicit scope — пометка «цель: solution» / «цель: startup project» из IDE. - Подстановка по-прежнему может вставлять алиас (короткий path), если
path_role = aliasиauto_run_on_commit. - Сегментные подсказки строятся по domain, затем object, затем intent из индекса каталога, а не по «первому токену = domain».
Последствия¶
- Единый язык для авторов каталога, тестов и ADR; меньше путаницы workspace/solution/project.
- Допускается несколько
pathна одну семантику без второго парсера. - Миграция постепенная: 0153 остаётся; поля
domain/object/intent— следующий шаг loader + codegen.
Non-goals¶
- Автоматический вывод domain из
command_idбез явной записи в TOML. - Обязательная полная форма
/solution build runв UI (алиасы остаются). - Слияние
groupиdomainв одно поле. - Переименование IDE-терминов workspace/solution в коде Roslyn/MCP — только slash-каталог.
- v1: отдельный slash
/project build run, второйcommand_idтолько для сборки.csproj, обязательная дублирующая запись canonical path в каталоге.
Альтернативы (отклонены)¶
| Вариант | Почему нет |
|---|---|
Только path, без тройки |
UI и авторы каталога продолжают расходиться в трактовке сегментов |
object = "" для /build run |
Маскирует elision; ломает иерархию подсказок |
domain = workspace для всех build/test/debug |
Смешивает контекст IDE с операцией над solution; в каталоге уже есть отдельный сегмент workspace (/workspace show) |
Один domain solution для всех build/test/debug без варианта project |
Отрицает реальный dotnet build на csproj; оставляем оба канона + алиас |
Принятые решения¶
| # | Вопрос | Решение |
|---|---|---|
| A | Дефолт /build run |
Solution; один command_id = build; отдельный project-slash в v1 нет (см. §2a) |
| B | canonical_path в TOML |
Не вводим отдельное поле; достаточно domain/object/intent + path + path_role (canonical | alias) |
| C | Массовая миграция каталога | Done (2026-05-28): все [[command.form.slash]] в bundled intent-catalog.toml; intent_catalog_schema_version = 2 |
Открытые вопросы¶
- Канон для
/solution new console: предпочтение при миграции —domain=solution,object=project,intent=new, шаблонconsoleв хвосте/args (см. §4); финально — при разметке семействаsolution. - Семейство
format/git/agent: таблица domain·object·intent при пошаговой миграции TOML (не блокирует Accepted ADR). - Project-scope без второго slash: при появлении фичи — тот же
build+scopeв executor vs контекст explorer; отдельныйcommand_idтолько если поведение принципиально другое.
Связь с реализацией¶
| Сейчас (0153) | После 0154 |
|---|---|
Только path |
domain, object, intent + проверка path в TOML |
Trie по полному path (резолв) |
+ SlashSemanticCatalogIndex для popup |
| Breadcrumb по глубине токенов | Breadcrumb по семантике (elision /build → «действие») |
История¶
| Дата | Изменение |
|---|---|
| 2026-05-28 | Proposed: семантика domain/object/intent, elision, глоссарий workspace≠solution≠project |
| 2026-05-28 | §2a: build/test — domain solution или project; /build run = object+intent, scope implicit |
| 2026-05-28 | Accepted v1: один /build run, implicit solution; project-slash deferred; § «Принятые решения»; статус Deferred для TOML/loader |
| 2026-05-28 | Implemented: domain/object/intent/path_role в TOML; SlashRouteSemantics; loader validation; popup breadcrumb для elision (/build → «действие») |
| 2026-05-28 | SlashSemanticCatalogIndex: popup по domain → object → intent (elision starters на корне) |