feat(trainer): P3 — текстовые задачи от LLM с серверной проверкой подстановкой

- practiceVerify.js: грузит SimExpr в Node (require), verifyRoot подстановкой корня
- practiceGenService.js: LLM (инъектируемый ask) → parse → validateAndVerify (SimExpr + подстановка + санитизация) → авторетрай по фидбэку; дефолт ask = assistantController.callLLMFailover
- пул practice_problems (мигр.083); POST /api/practice/generate (учитель/админ) + GET /api/practice/pool
- инвариант: невалидная/неверная задача в БД НЕ пишется → ученику не попадёт
- клиент: LS.practicePool/Generate, тема «Текстовые задачи» (из пула; учителю кнопка «Сгенерировать»)
- тесты practice-gen.test.js 13/13 (verify, ретраи, off→503, 403 ученику, пул); смоуки страница 26/26; план P3 → DONE

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-25 14:00:39 +03:00
parent 48a73d9f8e
commit 8c4c9bf04c
9 changed files with 445 additions and 9 deletions
+13 -2
View File
@@ -75,9 +75,20 @@ practice.test.js 11/11 (+SR box/due).
- **Acceptance:** сессия из N задач сама ведёт от простого к сложному; промахнутый навык
всплывает повторно; прогресс переживает перезаход.
## Phase 3 — Уровень 1: LLM-задачи с верификацией
## Phase 3 — Уровень 1: LLM-задачи с верификацией — DONE
**Цель:** текстовые/контекстные задачи, которых не даёт параметрика.
**Сделано:** серверная проверка `backend/src/utils/practiceVerify.js` (грузит `SimExpr`
в Node через require, `verifyRoot` подстановкой). Сервис `practiceGenService.js`:
`buildMessages`→LLM→`parseProblem``validateAndVerify` (компиляция SimExpr + подстановка
корня + санитизация story/шагов) с **авторетраем по фидбэку**; LLM-вызов инъектируется
(`opts.ask`, дефолт — `assistantController.callLLMFailover`). Пул `practice_problems`
(мигр.**083**, status approved/draft). Эндпоинты: `POST /api/practice/generate`
(учитель/админ) + `GET /api/practice/pool` (ученикам). Клиент: `LS.practicePool/Generate`,
тема **«Текстовые задачи»** на странице (берёт из пула; учителю — кнопка «Сгенерировать»).
Гарантия: невалидная/неверная задача в БД НЕ пишется → ученику не попадёт.
Тесты `practice-gen.test.js` 13/13 (verify, ретраи, off→503, 403 ученику, пул).
**Цель (исходная):** текстовые/контекстные задачи, которых не даёт параметрика.
- LLM (через провайдеров админки) генерирует `{ lhs, rhs, answer, story }`; сервер прогоняет
`verifyRoot`; расхождение → авторетрай с фидбэком («корень не удовлетворяет, исправь»).