diff --git a/docs/QA-versioning-and-ai.md b/docs/QA-versioning-and-ai.md index a504b15..8bce2c5 100644 --- a/docs/QA-versioning-and-ai.md +++ b/docs/QA-versioning-and-ai.md @@ -1,301 +1,412 @@ -# Инструкция для тестировщика: версионирование тестов и AI-функции +# Инструкция для тестировщика: версионирование тестов и AI -> Контур: новый Flask на `:3108` (после E1.0–E1.3, E1.8). Старый Node — на `:3107`, -> для проверки этих задач **используйте только `:3108`**. +Сайт: **[https://edullm.pirogov.ai/](https://edullm.pirogov.ai/)** -Перед началом: +Учётка: войдите под автором (роль «менеджер» или «администратор»). Если +учётки нет — попросите её у разработчика, без неё тестировать нельзя. -1. Откройте `http://:3108/login` под учёткой автора (роль `manager` или - `admin`). Если сидов нет — заведите пользователя в `clinic_tests.users` - обычным способом. -2. Для AI-задач: откройте `http://:3108/settings` и убедитесь, что - статус ключа = «Задан» и кнопка **«Проверить подключение»** возвращает - зелёный **OK · provider/model · NN мс**. Если ключ не задан — AI-задачи - нужно прогнать в негативном сценарии (см. блок A.0). -3. Откройте `http://:3108/tests` — это каталог. +> Всё, что описано ниже, проверяется **только через сайт**. Если в каком-то +> сценарии написано «недоступно сейчас» — это **не баг**, это значит, что +> функция UI ещё не сделана и появится позже. Просто пропускайте. --- -## Часть 1. Версионирование при правке после попыток - -### Что должно работать - -| Правило | Поведение | -|---|---| -| Нет попыток | Автор правит тест **на месте**, номер версии не меняется. | -| Есть ≥ 1 попытка | Любое сохранение изменений **создаёт новую версию** (`version + 1`), старая становится неактивной, но **сохраняется в БД** и связана через `parent_id`. | -| Цепочка | Все версии связаны (parent → child), на странице «Версии» видны все. | -| Каталог | В списке видна **только активная** версия цепочки. | -| Переключение активной версии | Автор может вручную сделать активной любую версию — остальные автоматически становятся неактивными. | -| Деактивация цепочки | Тест можно скрыть целиком; данные не удаляются. | -| Корректность истории | Каждая попытка привязана к **той версии**, по которой её проходили — разбор ошибок остаётся корректным после правок. | - -### Сценарий 1.1. Правка теста до попыток (версия не растёт) - -1. В каталоге → **«Создать тест»**, заполните название и описание → создать. -2. В редакторе добавьте 2–3 вопроса по 3–4 варианта, сохраните. -3. Откройте этот же тест в редакторе ещё раз, измените: - - название; - - описание; - - текст одного вопроса; - - пометьте один вариант как правильный иначе; - - удалите/добавьте вариант. -4. **«Сохранить»**. - -**Ожидается:** -- Сообщение «Сохранено.» (без слов «создана новая версия»). -- В БД: `SELECT version FROM test_versions WHERE test_id = ''` → **одна** строка с `version = 1, is_active = true`. -- Эндпоинт `GET /api/tests//versions` → массив из 1 элемента, `hasAttempts: false`. - -### Сценарий 1.2. Появление первой попытки → форк новой версии - -> Прохождение теста (UI) пока не реализовано в Flask-контуре (запланировано -> в **E1.4**). Поэтому факт попытки имитируется напрямую в БД — это норма -> для текущего этапа. - -1. Возьмите `id` теста и `id` активной версии: - ```sql - SELECT t.id AS test_id, tv.id AS version_id - FROM tests t JOIN test_versions tv ON tv.test_id = t.id AND tv.is_active - WHERE t.title = 'Ваш тест'; - ``` -2. Создайте «попытку» (минимальный INSERT, любой пользователь, любое - состояние; нам нужен только сам факт записи в `test_attempts`): - ```sql - INSERT INTO test_attempts (id, test_version_id, user_id, status, created_at) - VALUES (gen_random_uuid(), '', '', 'completed', now()); - ``` -3. В UI откройте редактор того же теста, **измените хотя бы один вопрос** - (текст / правильность варианта / число вариантов) и **«Сохранить»**. - -**Ожидается:** -- Сообщение «Сохранено (создана новая версия — есть попытки прохождения).» -- В БД: `SELECT version, is_active, parent_id FROM test_versions WHERE test_id=...` - → **две** строки: - - `version = 1, is_active = false, parent_id = NULL` (старая, не удалена); - - `version = 2, is_active = true, parent_id = ` (новая). -- Старая попытка по-прежнему ссылается на `version_id` из v1, и её ответы/вопросы остаются те же — разбор ошибок не «съехал». - -### Сценарий 1.3. Правка только метаданных после попыток (без форка) - -После сценария 1.2: - -1. В редакторе **не трогайте** вопросы и варианты. Поменяйте только название - или описание или проходной балл. Сохраните. - -**Ожидается:** -- Сообщение «Сохранено.» (без форка). -- `version` не вырос; метаданные обновились на активной версии. - -> Логика: форк делается только если после попыток меняется **содержание** -> (вопросы/варианты). Чисто косметические правки шапки версию не плодят. - -### Сценарий 1.4. Каталог показывает только активную версию - -1. После 1.2 откройте `/tests` под автором и под не-автором (если есть назначения). - -**Ожидается:** -- В каталоге — одна карточка теста с пометкой `v.2` (активная). Версия 1 в каталог не попадает, но видна автору на странице «Версии» теста. - -### Сценарий 1.5. Ручное переключение активной версии - -1. Получите id v1 и v2: `SELECT id, version, is_active FROM test_versions WHERE test_id=...` -2. Сделайте активной v1: - ```bash - curl -X POST -b cookies.txt \ - http://:3108/api/tests//versions//activate - ``` - (cookie сессии берёте из браузера или логином через `/api/auth/login`). - -**Ожидается:** -- Ответ `{ ok: true, activeVersionId: "" }`. -- В БД: `is_active = true` только у v1, у v2 — `false`. -- В каталоге карточка теста снова показывает `v.1`. - -### Сценарий 1.6. Деактивация цепочки целиком - -1. В редакторе снимите чекбокс **«Цепочка активна»** и сохраните. - -**Ожидается:** -- В каталоге `/tests` теста больше не видно (ни в visible, ни у не-авторов). -- У автора он появляется в блоке **«Скрытые вами»** (внизу каталога). -- В БД: `tests.is_active = false`, версии и попытки нетронуты. -- Включение чекбокса обратно возвращает тест в каталог. - -### Сценарий 1.7. Корректность истории по старым попыткам - -> Полноценный разбор пользовательских ответов появится в **E1.4** вместе -> с UI прохождения. Сейчас минимально проверяем, что данные старой версии -> не повреждены. - -1. После 1.2 в БД: - ```sql - SELECT q.text - FROM questions q - JOIN test_versions tv ON tv.id = q.test_version_id - WHERE tv.test_id = '' AND tv.version = 1; - ``` -2. **Ожидается:** видны вопросы **в том виде, в каком они были до правки** - (а не текущая версия v2). Эта же выборка должна совпадать с - `q.test_version_id` любой попытки, которую вы создали в 1.2. - -### Что фиксировать как баг - -- После правки **с попытками** в БД остался один `test_versions`-ряд (нет форка). -- После правки **без попыток** появилась `version = 2` (лишний форк). -- При активации одной версии другие не сбросились в `is_active = false`. -- Каталог показывает неактивную версию или скрытый тест. -- Сообщение в UI после сохранения не совпадает с реальным поведением (форк есть, текст «Сохранено.» без уточнения, или наоборот). +## Часть 1. Версии теста — что меняется при правках + +### О чём вообще задача + +Когда автор правит тест, в системе важно не сломать историю прохождений +сотрудников. Поэтому правила такие: + +- Пока **никто не прошёл** тест — автор правит на месте, версия одна. +- Как только **хотя бы один сотрудник прошёл** тест — следующее сохранение + изменений создаёт **новую версию** (v2, v3, …), старая сохраняется. +- В каталоге всегда видна **только одна** активная версия. +- Автор может **скрыть** тест целиком (чекбокс «Цепочка активна»). +- Автор может **переключить** активную версию на другую из истории. + +> Сейчас на сайте нельзя пройти тест сотруднику и нельзя из UI открыть +> историю версий — это будет в следующих спринтах. Поэтому из шести +> правил тестировщик пока проверяет четыре, остальные помечены ниже. + +--- + +### 1.1. Создание нового теста + +**Что проверяем:** автор может создать тест с нуля. + +**Как проверять:** +1. Откройте [https://edullm.pirogov.ai/](https://edullm.pirogov.ai/) и войдите. +2. Нажмите в шапке иконку **«Тесты»** (список) → попадаете в каталог. +3. Нажмите кнопку **«Создать тест»**. +4. В появившемся окне заполните **Название** (например, «Тест A»), + при желании — Описание. +5. Нажмите **«Создать»**. + +**Что должно произойти:** +- Открывается экран редактора нового теста. +- В поле «Название» — то, что вы ввели. +- Список вопросов пуст, счётчик «Вопросы (0)». +- Внизу — кнопка **«Сохранить»** и чекбокс **«Цепочка активна»** (по + умолчанию включён). + +**Если что-то не так — баг:** +- Окно «Создать тест» не открывается. +- После «Создать» никуда не перенаправило. +- В поле «Название» в редакторе пусто, хотя ввели текст. +- Список тестов в каталоге не обновился (не появилась новая карточка). --- -## Часть 2. AI-функции (E1.2 + E1.8) +### 1.2. Правка теста до прохождений (версия не растёт) + +**Что проверяем:** пока никто не проходил тест, автор может править его +сколько угодно — это всё одна и та же версия. -### Заметка о ключе +**Как проверять:** +1. Откройте только что созданный «Тест A» (если уже не открыт): шапка → **«Тесты»** → нажмите на карточку теста. +2. Нажмите **«Добавить вопрос»** — появится карточка вопроса. +3. Введите текст вопроса. +4. Заполните 3–4 варианта ответа в поле «Вариант ответа», у одного из них поставьте чекбокс «Правильный» (квадратик слева от текста). +5. Добавьте ещё один-два вопроса тем же способом. +6. Нажмите **«Сохранить»** в нижней панели. -Изначально в ТЗ предполагалось хранить ключ в БД и вводить на `/settings`. -По согласованию ключ **общий** и хранится в `ENV` контейнера -(`DEEPSEEK_API_KEY` / `OPENAI_API_KEY`). Страница `/settings` остаётся, -но в ней — только статус и кнопка проверки подключения. Поле ввода ключа в UI **не нужно** (это не баг). +**Что должно произойти:** +- Под шапкой появляется надпись **«Сохранено.»** (без слов про новую версию). +- Если перезагрузить страницу — все вопросы и варианты на месте. -### A.0. Негативный кейс — ключ не задан +**Повторите правку:** +1. На том же экране **измените** текст одного вопроса, **добавьте** ещё один вариант к другому, **удалите** третий вопрос (кнопка «корзина» справа в карточке вопроса). +2. Нажмите **«Сохранить»**. -1. На сервере уберите `DEEPSEEK_API_KEY` из окружения и перезапустите контейнер. -2. Откройте `/settings`. +**Что должно произойти:** +- Снова надпись **«Сохранено.»**. +- Никаких слов «создана новая версия». +- Перезагрузка страницы — изменения сохранились. -**Ожидается:** -- Бейдж «Не задан» (красный). -- Блок «Как задать ключ» с примером `.env`. -- Кнопка **«Проверить подключение»** возвращает красный блок с текстом про незаданный ключ. -- В редакторе при нажатии **«Сгенерировать по сетке» / «по названию» / «Проверить тест» / «Улучшить тест» / «AI: вопрос»** появляется confirm: - «… Открыть Настройки?» → согласие открывает `/settings`. +**Если что-то не так — баг:** +- Появляется сообщение про «новую версию» (его быть не должно — попыток ещё нет). +- Изменения не сохранились после перезагрузки страницы. +- Сообщение «Сохранено.» не появилось вовсе. -После проверки верните ключ и `docker compose ... up -d` — переходим к позитивным сценариям. +--- + +### 1.3. Правка после прохождений (создаётся v2) -### A.1. `/settings` → «Проверить подключение» +> ⏳ **Сейчас недоступно для проверки.** +> +> На сайте пока нет страницы для прохождения теста сотрудником, поэтому +> тестировщик не может «накопить» попытки и проверить эту логику через UI. +> Сценарий вернётся в инструкцию вместе со следующим спринтом, когда +> появится страница прохождения. + +--- + +### 1.4. Каталог показывает только активные тесты + +**Что проверяем:** в каталоге нет неактивных/скрытых тестов. + +**Как проверять:** +1. На экране редактора любого теста снимите внизу чекбокс + **«Цепочка активна»** и нажмите **«Сохранить»**. +2. Перейдите в шапке на **«Тесты»** (каталог). + +**Что должно произойти:** +- Карточки этого теста в основном списке нет. +- Внизу страницы каталога есть раскрывающийся блок **«Скрытые вами цепочки (N)»**. Раскройте его — там видно ваш тест. +- Нажмите **«Открыть»** рядом с тестом — снова попадаете в редактор. +- Поставьте обратно галку **«Цепочка активна»** → **«Сохранить»**. +- Снова перейдите в **«Тесты»** — тест опять в основном списке каталога. + +**Если что-то не так — баг:** +- После снятия галки тест остаётся в обычном каталоге. +- Тест полностью пропал и его не видно нигде, даже в «Скрытых». +- После возврата галки тест не вернулся в основной каталог. + +--- + +### 1.5. Ручное переключение активной версии + +> ⏳ **Сейчас недоступно для проверки.** +> +> Страница с историей версий теста (где можно нажать «сделать активной») +> ещё не сделана. Появится в следующем спринте. + +--- + +### 1.6. История прохождений после правок + +> ⏳ **Сейчас недоступно для проверки** — см. 1.3 и 1.5. + +--- -1. На `/settings` нажмите **«Проверить подключение»**. +## Часть 2. AI-функции в редакторе теста -**Ожидается:** -- В течение нескольких секунд — зелёный блок: `OK · / · мс` и сэмпл ответа. -- Provider/Model совпадают с ENV (`deepseek` + `deepseek-chat` по умолчанию). +### Как проверять, что AI вообще работает -### A.2. «Сгенерировать тест по названию» (E1.8) +**Что проверяем:** ключ к AI задан и сервис отвечает. -1. Создайте новый пустой тест (никаких вопросов). -2. В редакторе нажмите **«Сгенерировать по названию»**. -3. На запрос «Сколько вопросов?» введите, например, `8`; «Сколько вариантов?» — `4`. -4. Дождитесь готовности → confirm «Применить как черновик?». +**Как проверять:** +1. В шапке нажмите иконку **«Настройки»** (шестерёнка). +2. Посмотрите блок «Подключение к LLM»: + - **Статус ключа** — должно быть зелёное **«Задан»**. + - **Провайдер** и **Модель** — заполнены. +3. Нажмите кнопку **«Проверить подключение»**. -**Ожидается:** -- Кнопка **активна только** когда поле «Название» заполнено. Если очистить название — нажатие даёт алерт «Сначала заполните название теста.» и фокус возвращается в название. -- Появляется ровно ~8 вопросов по ~4 варианта (модель может слегка отклониться по инструкции, это допустимо). +**Что должно произойти:** +- В течение 1–10 секунд под кнопкой появляется **зелёный** блок + с текстом вида **«OK · deepseek / deepseek-chat · 1234 мс»**. + +**Если что-то не так:** +- Если статус **«Не задан»** (красный) — сообщите разработчику, не задан ключ. Тестировать AI-функции в этом режиме не нужно, кроме одного сценария ниже (2.7). +- Если кнопка отдала **красный** блок «Ошибка» при заданном ключе — это баг, прикладывайте текст ошибки к тикету. + +--- + +### 2.1. Сгенерировать тест по названию + +**Простыми словами:** автор пишет только тему, AI сам придумывает вопросы. + +**Как проверять:** +1. **«Тесты»** → **«Создать тест»** → название, например, **«Гигиена рук»**, описание можно оставить пустым → **«Создать»**. +2. В редакторе нажмите кнопку **«По названию»** (фиолетовая, в блоке «AI-помощник» → «Создать вопросы»). +3. На вопрос «Сколько вопросов сгенерировать?» введите, например, `8` → **OK**. +4. На вопрос «Сколько вариантов в каждом вопросе?» введите, например, `4` → **OK**. +5. Подождите 5–20 секунд. +6. Появится подтверждение «Готово: «…», вопросов — N. Применить как черновик? Текущие вопросы будут заменены». Нажмите **OK**. + +**Что должно произойти:** +- В списке появилось примерно 8 вопросов на тему гигиены рук, в каждом примерно 4 варианта ответа на русском языке. +- В каждом вопросе хотя бы один вариант помечен как «Правильный» (галка слева от текста варианта). +- Внизу можно нажать **«Сохранить»** — тест сохраняется. + +**Дополнительно (что блокировка названия работает):** +1. Создайте ещё один тест, в редакторе **очистите поле «Название»**. +2. Нажмите **«По названию»**. +3. Должен появиться алерт **«Сначала заполните название теста.»**, курсор перейдёт в поле «Название». Никакой генерации не происходит. + +**Если что-то не так — баг:** +- Кнопка **«По названию»** работает при пустом названии (без алерта). +- Сгенерированные вопросы — не на русском или не по теме названия. +- В вопросе нет ни одного правильного варианта. +- Подтверждение «Применить?» не появилось — вопросы заменились молча. +- Отказ в подтверждении (Cancel) всё равно заменил вопросы. + +--- + +### 2.2. Сгенерировать тест по сетке + +**Простыми словами:** автор сам задаёт «скелет» — сколько вопросов и +сколько вариантов; AI заполняет вопросы по этому скелету. + +**Как проверять:** +1. Создайте новый тест с названием **«Тест по сетке»**. +2. Нажмите **«Добавить вопрос»** пять раз — получится 5 пустых карточек. +3. В **третьей и пятой** карточках поставьте галку **«Несколько правильных ответов»**. +4. В каждом вопросе по умолчанию 0 вариантов — нажмите **«Добавить вариант»** в каждом вопросе по 3 раза, чтобы стало по 3 варианта. +5. Нажмите кнопку **«По текущей сетке»** в блоке «AI-помощник». + +**Что должно произойти:** +- В списке снова 5 вопросов (не больше, не меньше). +- В каждом — по 3 варианта. +- В третьем и пятом вопросах несколько вариантов помечены правильными; + в остальных — ровно один. - Тексты — на русском, по теме названия. -- В каждом вопросе хотя бы один вариант помечен как правильный. -- Отказ в confirm не меняет редактор; согласие — заменяет. -- Сохранение работает, в БД появляется версия с этими вопросами. -### A.3. «Сгенерировать тест по сетке» (E1.2 — было) +**Если что-то не так — баг:** +- Стало другое число вопросов или вариантов (не 5×3). +- В третьем/пятом вопросе только один правильный ответ, а в остальных — несколько. +- Пришла ошибка типа **«AI: ошибка»** без понятного объяснения. -1. Откройте тест, в котором уже руками настроены 5 вопросов, по 3 варианта в каждом, 2 из вопросов помечены как «Несколько правильных». -2. Нажмите **«Сгенерировать по сетке»**. +--- + +### 2.3. Проверить тест + +**Простыми словами:** AI читает весь тест и пишет, что в нём не так. + +**Как проверять:** +1. Откройте любой тест с 3+ вопросами (например, «Гигиена рук» из 2.1). +2. Желательно специально испортить пару вопросов: переписать + формулировку расплывчато («что-то про что-то»), сделать варианты + ответа очень похожими друг на друга или явно дурацкими. +3. Нажмите **«Сохранить»**. +4. Нажмите кнопку **«Проверить»** в блоке «AI-помощник» → «Улучшить существующее». + +**Что должно произойти:** +- Открывается окно «Проверка теста». +- Сверху — цветная плашка с одним из вердиктов: **«Годен»** (зелёный), + **«Есть замечания»** (жёлтый) или **«Серьёзные проблемы»** (красный) + + одно-два предложения резюме. +- Ниже — список разделов: «Чёткость формулировок», «Качество дистракторов», + «Охват темы», «Сбалансированность сложности». Под каждым — конкретные + пункты, что улучшить. +- Закрытие крестиком сверху или кнопкой «Закрыть» внизу — работает. +- В тесте при этом **ничего не меняется**, AI только советует. + +**Если что-то не так — баг:** +- Окно пустое или текст не на русском. +- Все вопросы AI признал хорошими, хотя вы их специально испортили. +- После закрытия окна в тесте появились/исчезли вопросы. -**Ожидается:** -- Возвращается ровно 5 вопросов. -- В тех же позициях, что у вас стояли «Несколько правильных», — у новых вопросов несколько правильных вариантов. -- Число вариантов в каждом вопросе совпадает. -- При несовпадении сетки эндпоинт вернул бы 502 с кодом `llm_shape` (модель «не попала») — допустимая редкая ошибка, повторите. +--- -### A.4. «Проверить тест» (E1.8) +### 2.4. Улучшить весь тест + +**Простыми словами:** AI предлагает улучшенные формулировки и варианты; +автор отмечает галками, что применить. + +**Как проверять:** +1. Откройте тест из 2.3 (с теми же намеренно слабыми вопросами). +2. Нажмите **«Сохранить»** на всякий случай. +3. Нажмите кнопку **«Улучшить»**. + +**Что должно произойти:** +- Открывается окно «Улучшение теста». +- Сверху подпись «Отметьте вопросы… N из M» (M — всего вопросов, N — где AI предложил изменения). +- Каждый изменённый вопрос — отдельный блок: + - Чекбокс **«Вопрос #N»** (по умолчанию **отмечен**). + - Слева — «Было» (старый текст и варианты, изменённые куски зачёркнуты). + - Справа — «Стало» (новые формулировки, выделены). + - Правильные варианты помечены галочкой **✓**. +- Внизу — две кнопки: **«Отмена»** и **«Применить выбранное»**. + +**Проверьте применение по выбору:** +1. Снимите галки у двух вопросов из списка. +2. Нажмите **«Применить выбранное»**. + +**Что должно произойти:** +- Окно закрывается. +- В редакторе **только** отмеченные вопросы заменены на улучшенные; + два вопроса, у которых вы сняли галки, остались в прежнем виде. +- Появляется подсказка «Изменения применены. Не забудьте сохранить.» +- После **«Сохранить»** — обычное «Сохранено.» + +**Если что-то не так — баг:** +- Поменялось **число** вопросов или вариантов в каких-то вопросах + (должно остаться как было). +- В вопросе изменилось значение «Несколько правильных ответов» (галка + переключилась сама). +- Изменились вопросы, у которых вы сняли галку. +- Кнопка «Отмена» всё равно применила изменения. +- В колонках «Было» и «Стало» одинаковый текст (нет смысла предлагать). -1. Создайте тест с парой нарочно слабых мест: - - один вопрос с длинной мутной формулировкой; - - один вопрос, где все варианты слишком похожи или в качестве «дистракторов» — очевидная ерунда. -2. Нажмите **«Проверить тест»**. +--- -**Ожидается:** -- Открывается модалка «Проверка теста». -- Есть цветная плашка с одним из вердиктов: **Годен / Есть замечания / Серьёзные проблемы**, и краткое резюме (1–2 предложения). -- Ниже — список разделов («Чёткость формулировок», «Качество дистракторов», «Охват темы», «Сбалансированность сложности»). Разделы без замечаний пропускаются. -- В списке — конкретные пункты на русском, по делу. -- Закрытие модалки крестиком или кнопкой «Закрыть» работает. +### 2.5. AI: вопрос/переформулировать -### A.5. «Улучшить тест» (E1.8) — массовое было → стало +**Простыми словами:** работа с одним вопросом. Если поле пустое — AI его +придумает; если уже заполнено — переформулирует красивее, варианты не трогает. -1. Возьмите тест из A.4 (с ≥ 3 вопросами). -2. Нажмите **«Улучшить тест»**. +**Как проверять (новый вопрос):** +1. В любом тесте нажмите **«Добавить вопрос»** — появилась пустая карточка. +2. **Не трогайте** поле «Формулировка вопроса». +3. Нажмите **«Добавить вариант»** 4 раза — должно стать 4 пустых варианта. +4. Нажмите кнопку **«AI: вопрос/переформулировать»** в этой карточке. -**Ожидается:** -- Открывается модалка с заголовком «Улучшение теста» и подсказкой «Отмечено N из M». -- Каждый изменённый вопрос — отдельная карточка: - - чекбокс «Вопрос #N» (по умолчанию **отмечен**); - - две колонки **Было** / **Стало**; - - изменённый текст в «Было» зачёркнут, в «Стало» — выделен; - - правильные варианты помечены ✓. -- Снимите галку с одного-двух вопросов и нажмите **«Применить выбранное»**. -- В редакторе **только** отмеченные вопросы заменены на улучшенные; остальные остались как были. -- Появляется надпись «Изменения применены. Не забудьте сохранить.» — нажмите **«Сохранить»** и проверьте версионирование (см. Часть 1). -- **Сетка не меняется**: число вопросов, число вариантов в каждом и значение «Несколько правильных» совпадают с исходными. Если модель «слетела» — эндпоинт возвращает 502 с `llm_shape` и UI показывает алерт; это не баг логики. +**Что должно произойти:** +- Поле «Формулировка вопроса» заполнено осмысленным текстом по теме теста. +- Все 4 варианта заполнены. +- Ровно один помечен как правильный. +- Внизу появляется строка статуса **«AI: вопрос сгенерирован.»** -### A.6. AI-кнопка на конкретном вопросе (E1.2) +**Как проверять (переформулировать существующий):** +1. Возьмите готовый вопрос с уже заполненной формулировкой. +2. Нажмите **«AI: вопрос/переформулировать»** в его карточке. -Сценарий «новый вопрос»: +**Что должно произойти:** +- Меняется **только текст вопроса** — варианты ответа остаются прежними, + правильные варианты те же. +- Статус **«AI: формулировка обновлена.»** -1. Добавьте вопрос, **поле текста оставьте пустым**, число вариантов = 4, «Несколько правильных» — выкл. -2. Нажмите **«AI: вопрос/переформулировать»** на этом вопросе. +**Если что-то не так — баг:** +- На пустом вопросе AI ничего не сгенерировал. +- На заполненном вопросе AI поменял варианты ответа или правильность — + должен трогать только формулировку. +- Получилось 0 или 1 правильных вариантов в новом вопросе (надо ровно 1 + для одиночного выбора). -**Ожидается:** заполнен текст вопроса и все 4 варианта; ровно один помечен правильным; внизу — статус «AI: вопрос сгенерирован.» +--- -Сценарий «переформулировать»: +### 2.6. Импорт документа -1. Возьмите готовый вопрос с заполненным текстом. -2. Нажмите ту же кнопку. +**Простыми словами:** автор загружает PDF/Word/текст со статьёй — +AI читает файл и сам предлагает черновик теста. -**Ожидается:** меняется **только текст** вопроса (вариант ответа и правильность не трогаются), статус «AI: формулировка обновлена.» +**Подготовьте файл:** возьмите PDF или DOCX на 1–3 страницы со связным +русским текстом (например, любую методичку или статью). Лимит — 16 МБ. -### A.7. Импорт документа (E1.3) +**Как проверять:** +1. В редакторе любого нового теста (можно пустого) → блок «AI-помощник» + → **«Импортировать»** → нажмите большую кнопку **«Загрузить документ (PDF, DOCX, TXT, MD)»** → выберите файл. +2. Подождите 5–30 секунд. -1. Подготовьте файл `sample.pdf` или `sample.docx` со связным текстом (1–3 страницы) на русском. -2. В редакторе → AI-панель → **«Импорт документа»** → выберите файл. +**Что должно произойти:** +- Появляется подтверждение «Сгенерировано: «…», вопросов: N. Применить как новый черновик? Текущие вопросы будут заменены». Нажмите **OK**. +- Тест заполнен вопросами по содержанию загруженного документа. +- Можно сохранить кнопкой **«Сохранить»**. -**Ожидается:** -- Прогресс «Загружаем «sample.pdf»…». -- Confirm «Сгенерировано: «», вопросов: N. Применить как новый черновик?» → согласие заменяет вопросы, отказ ничего не меняет. -- При файле > 16 МБ — ошибка от Flask (413/500), это норма (лимит). -- При файле неподдерживаемого формата (`.xlsx`, `.png`) — алерт «Неподдерживаемый формат…». -- При **отсутствующем** ключе AI: вместо confirm — алерт с текстом «Автогенерация выключена…» и первыми 600 символами извлечённого текста; вопросы **не** заменяются. +**Дополнительно — отказ:** +1. Повторите загрузку, но в подтверждении нажмите **«Отмена»**. +2. Тест должен остаться **в прежнем виде**, ничего не подменилось. -### A.8. Единая ошибка при отсутствии ключа +**Дополнительно — большой файл:** +1. Возьмите файл больше 16 МБ. +2. Загрузите его. -1. Уберите ключ (как в A.0). Откройте редактор любого теста. -2. По очереди нажимайте **«Сгенерировать по сетке»**, **«по названию»**, **«Проверить тест»**, **«Улучшить тест»**, **«AI: вопрос»**. +**Что должно произойти:** ошибка о слишком большом файле; вопросы не +подменились. -**Ожидается:** в каждом случае confirm с предложением открыть **/settings**, не молчаливый алерт. На бэке — JSON `{ error, code, settingsUrl: "/settings" }`, статус 502. +**Дополнительно — неподдерживаемый тип:** +1. Возьмите файл `.xlsx` или картинку `.png`. +2. Попробуйте загрузить. -### Что фиксировать как баг (AI) +**Что должно произойти:** алерт «Неподдерживаемый формат…»; вопросы не +подменились. -- Кнопка **«Сгенерировать по названию»** позволяет жать без названия и не показывает алерт. -- Модалка **«Проверить тест»** пуста или содержит англ. текст. -- В **«Улучшить тест»** меняется число вопросов / число вариантов / «Несколько правильных», т.е. сетка слетела, и UI всё равно применил. -- В **«AI: вопрос»** на пустом вопросе варианты не сгенерированы; на заполненном — варианты заменены без ведома пользователя. -- Любая AI-ошибка показывается без ссылки на `/settings`, когда ключ действительно отсутствует. -- Импорт документа подменяет вопросы **без confirm**. +**Если что-то не так — баг:** +- Подтверждение не появилось — вопросы заменились молча. +- Отказ в подтверждении всё равно подменил вопросы. +- Большой файл не вызвал ошибку, а как-то «прошёл». +- Файл не на русском дал тест с непонятной кашей вместо вопросов. --- -## Шпаргалка: что и где смотреть - -| Что | URL / SQL | -|---|---| -| Каталог | `/tests` | -| Редактор | `/tests/<id>/edit` | -| Версии теста | `GET /api/tests/<id>/versions` | -| Активность LLM | `/settings` + `POST /api/llm/ping` | -| `test_versions` | `SELECT id, version, is_active, parent_id, created_at FROM test_versions WHERE test_id = '<id>' ORDER BY version;` | -| Попытки | `SELECT id, test_version_id, status, created_at FROM test_attempts WHERE test_version_id IN (SELECT id FROM test_versions WHERE test_id='<id>');` | - -При баге прикладывайте: -- скрин редактора / модалки; -- ответ соответствующего эндпоинта (DevTools → Network → JSON); -- результат SQL из таблицы выше; -- `docker compose -f docker-compose.dev.yml logs --tail=200 testing-flask`. +### 2.7. Поведение, если ключа AI нет + +> Этот сценарий обычно проверять не нужно — он сработает автоматически, если разработчик уберёт ключ. +> Но если в каталоге AI вообще не работает, то проверьте именно это, чтобы понять — это баг или просто ключ не настроен. + +**Как проверять:** +1. **«Настройки»** → если статус **«Не задан»** (красный) — это и есть тестируемая ситуация. +2. Откройте любой тест и нажмите по очереди: + - **«По названию»** + - **«По текущей сетке»** + - **«Проверить»** + - **«Улучшить»** + - **«AI: вопрос/переформулировать»** в любой карточке + - **«Загрузить документ»** + +**Что должно произойти:** в каждом случае появляется понятное сообщение, +что AI не настроен, **и предложение открыть «Настройки»**. После согласия +— открывается страница `/settings`. Никакого «AI: ошибка» без объяснений. + +**Если что-то не так — баг:** +- Сообщение об ошибке без слов «Настройки». +- Ссылка/кнопка «Открыть Настройки» не ведёт на нужную страницу. +- Сайт молча ничего не делает после нажатия AI-кнопки. + +--- + +## Памятка: общий алгоритм отчёта о баге + +Если что-то идёт не так, к тикету приложите: + +1. **URL страницы**, на которой воспроизвели баг (полностью, из адресной + строки). +2. **Шаги** — что именно нажимали по порядку (1-2-3). +3. **Что увидели** против **что ожидали увидеть** (по описанию выше). +4. **Скриншот** экрана с проблемой (для модалок — со всем содержимым окна). +5. Если ошибка — **точный текст** сообщения. +6. **Учётная запись**, под которой воспроизвели (логин, без пароля). + +Этого достаточно — лезть в консоль/код/базу не нужно и не надо.