Forge
markdowndeeb25a2
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
2881. Если в wire есть **`memberKey`** → при клике **re-resolve** в *его* solution → рамка по **текущим** строкам; в UI опционально «было L50–100 @ send, сейчас L48–98».
2892. Если только lines (M0) → открыть по снимку + **предупреждение**, если файл не совпадает / диапазон пустой / сильный drift.
2903. **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
4131. **Sidebar vs overview в Forward:** при [0120](../adr/0120-primary-work-surface-intercom-or-editor.md) — карточки тем слева (MM-style) или полноэкранный overview?
4142. **Имя в UI:** только «Intercom» или подзаголовок «как в командном чате» на первый релиз? [0080 open](../adr/0080-intercom-naming-and-multi-party-channel-model.md#adr0080-open).
4153. **Минимальный набор system-сообщений v1:** только build fail/success или шире (git, index)?
4164. **Критерии выбора внешнего провайдера (слой B):** self-host, API, SSO — до ADR интеграции.
4175. **0128 implementation:** schema в [0045](../adr/0045-agent-chat-persistence-event-log-and-projections.md); фазы 0–4.
4186. *(закрыто)* 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).
4197. **Изображения в prompt агента:** политика vision vs path-only — отдельно от slash UX.
4208. *(отложено в [0128](../adr/0128-intercom-attachment-anchors-and-code-references.md))* `@file` inline — после фазы 2 `/attach` + `[path]`.
4219. *(закрыто)* 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.
42210. *(v1 в [0128](../adr/0128-intercom-attachment-anchors-and-code-references.md))* reveal: overlay/gutter ~3 s; adornment — v2.
42311. **`/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
View only · write via MCP/CIDE