| 1 | # Intercom UX: ориентиры Slack / Mattermost (границы v1) |
| 2 | |
| 3 | **Статус:** продуктовый playbook (детали attach — **ADR**). |
| 4 | **Дата:** 2026-05-17 |
| 5 | **Норматив:** attach / якоря — [ADR 0128](../adr/0128-intercom-attachment-anchors-and-code-references.md); fenced / MD в теле — [ADR 0129](../adr/0129-intercom-message-body-markdown-and-fenced-code.md) |
| 6 | **Связь:** [intercom-design-hub-v1.md](intercom-design-hub-v1.md) · [0080](../adr/0080-intercom-naming-and-multi-party-channel-model.md) · [0072](../adr/0072-chat-topic-cards-intent-melody-keyboard-contract.md) · [0119](../adr/0119-chat-slash-commands-intercom-surface.md) · [0057](../adr/0057-chat-surface-pipeline-adoption.md) · [0120](../adr/0120-primary-work-surface-intercom-or-editor.md) · [north-star](north-star-cursor-mcp-cascade-workbench-v1.md) |
| 7 | |
| 8 | ## Зачем этот документ |
| 9 | |
| 10 | **Intercom** в CascadeIDE — не «чат с ботом», а **канал связи в сессии работы** ([0080](../adr/0080-intercom-naming-and-multi-party-channel-model.md)). Пользователи и команды уже знают **Slack** и **Mattermost**: composer внизу, слэш-команды, треды, роли сообщений. |
| 11 | |
| 12 | Этот чертёж фиксирует, **какие паттерны** брать как вдохновение для **UX в IDE**, и что **сознательно не копировать**. Attach и code references — **[0128](../adr/0128-intercom-attachment-anchors-and-code-references.md)**; здесь — **playbook** для дизайна и приоритизации. |
| 13 | |
| 14 | --- |
| 15 | |
| 16 | ## Два слоя (не смешивать) |
| 17 | |
| 18 | | Слой | Что это | Ориентир Slack/MM | |
| 19 | |------|---------|-------------------| |
| 20 | | **A. Intercom в IDE** | Сессия + агент + workspace + MCP; Skia pipeline [0057](../adr/0057-chat-surface-pipeline-adoption.md) | Паттерны **UI и поведения**, не бэкенд | |
| 21 | | **B. Внешний командный контур** | Люди вне IDE, организация, retention, мобилки | Mattermost / Matrix / корп. API — **интеграция**, не переписывание ([0080 §5](../adr/0080-intercom-naming-and-multi-party-channel-model.md#adr0080-p5)) | |
| 22 | |
| 23 | Документ в основном про **слой A**. Слой B — **[ADR 0132](../adr/0132-intercom-federated-transport-and-multi-client-boundary.md)** (transport, Web, MCC, federation) и **[ADR 0142](../adr/0142-intercom-open-wire-pluggable-transports.md)** (открытый wire, pluggable transport, опциональные мосты); **фильтр ленты по роли** — **[ADR 0143](../adr/0143-intercom-feed-participant-lens.md)** (participant lens, не transport channel). Playbook остаётся UX-ориентиром. |
| 24 | |
| 25 | --- |
| 26 | |
| 27 | ## Что заимствуем (in scope для UX) |
| 28 | |
| 29 | ### Composer и command line |
| 30 | |
| 31 | - **Поле ввода внизу** (или закреплённый composer в Forward при [0120](../adr/0120-primary-work-surface-intercom-or-editor.md)) — привычная «точка речи» сессии. |
| 32 | - **Слэш-команды** с **иерархическим autocomplete** (`/` → namespace → action), как в Slack — [0119](../adr/0119-chat-slash-commands-intercom-surface.md). Discoverability **через подсказки**, не через запоминание `/br`. |
| 33 | - **Обычный текст** без ведущего `/` уходит агенту; слэш — **локальное** действие IDE/Intercom (Reject неизвестного `/`, без pass-through агенту). |
| 34 | |
| 35 | ### Навигация по темам (сильнее, чем «просто лента») |
| 36 | |
| 37 | - **Topic cards + overview/detail + back** [0072](../adr/0072-chat-topic-cards-intent-melody-keyboard-contract.md) — аналог «списка каналов/тредов», но заточен под **линии работы** в сессии, а не произвольные комнаты. |
| 38 | - **Одна тема** → default detail; **несколько тем** → default overview карточек. |
| 39 | - **Main line** — одна из карточек, не скрытый режим «без карточек». |
| 40 | |
| 41 | ### Типы сообщений и «кто в эфире» |
| 42 | |
| 43 | | Тип (продуктово) | Примеры | Заметка | |
| 44 | |------------------|---------|---------| |
| 45 | | **Human** | оператор | | |
| 46 | | **Agent** | LLM / ACP | | |
| 47 | | **System** | сборка, git, MCP-статус, ошибка инструмента | визуально отличать от диалога (как system/bot в MM) | |
| 48 | | *(будущее)* **Operator external** | реплика из Mattermost | слой B, синхронизация по контракту | |
| 49 | |
| 50 | Минимум v1: заложить **тип сообщения** в модель событий [0045](../adr/0045-agent-chat-persistence-event-log-and-projections.md), даже если в UI пока только human + agent. |
| 51 | |
| 52 | ### Плотность и читаемость ленты |
| 53 | |
| 54 | - Хронология **внутри темы**; ветвления — данные [0031](../adr/0031-agent-chat-clarification-batches-and-threading.md), не хаотичные прыжки UI. |
| 55 | - **Карточка темы** со **сводкой** [0096](../adr/0096-intercom-topic-card-summary-and-product-spine.md) — аналог preview последнего сообщения в списке каналов. |
| 56 | - **Product spine** — ортогонален main thread; не смешивать с обычной лентой без явного действия. |
| 57 | |
| 58 | #### Лента без «пузырей» (как Slack/MM, не как Telegram) |
| 59 | |
| 60 | У **Slack и Mattermost** в канале **нет** messenger-пузырей (цветные «шарики» слева/справа) — плоская **лента**: аватар (опционально) + **имя + время** + текст на фоне канала. У Cascade Intercom **целевое направление — то же**: пузыри **отвлекают** от кода и смысла реплики; лишний визуальный шум в Forward. |
| 61 | |
| 62 | | Делаем | Не делаем | |
| 63 | |--------|-----------| |
| 64 | | **Большинство** реплик — одна плоская строка, **без** рамки и без заливки | Оформлять каждое сообщение как «карточку» | |
| 65 | | Роль human / agent / system — **колонка слева** (`SkiaChatFeedRoleRail` + единый **`SkiaChatFeedLayout`**) + тело справа; подряд идущие реплики той же роли — без повтора метки | Залитые rounded **bubble** вокруг каждой реплики | |
| 66 | | Локальные слэши (`/help`, audience self) — метка **«Система»**, не «Справка» | Дублировать роль в meta-строке и сверху тела | |
| 67 | | **Акцент редко:** рамка / inset только когда есть смысл прервать (ошибка, блокер, результат слэша, diff) | Рамка «для красоты» или на каждую реплику агента | |
| 68 | | System / slash-outcome — по умолчанию **компактная строка**; рамка — только при ошибке или явном статусе | Псевдо-диалог «два собеседника в шариках» | |
| 69 | |
| 70 | **Правило акцента:** если рамкой/inset помечено **больше малой доли** ленты, акцент **теряет смысл** — как в Dark Cockpit ([handbook §2.5](cide-design-handbook-v1.md)): в норме лента **тихая**, прерывание — по делу. |
| 71 | |
| 72 | **Текущее состояние:** в коде/теме ещё есть legacy `message_bubble` / `ChatMessageBubbleBackground` (Avalonia/Skia) — **долг** на эволюцию к flat feed ([0123](../adr/0123-intercom-full-skia-surface-evolution.md)). В макетах для дизайнера — **не** рисовать Telegram/iMessage-пузыри; ориентир — скриншот Slack (плоская лента). |
| 73 | |
| 74 | *Исключение термина:* в ADR про слэш иногда «пузырь» = **одна строка результата** `/command` в ленте (не chat-bubble); при рефакторинге лучше «slash outcome row». |
| 75 | |
| 76 | ### Упоминания и контекст в composer |
| 77 | |
| 78 | **Разные пространства имён** — не путать людей, команды IDE и «что уходит агенту вместе с текстом». |
| 79 | |
| 80 | | Префикс / путь | Объект | Зачем | Статус | |
| 81 | |----------------|--------|--------|--------| |
| 82 | | **`@…`** | **Только люди** (`@mention`) | Как Slack/MM: участник, уведомление; **не** файлы и не код | v2+ / слой B [0080 §5](../adr/0080-intercom-naming-and-multi-party-channel-model.md#adr0080-p5) | |
| 83 | | **`/…`** | **Команды IDE** (в т.ч. `/attach …`) | Единый каталог + autocomplete [0119](../adr/0119-chat-slash-commands-intercom-surface.md) | частично Implemented | |
| 84 | |
| 85 | **Решение (база):** **`@` — только люди**; артефакты workspace к реплике — через **`/attach …`** в том же slash-каталоге. **`@cc:` не используем.** |
| 86 | |
| 87 | #### Что считаем «вложением» (не только «код») |
| 88 | |
| 89 | Для агента полезны **любые файлы решения**: `.cs`, `.md`, `.txt`, `.toml`, `.json`, логи — не только «исходники». Поэтому в slash **не зажимаемся в `/attach code`** как единственный корень. |
| 90 | |
| 91 | | Термин в UX | Смысл | Пример | |
| 92 | |-------------|--------|--------| |
| 93 | | **`file`** | Файл в workspace (тип по расширению не важен для пути) | `notes.txt`, `README.md`, `Foo.cs` | |
| 94 | | **`selection`** | Текущее **выделение** в активном редакторе (какой бы ни был файл) | фрагмент из `.txt` или `.cs` | |
| 95 | | ~~`code`~~ как корень slash | Слишком узко и путает с «только .cs» | **не используем** как namespace; в prose можно говорить «код» | |
| 96 | |
| 97 | **Параллель с [0125](../adr/0125-slash-workspace-file-commands-and-dynamic-completion.md):** |
| 98 | |
| 99 | | Slash | Эффект | |
| 100 | |-------|--------| |
| 101 | | **`/file open`** … | **Открыть** файл в редакторе (навигация) | |
| 102 | | **`/attach file`** … | **Прикрепить** ссылку к **черновику** реплики (контент для агента) | |
| 103 | |
| 104 | Один autocomplete по файлам solution можно **переиспользовать** (динамические подсказки пути); разный `command_id` и исход: open vs attach. |
| 105 | |
| 106 | #### Привязка к реплике — UX (черновик) |
| 107 | |
| 108 | Не путать с **действием в редакторе**: |
| 109 | |
| 110 | | Сейчас (Implemented) | Смысл | Пример | |
| 111 | |------------------------|--------|--------| |
| 112 | | **`/editor line select`** / **`delete`** | **Сделать** в редакторе | `/editor line select 5 10` — [0124](../adr/0124-slash-parametric-editor-line-commands.md) | |
| 113 | | **`/file open`** … | **Открыть** файл | [0125](../adr/0125-slash-workspace-file-commands-and-dynamic-completion.md) | |
| 114 | | **`/attach file`** / **`/attach selection`** / **`/attach scope`** | **Вложение** в сообщение агенту | [0128](../adr/0128-intercom-attachment-anchors-and-code-references.md) *(фазы 1–3)* | |
| 115 | | **`/editor select code [M:…]`** / **`/editor reveal code […]`** | **Select / reveal** в редакторе без attach | [0131](../adr/0131-editor-slash-select-code-by-bracket-reference.md) *(в коде)* | |
| 116 | |
| 117 | **Рекомендуемый namespace:** **`/attach`** с подкомандами (не `/codecontext`). |
| 118 | |
| 119 | | Команда (черновик) | Поведение | Wire (идея) | |
| 120 | |--------------------|-----------|-------------| |
| 121 | | **`/attach selection`** | Выделение из **текстового** редактора → chip | `path` + `lineStart`/`lineEnd` + optional excerpt | |
| 122 | | **`/attach file`** + autocomplete | **Файл** → chip; диапазон строк — **только если уместен** | см. §«Формы вложения» | |
| 123 | | **`/attach file <path>`** | Весь файл (обязательно для `.png`, `.dll`, …) | `path` only | |
| 124 | | **`/attach file <path> <start> <end>`** | Участок **текстового** файла | только line-addressable типы | |
| 125 | | *алиас* `selected` → `selection` | Один канон в ADR | — | |
| 126 | |
| 127 | #### Формы вложения (не у всего есть «строки») |
| 128 | |
| 129 | **Диапазон строк** имеет смысл только для **line-addressable** артефактов (исходники, `.md`, `.txt`, `.json`, лог…). У **бинарных и медиа** — только **файл целиком**. |
| 130 | |
| 131 | | Форма | Когда | Chip в composer (пример) | Wire | |
| 132 | |-------|--------|---------------------------|------| |
| 133 | | **`whole-file`** | `.png`, `.jpg`, `.pdf`, `.dll`, `.zip`, …; или явно «весь файл» | `assets/diagram.png` | `path` | |
| 134 | | **`text-range`** | Текстовый файл + строки или выделение | `Foo.cs L12–18` | `path` + `lineStart`/`lineEnd` | |
| 135 | | **`selection`** | Фрагмент из открытого редактора | как `text-range` | из active editor | |
| 136 | |
| 137 | **Пример:** `/attach file docs/wireframe.png` — **без** `<start> <end>`; autocomplete **не предлагает** строки для известных binary/media расширений. Если пользователь ввёл диапазон для `.png` — **ошибка в slash** (как у [0124](../adr/0124-slash-parametric-editor-line-commands.md) I3), не молчаливый no-op. |
| 138 | |
| 139 | **Агент:** для `whole-file` + image — отдельная политика (vision / не отправлять / только path) — **не этот документ**; здесь фиксируем только UX attach и wire. В metadata: `attachmentShape` + опционально `contentKind` (`image`, `source`, `text`, …). |
| 140 | |
| 141 | #### В середине предложения (несколько вложений) |
| 142 | |
| 143 | Типичный запрос: *«Этот метод реализован у нас в **〔код1〕**, а этот — в **〔код2〕**»* — два якоря **внутри** одной реплики, не только в конце. |
| 144 | |
| 145 | **Целевой UX composer:** не plain text, а **текст + встроенные chip-токены** вложений (как placeholder в строке; в ленте после send — кликабельные метки, flat feed). |
| 146 | |
| 147 | | Способ | Как пользователь делает | Заметка | |
| 148 | |--------|-------------------------|---------| |
| 149 | | **A. `/attach …` в позиции курсора** *(приоритет v2)* | «…в », `/attach selection` или `/attach file Foo.cs 1 20` → **chip в курсор** | Discoverability; autocomplete пути | |
| 150 | | **B. Кнопка «Прикрепить»** | Выделение или файл → chip в курсор | Дублирует A для мыши | |
| 151 | | **D. Скобки `[…]` inline** *(параллельно A/B)* | `[M:Method]` или запасной `[Foo.cs 50 100]` | §«Якорь: блок, не путь»; resolve при send | |
| 152 | | **C. `@file` inline** *(запасной, если D/A неудобны)* | `@file` + autocomplete | **Не** `@cc`; не путать с `@ivan` и `/file open` | |
| 153 | |
| 154 | #### Якорь: человек думает **блоком**, не путём и не строками |
| 155 | |
| 156 | В голове обычно не `src/Domain/Foo.cs:50–100`, а **«этот метод»**, **«вот этот кусок»**, **«этот тип»**. Путь и номера строк — **технический снимок** для IDE и агента; их можно **вычислить** при send (выделение, Roslyn, активный файл). |
| 157 | |
| 158 | | Роль | Что помнит человек | Что хранит wire (канон) | |
| 159 | |------|-------------------|-------------------------| |
| 160 | | **Смысл** | метод / выделение / «этот файл» (png) | `memberKey` и/или excerpt; `attachmentShape` | |
| 161 | | **Производное** | *не обязан* | `file` + `lineStart`/`lineEnd` — **resolve при send** | |
| 162 | | **В ленте** | короткая метка | `GetUserAsync` или `выделение`; путь/строки — **мелко или по hover** | |
| 163 | |
| 164 | **Следствие для UX:** приоритет ввода — **`/attach selection`**, кнопка «Прикрепить выделение», **`[M:MethodName]`** с autocomplete; **`[Foo.cs 50 100]`** — запасной и power-user путь, не главная догма. |
| 165 | |
| 166 | #### Синтаксис `[…]` (скобки в тексте) |
| 167 | |
| 168 | Удобно для **середины предложения** без слэша: *«логика в [M:HandlePayment], а тест в [M:PaymentTests.ShouldFail]»* — без набора пути и строк. |
| 169 | |
| 170 | **Не второй тип вложения** — **вторая поверхность ввода** того же anchor. В wire — canonical anchor (member + снимок lines); в UI — метка по **смыслу**, не по диску. |
| 171 | |
| 172 | | Форма ввода (черновик) | Смысл | После parse | |
| 173 | |------------------------|--------|-------------| |
| 174 | | `[M:GetUserAsync]` | Member; **F:** из активного файла или autocomplete solution | resolve → lines + `memberKey` | |
| 175 | | `[Foo.cs M:GetUserAsync]` | Member в явном файле | то же | |
| 176 | | `[выделение]` / chip из selection | Текущее выделение редактора | `selection` shape | |
| 177 | | `[Foo.cs 50 100]` | *Запасной* positional ([0124](../adr/0124-slash-parametric-editor-line-commands.md)) | `text-range` | |
| 178 | | `[Foo.cs]` / `[diagram.png]` | Файл целиком (медиа, конфиг) | `whole-file` | |
| 179 | |
| 180 | **Отображение в ленте** (пример): `GetUserAsync` · при hover `Foo.cs L50–100 (на момент отправки)` — строки для ориентира, не как главный заголовок. |
| 181 | |
| 182 | **Парсер (принципы):** |
| 183 | |
| 184 | - Узнаём только **workspace-path-like** токен внутри `[` `]` (сегменты с `/`, расширение `.cs`, `.md`, …) — не каждые скобки в цитате кода. |
| 185 | - **Не** путать с `@mention` (`@` — люди; `[` — артефакты). |
| 186 | - **Не** путать с markdown-ссылкой `[label](url)` — у attach **нет** `(` после `]`. |
| 187 | - Литеральные `[` в тексте — экранирование TBD (`\[` или `[[`), в v1 можно не поддерживать, если редко. |
| 188 | |
| 189 | **Composer UX:** при вводе `]` — optional **подсветка** распознанного anchor; Tab на пути — autocomplete как у [0125](../adr/0125-slash-workspace-file-commands-and-dynamic-completion.md). Альтернатива slash: быстрее для тех, кто печатает prose; slash остаётся для discoverability и `selection`. |
| 190 | |
| 191 | Пример (человеко-ориентированный ввод **D**): |
| 192 | |
| 193 | ```text |
| 194 | Оплата у нас в [M:HandlePayment], а регрессия — в [M:PaymentTests.ShouldFail] |
| 195 | ↑ member (path resolve при send) ↑ member |
| 196 | в ленте: HandlePayment PaymentTests.ShouldFail |
| 197 | hover: Foo.cs L120–185 @ send PaymentTests.cs L40–62 @ send |
| 198 | ``` |
| 199 | |
| 200 | Пример **запасной** positional (агент, paste, нет Roslyn): |
| 201 | |
| 202 | ```text |
| 203 | см. [Foo.cs 50 100] |
| 204 | ``` |
| 205 | |
| 206 | **Отправка:** anchors живут **в теле** черновика (как chip или распознанные `[…]`); в ленте — **inline-метки** (без balloon). Агент получает **структурированный** список вложений + prose (offsets в тексте). |
| 207 | |
| 208 | #### Внутри метода: «второй `for`», без выделения и без имени |
| 209 | |
| 210 | `[M:Foo]` покрывает **весь** `void Foo() { … 500 строк … }`, но не «второй цикл `for`» внутри. Это нормальный случай; не сводить к «запомни строки». |
| 211 | |
| 212 | | Подход | Как в UI | Wire / лента | |
| 213 | |--------|----------|--------------| |
| 214 | | **1. Выделить блок** *(H0)* | Расширить выделение до `for` (Expand selection) → `/attach selection` | `selection` + excerpt; метка «фрагмент» или `Foo › for` | |
| 215 | | **2. Каретка + scope** *(H0b, целевой)* | Курсор **внутри** нужного `for` → `/attach scope` или кнопка «Прикрепить блок под курсором» | Roslyn: **innermost** синтаксический span (`ForStatement`, `IfStatement`, …); `scopeKind` + excerpt; в ленте `Foo › for (2)` если в методе несколько | |
| 216 | | **3. Member + prose** *(v1 допустимо)* | `[M:Foo]` в тексте + фраза «второй `for`» | Вложение = весь метод (или excerpt метода) + **prose** как уточнение для агента; у человека в ленте `Foo` + текст реплики | |
| 217 | | **4. Structural sub-anchor** *(v2/v3)* | `[M:Foo S:for:2]` или picker: `Foo` → список `for`/`if` внутри ([0053](../adr/0053-semantic-map-control-flow-pfd.md)) | `memberKey` + `syntaxPath` / индекс однотипных узлов; re-resolve у получателя | |
| 218 | | **5. Positional внутри метода** *(M0)* | `[Foo.cs 220 245]` только если иначе никак | Локальный hint; не primary | |
| 219 | |
| 220 | **Рекомендация по продукту:** |
| 221 | |
| 222 | - **Не заставлять** помнить строки для «второго for». |
| 223 | - **v1:** H0 (выделил) или **3** (весь `Foo` + сказал словами); параллельно заложить **H0b** (`/attach scope`) — одна команда, каретка в цикле, без ручного выделения 40 строк. |
| 224 | - **v2:** picker структурных узлов внутри `[M:Foo]`; опционально `S:for:2` в грамматике `[…]`. |
| 225 | - **Excerpt обязателен** для безымянных блоков: несколько строк текста @ send — то, что одинаково у отправителя, получателя и агента, даже если lines разъехались. |
| 226 | |
| 227 | ```text |
| 228 | В [M:Foo] меня смущает второй for — [attach scope @ caret был бы: Foo › for (2)] |
| 229 | ``` |
| 230 | |
| 231 | **Клик по метке `Foo › for (2)`:** re-resolve этот `ForStatement` в **текущем** файле получателя → рамка; не «строка 220 у отправителя». |
| 232 | |
| 233 | ##### Слои грамматики (смысл → снимок на диске) |
| 234 | |
| 235 | **Порядок приоритета для человека** (не «сначала путь, потом member»): |
| 236 | |
| 237 | | Слой | Пример ввода | Зачем | |
| 238 | |------|----------------|--------| |
| 239 | | **H0 selection** | `/attach selection`, кнопка, chip | Ноль памяти path/lines — **главный** путь | |
| 240 | | **H0b scope @ caret** | `/attach scope` (каретка внутри `for`) | Блок **без имени**: innermost `for`/`if`/… по Roslyn — см. §«Внутри метода» | |
| 241 | | **H1 member** | `[M:HandlePayment]`, `[Foo.cs M:…]` | Имя метода/члена; path/lines — resolve | |
| 242 | | **H2 whole file** | `[diagram.png]`, `[appsettings.json]` | Когда важен файл, не символ | |
| 243 | | **M0 positional** | `[Foo.cs 50 100]`, `[Foo.cs L:50 100]` | Агент, paste, нет символа, legacy | |
| 244 | |
| 245 | **`anchor.notation.canonical`** *(агент/MCP; legacy «L2 field record»)*: `[F:…; M:…; L:…]` — тот же canonical anchor; в ленте для человека рендер **H1**. |
| 246 | |
| 247 | | Слой | Пример ввода | Кто печатает | После send | |
| 248 | |------|----------------|--------------|------------| |
| 249 | | **H0–H2** | см. выше | человек | `memberKey` / selection + **resolved** `file` + lines | |
| 250 | | **M0** | `[Foo.cs 50 100]` | агент, power user | `text-range` без member | |
| 251 | | **`anchor.notation.canonical`** | `[F:Foo.cs; M:GetUserAsync]` | агент, шаблоны | то же canonical; UI как H1 | |
| 252 | |
| 253 | **Рекомендация по форме readable / canonical (один канон, не два):** см. [naming-layers-v1.md](../design/naming-layers-v1.md) §5. |
| 254 | |
| 255 | - Ключи **`F` `M` `L` `T`** (File, Member, Lines, Type) — **опциональные**, порядок **не важен**; разделитель полей — **`;`** или **пробел между парами `Key:value`** (выбрать **один** в ADR). |
| 256 | - **Не** смешивать в продукте две нотации «через запятую `T:, M:`» и «через точку с запятой `type; member:`» — парсер и подсказки раздвоатся. |
| 257 | - Пример **`anchor.notation.readable`** (legacy intercom «L1»): `[Foo.cs M:GetUserAsync]` · `[Foo.cs L:50 100]` · комбо `[Foo.cs M:GetUserAsync L:50 100]` (lines — уточнение, если member размазан по partial). |
| 258 | - Пример **`anchor.notation.canonical`**: `[F:Foo.cs; M:GetUserAsync; L:50-100]` — для агента; в UI ленты рендерить как `Foo.cs › GetUserAsync`. |
| 259 | |
| 260 | | Поле | Смысл | Заметка | |
| 261 | |------|--------|---------| |
| 262 | | **F** | Путь в workspace | обязателен, если нет positional `Foo.cs` в начале | |
| 263 | | **L** | `start end` или `start-end` | 1-based inclusive; после **M:** может заполниться автоматически | |
| 264 | | **M** | Имя члена (method/property/…) | **resolve при send** ([0058](../adr/0058-agent-roslyn-mcp-coupling-settings-toml.md)); неоднозначность → ошибка в composer + picker overload | |
| 265 | | **T** | Имя типа (класс) | если **M** не уникален в файле; опционально | |
| 266 | |
| 267 | **Стабильность и «две правды» по строкам** |
| 268 | |
| 269 | Строки **плывут** не только от коммитов, но и **между участниками одного сообщения**: |
| 270 | |
| 271 | | Причина расхождения | Пример | |
| 272 | |---------------------|--------| |
| 273 | | Разный снимок репозитория | у получателя другая ветка / локальные правки | |
| 274 | | Разный контекст IDE | другой активный файл, не тот partial | |
| 275 | | Настройки отображения | перенос, шрифт, масштаб — **видимый** контекст другой; номера строк в файле на диске те же, но «где на экране» — нет | |
| 276 | | Только positional anchor (M0) | отправитель писал `[Foo.cs 50 100]` — получатель открывает **те же** числа, хотя метод уже сдвинулся | |
| 277 | |
| 278 | **Вывод для продукта:** номера строк в сообщении — **не общий контракт** между отправителем и получателем (и между человеком и агентом на другом снимке workspace). Это **локальный hint @ send** плюс fallback. |
| 279 | |
| 280 | | Что считать «устойчивым» в ленте | Что производное / локальное | |
| 281 | |----------------------------------|-----------------------------| |
| 282 | | **Member** (`M:`), имя типа, **excerpt** текста @ send | `lineStart`/`lineEnd` как единственная правда | |
| 283 | | **Selection snapshot** (хеш/якорь + excerpt) для H0 | «Открой строку 50» без символа | |
| 284 | | **File** для whole-file / медиа | Точный пиксель viewport | |
| 285 | |
| 286 | **Поведение у получателя (целевое):** |
| 287 | |
| 288 | 1. Если в wire есть **`memberKey`** → при клике **re-resolve** в *его* solution → рамка по **текущим** строкам; в UI опционально «было L50–100 @ send, сейчас L48–98». |
| 289 | 2. Если только lines (M0) → открыть по снимку + **предупреждение**, если файл не совпадает / диапазон пустой / сильный drift. |
| 290 | 3. **Excerpt** (несколько строк текста @ send) — то, что одинаково у всех в ленте; агент может оперировать им, даже если lines разъехались. |
| 291 | |
| 292 | В идеале в репо **не должно** быть рассинхрона, но UX **не строим** на предположении, что у всех одинаковые строки — строим на **смысле + excerpt**, строки — для IDE навигации после resolve. |
| 293 | |
| 294 | **Клик из ленты:** навигация по **смыслу** (member → текущий диапазон у *этого* получателя); M0-only — best-effort по снимку. |
| 295 | |
| 296 | **Не путать:** `M:` = member symbol, не «mention»; люди по-прежнему только `@`. |
| 297 | |
| 298 | **Паритет:** тот же диапазон, что `c:els:5:10` и `/editor line select 5 10` — общий binder; разный **эффект**: select = IDE action, attach = payload к сообщению. |
| 299 | |
| 300 | #### Клик по вложению в ленте (deep link) |
| 301 | |
| 302 | После send inline-метка вложения в тексте реплики — **ссылка-якорь** ([0080 future](../adr/0080-intercom-naming-and-multi-party-channel-model.md#adr0080-future-modalities): открыть, прыгнуть, показать участок). Один и тот же anchor в wire, что при attach. |
| 303 | |
| 304 | | Шаг | Поведение (целевое v2) | |
| 305 | |-----|-------------------------| |
| 306 | | 1 | **Открыть** файл в редакторе (или preview для не-текста), сфокусировать вкладку | |
| 307 | | 2 | **Прокрутить** диапазон в видимую область (`text-range` / `selection`) | |
| 308 | | 3 | **Показать участок** — по умолчанию **не** `Selection` в редакторе | |
| 309 | |
| 310 | **Почему не выделение по умолчанию:** активное выделение = риск случайно стереть/заменить фрагмент одной клавишей после клика из чата. Навигация «посмотреть, о чём речь» должна быть **безопасной**. |
| 311 | |
| 312 | **Рекомендуемый режим v1 для клика из Intercom:** **transient range highlight** — рамка/полоса вокруг строк (или gutter-band), по духу **`highlight_control`** / `AgentHighlightOverlay` ([ui-layout](../ui-ux/cascade-ide-ui-layout-v1.md): рамка поверх, `IsHitTestVisible=false`, не меняет фокус ввода в редакторе). Курсор редактора **не обязан** попадать внутрь диапазона; selection buffer **не трогаем**. |
| 313 | |
| 314 | | `attachmentShape` | Клик | |
| 315 | |-------------------|------| |
| 316 | | **`text-range`** / **`selection`** | open + scroll + **рамка** на `lineStart`…`lineEnd` | |
| 317 | | **`whole-file`** (в т.ч. `.png`) | open / preview; **без** строк и без рамки по строкам | |
| 318 | |
| 319 | **Опционально (мощный режим):** |
| 320 | |
| 321 | | Действие | Эффект | |
| 322 | |----------|--------| |
| 323 | | **Shift+клик** или пункт меню «Выделить в редакторе» | тот же якорь → `SelectInEditor` (как сегодня `go_to_position` для агента) | |
| 324 | | Настройка `[intercom.attachments.code].navigate` | `reveal` *(default)* \| `select` | |
| 325 | |
| 326 | **Разделение с агентом:** MCP `go_to_position` сегодня зовёт `SelectInEditor` — уместно, когда агент **готовит правку**. Клик человека из ленты — другой intent (`command_id` вроде `intercom.reveal_attachment` / `editor.reveal_range`), тот же binder строк, **другой presentation mode**. Отдельный ADR: editor range adornment vs reuse CDS attention channel. |
| 327 | |
| 328 | **Сейчас в коде:** deep link из ленты и range-frame **не реализованы**; для агента уже есть `go_to_position` → select. Документ фиксирует **целевой UX**, не текущее поведение. |
| 329 | |
| 330 | **`@file` vs `@mention`:** если понадобится **(C)** — только зарезервированное `@file`, не произвольный `@notes.txt`. |
| 331 | |
| 332 | **Канон:** [0128](../adr/0128-intercom-attachment-anchors-and-code-references.md) — не `/attach code`, не `@cc:`; chips в середине предложения; wire [0045](../adr/0045-agent-chat-persistence-event-log-and-projections.md). |
| 333 | |
| 334 | **Связь:** [0080 future](../adr/0080-intercom-naming-and-multi-party-channel-model.md#adr0080-future-modalities), [0039](../adr/0039-workspace-navigation-affordances.md). |
| 335 | |
| 336 | ### Входы (ортогональность) |
| 337 | |
| 338 | Один `command_id` — несколько поверхностей ([0013](../adr/0013-command-surface-and-discoverability.md), [handbook §2.6](cide-design-handbook-v1.md)): |
| 339 | |
| 340 | | Вход | Роль | |
| 341 | |------|------| |
| 342 | | Pointer / hit-target | тактика на карточках | |
| 343 | | **Палитра (Ctrl+Q)** | репетиция: полный каталог, fuzzy-поиск | |
| 344 | | **CascadeChord (Ctrl+K)** + Melody `c:` | выступление: мнемоники **в палитре/аккорде**, не в слэше | |
| 345 | | **Chat slash** + autocomplete | канал сессии: CLI в composer ([0119](../adr/0119-chat-slash-commands-intercom-surface.md) Implemented) | |
| 346 | | MCP / агент | тот же `command_id` [0030](../adr/0030-command-ids-hotkeys-and-ui-registry-layers.md) | |
| 347 | |
| 348 | --- |
| 349 | |
| 350 | ## Что не копируем (out of scope / non-goals) |
| 351 | |
| 352 | | Не делаем | Почему | |
| 353 | |-----------|--------| |
| 354 | | **Сервер Slack/MM внутри Cascade** | [0080 §5](../adr/0080-intercom-naming-and-multi-party-channel-model.md#adr0080-p5): отдельный продукт | |
| 355 | | **WebView полного клиента MM/Slack** в IDE без ADR | «Две правды», фокус, SSO — только осознанно | |
| 356 | | **Одна бесконечная лента** как единственный режим | Ломает topic cards [0072](../adr/0072-chat-topic-cards-intent-melody-keyboard-contract.md) | |
| 357 | | **Короткие слэш-мнемоники** (`/br`) | Discoverability только autocomplete; сжатие — `c:` Melody | |
| 358 | | **Messenger-пузыри** (Telegram/iMessage-style) | Отвлекают; у Slack/MM их нет — flat feed; акцент — рамка/inset, см. §«Лента без пузырей» | |
| 359 | | **Реакции, GIF, emoji-first** | Шум для IDE-цикла; отложить | |
| 360 | | **Полный поиск по истории** как в MM Enterprise | v2+; не блокер v1 Intercom | |
| 361 | | **Паритет каждой фичи MM** (threads в threads, workflows) | Берём **ментальную модель**, не feature checklist | |
| 362 | | **`/attach code` как корень** | Узко; любой `.txt`/`.md` — **`/attach file`** | |
| 363 | | **`@cc:`** | Не используем | |
| 364 | |
| 365 | --- |
| 366 | |
| 367 | ## Карта паттернов: Slack/MM → Cascade |
| 368 | |
| 369 | | Паттерн Slack / Mattermost | В Cascade Intercom | |
| 370 | |----------------------------|-------------------| |
| 371 | | Channel list | Topic overview (карточки) [0072](../adr/0072-chat-topic-cards-intent-melody-keyboard-contract.md) | |
| 372 | | Thread | Тема / `ThreadNode` [0031](../adr/0031-agent-chat-clarification-batches-and-threading.md) | |
| 373 | | `/command` + picker | [0119](../adr/0119-chat-slash-commands-intercom-surface.md) | |
| 374 | | `@mention` (люди) | Упоминание участника; уведомление — как Slack/MM; v2+ / внешний контур [0080 §5](../adr/0080-intercom-naming-and-multi-party-channel-model.md#adr0080-p5) | |
| 375 | | `[path]` / `[path start end]` в тексте | Тот же attach-anchor, что `/attach`; ввод в середине фразы | |
| 376 | | `/attach file` / `/attach selection` | Вложение в реплику; параллель `/file open` [0125](../adr/0125-slash-workspace-file-commands-and-dynamic-completion.md) | |
| 377 | | Клик по file anchor в сообщении | open + scroll; **рамка** диапазона (default), не selection; Shift → select | |
| 378 | | `/editor line …` | Действие в редакторе — [0124](../adr/0124-slash-parametric-editor-line-commands.md) Implemented | |
| 379 | | Сообщение в канале (flat) | Строка ленты: имя + время + текст; **без** balloon | |
| 380 | | Bot / system message | System role + build/git/MCP lines (компактно, не пузырь) | |
| 381 | | Pin / bookmark | Spine, session tree [0116](../adr/0116-intercom-session-tree-and-agent-message-steering.md) | |
| 382 | | Unread badge | IDE Health / уведомления кабины (не дублировать MM) | |
| 383 | |
| 384 | --- |
| 385 | |
| 386 | ## Skia и «ощущение Slack» |
| 387 | |
| 388 | [0044](../adr/0044-avalonia-host-skia-agent-chat-surface.md) / [0057](../adr/0057-chat-surface-pipeline-adoption.md): вдохновение — **иерархия экранов, composer, типографика, плоская лента + системные строки**, а не HTML-виджеты Slack и не messenger-пузыри. Pipeline **Intent → Layout → Render** сохраняет intent-first [0072 §5](../adr/0072-chat-topic-cards-intent-melody-keyboard-contract.md): pointer и слэш не дергают Skia напрямую. |
| 389 | |
| 390 | **Визуальные ориентиры v1 (мягкие):** |
| 391 | |
| 392 | - human / agent — различимые **роли** (цвет имени, иконка), **без** balloon; **без** рамки на обычной реплике; |
| 393 | - system / slash-outcome — по умолчанию компактная строка; **рамка/inset — исключение** (ошибка, fail, требует действия); |
| 394 | - topic card — заголовок + сводка + метаданные (время, непрочитанное — по мере готовности модели). |
| 395 | |
| 396 | --- |
| 397 | |
| 398 | ## Приоритеты внедрения (согласовано с ADR) |
| 399 | |
| 400 | | Приоритет | Содержание | ADR | |
| 401 | |-----------|------------|-----| |
| 402 | | P0 | Topic cards, drill-in/back, adaptive default | 0072 | |
| 403 | | P0 | Слэш + **обязательный** autocomplete; без коротких слэш-алиасов | 0119 | |
| 404 | | P1 | Типы сообщений (system/agent/human) в ленте | 0045, 0080 | |
| 405 | | P1 | Intercom-centric Forward (опционально) | 0120 | |
| 406 | | P2 | Attach по [0128](../adr/0128-intercom-attachment-anchors-and-code-references.md) фазы 0–2 | 0045, 0124/0125, 0058 | |
| 407 | | P3 | Внешний MM/Slack как канал команды | 0080 §5, отдельный ADR | |
| 408 | |
| 409 | --- |
| 410 | |
| 411 | ## Открытые вопросы |
| 412 | |
| 413 | 1. **Sidebar vs overview в Forward:** при [0120](../adr/0120-primary-work-surface-intercom-or-editor.md) — карточки тем слева (MM-style) или полноэкранный overview? |
| 414 | 2. **Имя в UI:** только «Intercom» или подзаголовок «как в командном чате» на первый релиз? [0080 open](../adr/0080-intercom-naming-and-multi-party-channel-model.md#adr0080-open). |
| 415 | 3. **Минимальный набор system-сообщений v1:** только build fail/success или шире (git, index)? |
| 416 | 4. **Критерии выбора внешнего провайдера (слой B):** self-host, API, SSO — до ADR интеграции. |
| 417 | 5. **0128 implementation:** schema в [0045](../adr/0045-agent-chat-persistence-event-log-and-projections.md); фазы 0–4. |
| 418 | 6. *(закрыто)* attach — [0128](../adr/0128-intercom-attachment-anchors-and-code-references.md); fenced vs anchor — [0129](../adr/0129-intercom-message-body-markdown-and-fenced-code.md). |
| 419 | 7. **Изображения в prompt агента:** политика vision vs path-only — отдельно от slash UX. |
| 420 | 8. *(отложено в [0128](../adr/0128-intercom-attachment-anchors-and-code-references.md))* `@file` inline — после фазы 2 `/attach` + `[path]`. |
| 421 | 9. *(закрыто)* L2 `F;M;L` — [0128](../adr/0128-intercom-attachment-anchors-and-code-references.md); `[` не парсить внутри fenced — [0129](../adr/0129-intercom-message-body-markdown-and-fenced-code.md) §5. |
| 422 | 10. *(v1 в [0128](../adr/0128-intercom-attachment-anchors-and-code-references.md))* reveal: overlay/gutter ~3 s; adornment — v2. |
| 423 | 11. **`/attach scope`:** innermost syntax span; нумерация `for (2)`; picker vs `S:for:2` — фаза 3 [0128](../adr/0128-intercom-attachment-anchors-and-code-references.md). |
| 424 | |
| 425 | --- |
| 426 | |
| 427 | ## История |
| 428 | |
| 429 | | Дата | Изменение | |
| 430 | |------|-----------| |
| 431 | | 2026-05-17 | Черновик: Slack/Mattermost как UX-ориентир; границы A/B; in/out of scope; карта паттернов. | |
| 432 | | 2026-05-19 | Лента без messenger-пузырей (flat feed как Slack); акцент редко (рамка/inset); legacy bubble — долг. | |
| 433 | | 2026-05-19 | Разделены `@mention` (люди) и `@cc:` (code context); черновик `selected` / autocomplete файлов. | |
| 434 | | 2026-05-19 | UX attach: `/attach code` vs `/editor line`; паритет binders 0124; `@` только люди, без `@cc:`. | |
| 435 | | 2026-05-19 | Вложения в середине предложения: chip в курсор; запасной `@file` inline (не `@cc`). | |
| 436 | | 2026-05-19 | `/attach file` + `/attach selection` вместо узкого `/attach code`; параллель `/file open`. | |
| 437 | | 2026-05-19 | Формы вложения: `whole-file` (png…) vs `text-range`; строки не у всех типов. | |
| 438 | | 2026-05-19 | Клик по attach: open + scroll + рамка (не selection); Shift → select; ≠ `go_to_position` агента. | |
| 439 | | 2026-05-19 | Inline `[path start end]` — ввод в prose; тот же wire, что `/attach`; отображение `L50–100`. | |
| 440 | | 2026-05-19 | Слои якоря: H0–H2 (смысл) vs M0 (path/lines); wire = resolve @ send; лента — member-first. | |
| 441 | | 2026-05-19 | Строки @ send — не контракт между участниками; re-resolve у получателя; excerpt устойчивее L50–100. | |
| 442 | | 2026-05-19 | Внутри метода: H0b `/attach scope`, member+prose, v2 `S:for:2` / structural picker. | |
| 443 | | 2026-05-19 | Норматив attach → [ADR 0128](../adr/0128-intercom-attachment-anchors-and-code-references.md). | |
| 444 | | 2026-05-19 | Fenced / MD в теле → [ADR 0129](../adr/0129-intercom-message-body-markdown-and-fenced-code.md). | |
| 445 | |