116 lines
23 KiB
Markdown
116 lines
23 KiB
Markdown
# KT AI — Definition of Done (единый гейт качества)
|
||
|
||
**Это — единственный чек-лист системы.** Прогоняй его при ЛЮБОМ изменении UI, а не только при новом прототипе.
|
||
Раньше чек-листы жили в трёх местах (`docs/PRINCIPLES.md`, `docs/DESIGN.md`, `docs/ELEVENLABS_DESIGN.md`) и расходились — теперь
|
||
канон тут, остальные доки ссылаются сюда. «Почему так» — `docs/PRINCIPLES.md` + `docs/ELEVENLABS_DESIGN.md`; «чем строить» — `docs/DESIGN.md` + `COMPONENTS.md`.
|
||
|
||
`[auto]` = проверяет `scripts/validate_product.py` или сборка (машина не забывает — это и есть «соблюдается каждый раз»).
|
||
`[review]` = глазами/в showcase (машина пока не ловит; см. «Что нельзя автоматизировать» внизу).
|
||
|
||
## Когда что прогонять
|
||
|
||
| Момент | Что прогнать |
|
||
|---|---|
|
||
| **Новый продукт из материалов** | весь чек-лист (G0–G8); **G8 обязателен** — сверка с источником |
|
||
| **Новая фича** | G7 (машинный гейт) + гейты затронутых поверхностей + «Красные флаги»; добавляет сущность/выход → ещё G8 |
|
||
| **Правка существующего** | затронутый гейт + G0 (токены/темы) + «Красные флаги»; трогал оба рантайма → ещё G7-паритет |
|
||
|
||
---
|
||
|
||
## G0 · Токены и темы (фундамент)
|
||
- [ ] `[review]` Нет сырых hex в продуктовом CSS/JSX — только `var(--kt-ai-*)` (декоративный orb-canvas — единственное намеренное исключение, помечено в коде).
|
||
- [ ] `[review]` Геометрия не зависит от темы: темы меняют ТОЛЬКО цвет, не радиусы/отступы/размеры.
|
||
- [ ] `[auto]` Контраст — `python3 scripts/build_tokens.py` (гейт падает и называет пары). Пороги: текст ≥7:1, приглушённый ≥4.5:1, фокус и заливка состояния ≥3:1. Раньше пункт стоял с меткой `[review]`, и три нарушения прожили несколько мажорных версий: 2,8:1 на кегле 11px глаз читает не как «нечитаемо», а как «тихо».
|
||
- [ ] `[review]` Обе темы проверены переключателем в `showcase.html` — глазами проверяется соразмерность и иерархия, а не контраст.
|
||
- [ ] `[auto]` Менял `tokens.json`/`kt-ai-components.css` → прогнал `python3 scripts/build_tokens.py` (+ `scripts/visual_check.mjs` при наличии chromium).
|
||
- [ ] `[auto]` Статика адресуется `ktAsset()` (в HTML-рантайме — `ktAiAsset()`), а не путём от корня сайта. Под префиксом развёртывания (`/cons`) путь `/kt-ai-orb.js` уходит мимо приложения; ломается только на развёртывании, в корне домена всё работает. Гейт 18 в `doctor.py`.
|
||
|
||
## G1 · Высота и иерархия
|
||
- [ ] `[auto]` Один primary на зону (`scenario.control`); `[review]` кнопки названы глаголами действия, не «Да/ОК».
|
||
- [ ] `[review]` Page-title 24–26px semibold БЕЗ лого + muted-подпись; лого живёт в сайдбаре.
|
||
- [ ] `[auto]` KPI отвечают на вопрос пользователя на экране; на `view: operational` — без ROI/FTE/экономии (это management-view).
|
||
- [ ] `[auto]` Лейблы коротко: filter ≤2 слов, status ≤4, header колонки ≤2–3; `[review]` детали — в drawer/help, не в лейбле.
|
||
- [ ] `[review]` Размер/вес/цвет ведут глаз: title → секции → body → meta; один акцент на зону.
|
||
- [ ] `[review]` KPI-плашка читается четырьмя уровнями сверху вниз: подпись → значение → `.hint` (знаменатель, доля, период) → `.note` (оговорка: чем число НЕ является). Значение идёт сразу под подписью и НЕ прижимается к низу; полоса выравнивает карточки по верху — иначе в соседних карточках с уточнением и без числа встают на разной высоте.
|
||
- [ ] `[auto]` Три места для трёх разных текстов, и они не путаются: `banner` — из-за чего число соврёт (до чисел), `kpis[].note` — что число значит (у самого числа), `conclusion` — что из чисел следует (после таблицы). Валидатор предупреждает, когда баннер длиннее 200 знаков: это абзац до первого числа, и почти всегда там лежит чужой текст.
|
||
- [ ] `[review]` Текста на экране столько, сколько нужно для решения. Поясняющая строка, оговорка и подзаголовок сперва пробуются как свойство самого элемента (подпись пилюли, подсказка у метки, название колонки) и живут рядом с ним, а не отдельной строкой над списком. **Строка, которая не меняется от данных, — кандидат на удаление**; если она нужна для честности (непроверенное правило, тестовые данные, пробел в данных), она остаётся, но переезжает к элементу.
|
||
- [ ] `[review]` Ориентация: экран отвечает где я / куда пойти / что здесь / как выйти (крошка, активный nav, заголовок, Esc). Лейблы конкретны (nav по содержимому, не «зонтик»); контролу не нужен поясняющий лейбл.
|
||
- [ ] `[auto]` Подпись сочетания стоит там, где сочетание работает, и называет клавишу этой машины (⌘K / Ctrl K). Подпись без обработчика — обещание, обработчик без подписи — незаявленная горячая клавиша; включаются одним полем. Гейт 19.
|
||
- [ ] `[auto]` У подписи поля есть `for=` или обёртка `<label class="kt-ai-field">`. Подпись рядом с контролом выглядит подписью, но без связи диктор объявляет поле безымянным, а щелчок по подписи не ставит фокус. Гейт 22.
|
||
- [ ] `[auto]` Кит показывает контракт целиком: `npm run kit:render` (гейт 23). Типы и гейты читают код и не ловят главное — когда рантайм молча не читает блок контракта. Проверка рендерит кит в строку и сверяет содержимое с контрактом.
|
||
- [ ] `[auto]` Архетип реализован в том рантайме, где вы строите: `runtimes` в `archetypes/registry.json`. `status: stable` про рантайм не говорит. Гейт 21 + заметка валидатора.
|
||
- [ ] `[auto]` id разметки не совпадают с id символов вшитого спрайта: спрайт стоит выше, и `getElementById` вернёт `<symbol>` — элемент останется мёртвым молча, без единой ошибки. Гейт 20.
|
||
- [ ] `[review]` Кнопки create/«Новый X» начинаются с ведущего «+». Один фильтрующий поиск на экран (глобальная ⌘K-палитра и табличный фильтр — разные роли, но два одинаково фильтрующих поля — нет). AI-кнопка Төре — в топбаре рядом с поиском. Не добавляй input/селект, если прямой кнопки достаточно.
|
||
|
||
## G2 · Язык ElevenLabs (эстетика и плотность)
|
||
- [ ] `[review]` Структуру задают hairline-границы 1px, а не тени; тени — шёпот (карточки приподняты, не парят).
|
||
- [ ] `[review]` Поверхности нейтральные (white/near-white/near-black); цвет — только статус/ошибка/акцент, не украшение.
|
||
- [ ] `[review]` Статус = пилюля со скруглением `radius-tag` (5px) и тоном; число/текст остаются нейтральными (не цвет текста).
|
||
- [ ] `[review]` Радиусы 8–12px для карточек/кнопок/инпутов; полный радиус — только pill/toggle/chip.
|
||
- [ ] `[review]` Контент важнее хрома: сайдбар/топбар тонкие и тихие, рабочая область доминирует.
|
||
- [ ] `[auto]` Ширина колонок — по содержимому (`colw`/`ktColWidth`), не «на глаз»; короткие колонки не растянуты, длинные не зажаты.
|
||
- [ ] `[review]` Нет карточки-в-карточке (две рамки спорят за группировку).
|
||
- [ ] `[review]` **Ритм блоков — из шкалы, и он группирует**: регионы экрана (шапка / баннер / содержимое) — `stack-group` (24); панель управления ближе к тому, чем управляет — `stack-block` (16); внутри группы (фильтры ↔ вкладки, карточка ↔ карточка) — `stack-tight` (12); интерьер карточки — `pad-card` (20); поля области и отрыв от топбара — `stack-region` (32). Выражается `kt-ai-v[data-gap]`; собственный `app-stack-*` в продукте — сигнал, что группировку обошли.
|
||
- [ ] `[review]` **Проверка ритма**: пройди по вертикали и назови каждый зазор. Все числа разные (три и больше на отношение «блок ↔ блок») — фейл, читается как небрежность. **Все числа одинаковые — фейл ровно такой же**: экран плоский, группы не читаются. Чисел должно быть столько, сколько уровней вложенности.
|
||
|
||
## G3 · Состояния и обратная связь
|
||
- [ ] `[review]` Каждое действие даёт отклик ≤100мс (toast / смена статуса / состояние кнопки); лоадер на всём, что дольше 300мс — skeleton, не спиннер.
|
||
- [ ] `[review]` Нарисованы empty / loading / error; пустота — осознанный empty-state («что здесь будет»), не голая белизна.
|
||
- [ ] `[review]` Лестница состояний контрола: default → hover → active/selected → focus-visible → disabled; у инпута — focus + error.
|
||
- [ ] `[review]` Микроинтеракция подтверждает результат (copy → чип «скопировано», не только hover).
|
||
- [ ] `[review]` Движение: отклик на pointer-down (не на отпускании); появление от `scale(.95)`, не из ниоткуда; переходы прерываемы/обратимы; overlay растёт из триггера и уходит тем же путём; анимируются только `transform`/`opacity`. Подробно — `docs/DESIGN.md §Движение`.
|
||
|
||
## G4 · Честность данных и копирайт
|
||
- [ ] `[review]` Только подтверждённые материалами факты; цифр «с потолка» нет; ПДн маскированы (`ИИН •••4821`, без реальных ФИО).
|
||
- [ ] `[auto]` Нет debug-языка генерации в UI (`fallback`, `модель вернула`, `JSON`, `prompt`, `shell`, `не проходит дизайн-систему`).
|
||
- [ ] `[review]` Поля поиска пусты по умолчанию — не префилл произвольными примерами.
|
||
- [ ] `[auto]` Статусы строк — только из объявленных в `statuses`; `scenario`/`drawer`/`chart` ссылаются на существующие ключи.
|
||
- [ ] `[review]` AI-контент атрибутирован («Сгенерировано ИИ» / орб) там, где это генерация.
|
||
- [ ] `[auto]` Без дисклеймеров и нравоучений в UI («это прототип», «данные иллюстративны», «AI не действует сам», «решение подтверждает человек») — решение показывают контролы, а не объяснения. `[review]` Лейблы-секции — нейтральные существительные, не лозунги капсом («Решение», не «РЕШЕНИЕ — ЗА ВАМИ»). Продукт-специфичный текст живёт в контракте (`scenario.aiSummary`), а НЕ зашит в shell.
|
||
|
||
## G5 · Законы взаимодействия
|
||
- [ ] `[review]` Выход из любого состояния: Esc / назад / закрытие работают; деструктив — глаголом + подтверждением, необратимое — вводом имени объекта.
|
||
- [ ] `[auto]` Первичные фильтры ≤4 + «Все», только workflow-status (не confidence/risk-type/системы); `[review]` остальное — прогрессивным раскрытием.
|
||
- [ ] `[review]` Прогрессивное раскрытие: детали в drawer/modal, редкие действия — в hover/popover/kebab, не вшиты в UI навсегда.
|
||
- [ ] `[review]` Shell неприкосновенен: sidebar, topbar, theme-toggle, AI-кнопка Төре — системный контракт, не творческая зона.
|
||
|
||
## G6 · Адаптивность и локализация
|
||
- [ ] `[review]` <lg → icon-rail, <md → sidebar-drawer; на 360/390/393px нет горизонтального скролла (`documentElement.scrollWidth ≤ clientWidth`) и топбар влезает.
|
||
- [ ] `[review]` **Сенсорная цель ≥44px на ≤768px.** Порог задаёт ДС: токен `--kt-ai-control-h-touch` и правило-порог в `kt-ai-components.css` (условие `(pointer: coarse), (max-width: 767.98px)`). Своими руками высоты не поднимай — проверь, что элемент попадает под правило: компоненты через классы `.kt-ai-*`, разметка кита — через `[data-kt-ai-kit]`. Осознанно меньший контрол помечается `data-kt-touch="off"`; молча — нельзя.
|
||
- [ ] `[review]` Колонка не шире отведённого: у прямых детей сеток (`.kt-ai-cols` это делает сам) `min-width: 0`. Без него `1fr` = `minmax(auto,1fr)` и одна длинная строка распирает страницу — сворот в одну колонку это НЕ лечит.
|
||
- [ ] `[review]` Длинные казахские строки (≈+20%) — truncate + tooltip; фикс-ширины под текст кнопок/чипов/пунктов запрещены.
|
||
- [ ] `[auto]` Icon-only кнопка — с tooltip и aria-label (гейт 16 в `doctor.py`; `title` за имя не считается — диктор его не обязан читать). У кнопки-переключателя подпись зависит от состояния: «Свернуть меню» в свёрнутом виде — ложь.
|
||
- [ ] `[review]` Кнопка, за которой слой, сообщает состояние: `aria-expanded`, `aria-haspopup`, `aria-controls`. Фокус виден с клавиатуры на всём пути.
|
||
- [ ] `[review]` Модальный слой закрывается по Esc — через общий хук кита `useKTEscape`, а не своей копией слушателя: копий было две, и они успели разойтись (`window` против `document`), а два слоя Esc не имели вовсе.
|
||
- [ ] `[review]` Учтены `prefers-reduced-motion` (обнуление длительностей), `prefers-contrast: more` (толще фокус/границы) и `prefers-reduced-transparency` (blur снят, фон плотный).
|
||
|
||
## G7 · Контракт и паритет (машинный гейт)
|
||
- [ ] `[auto]` `python3 scripts/validate_product.py "<config>.json" --strict` → `0 ошибок, 0 предупреждений`.
|
||
- [ ] `[review]` HTML ↔ React выглядят и ведут себя идентично (если трогал оба рантайма) — один контракт, одно поведение.
|
||
- [ ] `[auto]` Прототип собран `python3 scripts/build_prototype.py` — НЕ инлайнен руками.
|
||
- [ ] `[auto]` Менял `DS/` → синхронизировал Töре + `integrity.test` без падений (0 failed; число тестов не фиксируем — оно растёт).
|
||
- [ ] `[review]` Правил гейт в `doctor.py` → **сломай его намеренно снова** и убедись, что он падает. Одной проверки при написании мало: рефакторинг 5.9.1 молча вырезал тело гейта 16, и `doctor.py` остался зелёным.
|
||
- [ ] `[auto]` Добавил компоненту рантайм-ресурс (`<script src="/…">`, спрайт, шрифт) → он лежит в бандле как `public/…`. Проверяет гейт 15 в `doctor.py`: компонент без своего файла собирается и типизируется чисто, а у потребителя даёт 404 и пустое место.
|
||
|
||
## G8 · Соответствие источнику (сборка из материалов / Төре-интервью)
|
||
Закрывает разрыв «UI ≠ то, что обещали материалы». Не про пиксели — про содержание. Обязателен, когда продукт собран из PRD/ТЗ или из интервью Төре.
|
||
- [ ] `[review]` Есть **карта источника** (`source-map`): выписаны ВСЕ сущности, **выходные артефакты** (документы, которые продукт производит: ТС, отчёт, СЗ…), роли, сценарии (S-xx) и критерии приёмки (A-xx) из материалов.
|
||
- [ ] `[review]` **Трассировка:** каждый пункт карты → UI-дом (nav-секция / поле или артефакт в drawer / явный «вне v1»). Правило: **представлен или осознанно отложен — никогда молча не выброшен.**
|
||
- [ ] `[review]` Каждый **named output** из PRD (раздел «первая версия» / «данные» / «сценарии») имеет видимое место в UI — не зарыт в `_flags`.
|
||
- [ ] `[review]` Роли из материалов отражены (кто решает, кто согласует, кто получает) — экран собран под пользователя, принимающего решение.
|
||
- [ ] `[review]` Доменные термины (ТС, ОБ/БКВ, СЗ, ЕНС ТРУ…) — как первоклассные сущности/артефакты, а не обезличенный текст.
|
||
|
||
---
|
||
|
||
## Красные флаги (мгновенный фейл ревью)
|
||
Лого в page-header · заголовок 30–32px bold (надо 24–26 semibold) · два тоггла сворачивания · гигантская пустота над/под контентом ·
|
||
вертикальные сепараторы в таблице · статус сырым текстом/цветом вместо пилюли · сырой hex вместо `var(--kt-ai-*)` · карточка-в-карточке ·
|
||
спиннер вместо skeleton · >1 primary в зоне · разнобой отбивок между блоками (три и больше значений на одно отношение) · один зазор на всё — плоский экран без групп · плотный экран, растянутый во всю ширину монитора (нет `content-table`-клампа) · цвет ради украшения · синий как заливка primary-кнопки · ROI/FTE на рабочем экране ·
|
||
debug-язык генерации в UI · самодельные глифы вместо иконок спрайта · разная геометрия в темах ·
|
||
дисклеймер/мета-копирайт («это прототип», «данные иллюстративны») · нравоучение про human-in-the-loop («AI не действует сам», «решение подтверждает человек») ·
|
||
лозунг-лейбл капсом («РЕШЕНИЕ — ЗА ВАМИ») · продукт-специфичный текст зашит в shell вместо контракта · два одинаково фильтрующих поиска · кнопка create без ведущего «+».
|
||
|
||
## Что нельзя автоматизировать (всегда `[review]`)
|
||
Валидатор ловит структуру и честность контракта (статусы, один primary, ROI на operational, debug-язык, длину лейблов, иконки, chart, паритет схемы).
|
||
Он НЕ видит пиксели: иерархию, ритм отступов, тени-vs-hairline, состояния hover/empty/error, паритет тем, адаптив. Это — обязательный глазами-проход в `showcase.html`/preview. «Зелёный валидатор» ≠ «прошло DoD».
|