ADR 0140: TCI — глифы статуса slash (✓ / ✕ / P(n)) и счётчик аргументов¶
Статус: Accepted (контракт глифов и отрисовка) · Proposed (счётчик P(n) в preview pipeline)
Дата: 2026-05-23
Связанные ADR¶
| ADR | Роль |
|---|---|
| 0138 | CCL, debounced slash-preview, Enter не блокируется |
| 0119 | Каталог slash, иерархический autocomplete |
| 0124 | Параметрические хвосты (/editor line select …) |
| 0125 | Динамическое дополнение путей / тем |
| 0128 | Attach-style chip: preview без блокировки |
| 0021 | EICAS W/C/A — отдельный канал от TCI preview |
Playbook: playbook-tci-v1.md.
Резюме¶
В полосах TCI (CCL, composer) slash-команда оборачивается в pill (SkiaStatusChip / SkiaSlashCommandChip). Слева в pill — компактный глиф статуса (не отдельный чекбокс снаружи поля). Семантика:
| Глиф | Смысл для оператора |
|---|---|
| ✓ | Команда распознана, обязательные аргументы на месте — Enter без сюрприза |
| ✕ | Команды нет в каталоге, опечатка namespace/action, синтаксис parametric |
| P или P(n) | Команда известна, ожидаются аргументы; n — сколько ещё нужно ввести (опционально) |
| A | Синоним «args» в подсказке/tooltip (не обязателен в v1 UI; см. § Глифы) |
Preview не блокирует Enter (0138, 0128 §9.1). Полный текст — tooltip (IntercomSlashPreviewToolTip / CommandLineSlashPreviewToolTip).
Контекст¶
Что уже было (до ADR)¶
SlashCommandPreviewKind:Ok,Incomplete,Error,Hint,None.- Маппинг в chip:
Ok→ ✓,Error→ ✕,Incomplete→ ⚠,Hint→ ℹ (SkiaStatusChip.GlyphFor). - Pill вокруг текста буфера (строка с
/), иконка левее начала slash-токена (IconLeadingOverhang).
Проблемы¶
- Иконка обрезалась: pill рисовался с иконкой слева от
/, а clip был только поtextBounds(иконка вне клипа). Исправлено: clip = union(textBounds, chipRect); по умолчанию иконка справа (tci_validation_icon = right); дляleft—LeadingChipLayoutGutter. - ⚠ для «ждём args» плохо читается при пошаговом autocomplete: оператор ожидает P / P(3), как в REPL.
- На полупути (
/intercom mes) preview часто даёт ✕ («нет команды»), хотя autocomplete ещё ведёт по ступеням — нужны правила «prefix match → Incomplete + P(n)», не Error.
Решение¶
1. Контракт глифа (отдельно от severity)¶
Ввести отображаемый глиф как производное от preview-результата, не смешивая с EICAS:
// Features/Chat/SlashCommandPreviewGlyph.cs (при имплементации)
public readonly record struct SlashCommandPreviewGlyph(
string IconText, // "✓", "✕", "P", "P(3)", "ℹ"
SlashCommandPreviewKind Kind,
int? ArgsRemaining = null);
SlashCommandPreviewResult расширить опциональным Glyph или вычислять через SlashCommandPreviewGlyphResolver из (Kind, ArgsRemaining, CatalogDescriptor).
Правило v1 (до счётчика):
SlashCommandPreviewKind |
Глиф по умолчанию |
|---|---|
Ok |
✓ |
Error |
✕ |
Incomplete |
P (заменить ⚠; tooltip сохраняет пояснение) |
Hint |
ℹ |
None |
(pill не рисуется) |
2. Счётчик P(n) (фаза B — Proposed)¶
Когда каталог / parser знает число обязательных хвостовых аргументов:
| Состояние | Глиф | Пример |
|---|---|---|
| Команда без хвоста, всё введено | ✓ | /intercom message anchors list |
| Нужен 1 хвост, пусто | P(1) | /intercom message select |
| Нужно 3 сегмента range, введён 1 | P(2) | /editor line select [3;5] + ещё сегменты |
| Неизвестная команда | ✕ | /intercom mesage (нет в каталоге) |
| Префикс совпал с catalog, action не допечатан | P | /intercom mes + autocomplete |
Источники n:
- Статические дескрипторы
ChatSlashCommandCatalog/IntentSlashCatalog(поляMinArgCount,ParametricKind). ParametricSegmentListParser— для[L;R]ожидаемый минимум сегментов.- Dynamic completion (0125) —
n = 1пока путь/тема не выбраны.
Не цель v1: точный подсчёт optional args; только обязательный минимум для «зелёного ✓».
3. Отрисовка (Skia)¶
- Примитив:
SkiaStatusChip.DrawIconGlyph— уже поддерживает произвольную строку. SkiaSlashCommandChip.DrawпринимаетSlashCommandPreviewGlyph(илиiconText) вместо толькоSlashCommandPreviewKind.- Инвариант layout: при
ShouldDrawChipрезервLeadingChipLayoutGutterслева вComputeInputRegion(CCL) илиComputeTextLayout(composer, slash в начале строки); при смене глифа наP(3)учитывать ширину глифа — при необходимости увеличитьIconBoxили gutter.
4. A11y¶
- Tooltip:
SlashCommandPreviewAccessibility.FormatToolTipдополняется: «Ожидается ещё 2 аргумента» приP(2). - Severity для цвета pill без изменений:
Incomplete→ Warning (янтарь),Ok→ Success,Error→ Error.
5. Preview rules (фаза B)¶
Добавить / уточнить в SlashCommandPreviewRulePipeline:
- Prefix catalog match →
Incomplete+P, неError, покаChatSlashAutocompleteещё предлагает ступени. - Unknown only когда нет ни одного подходящего route и нет suggestions.
Последствия¶
| Область | Действие |
|---|---|
SkiaStatusChip |
GlyphFor(Incomplete) → P; опционально GlyphFor(SlashCommandPreviewGlyph) |
SlashCommandPreviewRuleHelpers |
Возвращать ArgsRemaining для parametric / catalog |
ChatSlashCommandCatalog |
Метаданные min args (постепенно) |
| Тесты | SlashCommandPreviewGlyphResolverTests, snapshot glyph strings |
| Доки | playbook-tci-v1.md § Preview severity |
Не делаем¶
- Блокировка Enter при ✕ или P(n).
- Дублирование статуса в EICAS /
EicasAlertsBar. - Отдельная строка под полем (pill-only, playbook-tci-v1).
Состояние имплементации¶
| Элемент | Статус |
|---|---|
Pill + ✓/✕/⚠/ℹ по SlashCommandPreviewKind |
Implemented |
Clip union + icon right default + tci_validation_icon |
Implemented (2026-05-23) |
Глиф P вместо ⚠ для Incomplete |
Proposed |
| Счётчик P(n) + prefix→Incomplete | Proposed |
| Метаданные args в каталоге | Proposed |
Критерии приёмки (фаза B)¶
/intercom message selectбез хвоста → pill P(1) (или P), янтарь, tooltip с пояснением.- Полный валидный хвост → ✓.
/nope→ ✕./intercom mesпри открытом autocomplete по ступеням → P, не ✕.- CCL и composer: глиф виден слева в pill при горизонтальном scroll.
История¶
| Дата | Изменение |
|---|---|
| 2026-05-23 | Accepted: контракт глифов; clip fix; P(n) — Proposed |