docs(ct-math): план подготовки к ЦЭ/ЦТ по математике + миграция дерева тем

- plans/ct-math: модульная программа (карта теста А1–А10/В1–В20, 9 блоков
  и ~32 модуля, 3 уровня, маппинг на exam-prep платформы), 2 пилота
  (тригонометрия, стереометрия), seed дерева тем, спецификация оцифровки
  заданий РТ/ЦТ, инвентарь материалов
- backend: миграция 077 — трек ctmath + exam_topics (9 разделов, 32 подтемы),
  валидирована in-memory node:sqlite; на живую БД НЕ применялась

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-14 21:26:43 +03:00
parent c9a00d105e
commit 7eb6cb2da0
8 changed files with 1187 additions and 0 deletions
+190
View File
@@ -0,0 +1,190 @@
# Спецификация оцифровки заданий РТ/ЦТ → `exam_tasks` + диагностика
> Как переносить задания из PDF (РТ 20062025, ЦТ/ЦЭ 20042024) в банк `exam_tasks` трека `ctmath`,
> как их классифицировать (тема/сложность/тип) и как собрать входной диагностический тест.
> Опирается на реальные конвейеры платформы: `backend/scripts/import-exam-tasks.js` (импорт),
> `tag-exam-tasks.js` (классификатор темы), формат вариантов `frontend/js/exam9/variants/v*.js`.
---
## 1. Схема целевой таблицы (напоминание)
```sql
exam_tasks(
id, exam_key, variant, task_idx,
task_type TEXT CHECK (task_type IN ('mc','open','long')),
text_html, figure_html, opts_json, answer, solution_html,
topic, subtopic, difficulty,
UNIQUE(exam_key, variant, task_idx)
)
```
Для трека: `exam_key='ctmath'`, `variant` = номер варианта (сквозная нумерация по источникам, см. §6), `task_idx` = 1..30.
---
## 2. Маппинг номера задания → тип и подтема
Позиция в ЦЭ/ЦТ почти жёстко задаёт тему (карта §1.2 PLAN.md). Это **дефолт классификатора** — экономит ручную разметку; правится точечно, если конкретный вариант отклонился.
| task_idx | task_type | topic (раздел) | subtopic (по умолчанию) | difficulty |
|---|---|---|---|---|
| 1 (А1) | mc | numbers | `num-real` | 1 |
| 2 (А2) | mc | stereometry | `ster-basics` | 2 |
| 3 (А3) | mc | trigonometry | `trig-circle` | 1 |
| 4 (А4) | mc | numbers | `num-divisibility` | 1 |
| 5 (А5) | mc | equations | `eq-quadratic` | 1 |
| 6 (А6) | mc | equations | `eq-linear` | 2 |
| 7 (А7) | mc | word-sequences | `word-problems` | 2 |
| 8 (А8) | mc | trigonometry | `trig-identities` | 2 |
| 9 (А9) | mc | stereometry | `ster-rotation` | 3 |
| 10 (А10) | mc | expressions | `expr-powers-roots` | 2 |
| 11 (В1) | open | stereometry | `ster-angles-distances` | 3 |
| 12 (В2) | open | functions | `fn-properties` | 2 |
| 13 (В3) | open | word-sequences | `seq-progressions` | 2 |
| 14 (В4) | open | trigonometry | `trig-identities` | 3 |
| 15 (В5) | open | planimetry | `plan-triangles` | 3 |
| 16 (В6) | open | word-sequences | `seq-progressions` | 3 |
| 17 (В7) | open | word-sequences | `word-problems` | 3 |
| 18 (В8) | open | equations | `eq-linear` | 2 |
| 19 (В9) | open | functions | `fn-properties` | 3 |
| 20 (В10) | open | planimetry | `plan-quadrilaterals` | 3 |
| 21 (В11) | open | equations | `eq-logarithmic` | 3 |
| 22 (В12) | open | numbers | `num-divisibility` | 4 |
| 23 (В13) | open | stereometry | `ster-rotation` | 4 |
| 24 (В14) | open | equations | `eq-exponential` | 4 |
| 25 (В15) | open | trigonometry | `trig-equations` | 5 |
| 26 (В16) | open | equations | `eq-logarithmic` | 5 |
| 27 (В17) | open | stereometry | `ster-polyhedra` | 5 |
| 28 (В18) | open | equations | `eq-irrational` | 4 |
| 29 (В19) | open | functions | `fn-derivative` | 5 |
| 30 (В20) | open | stereometry | `ster-angles-distances` | 5 |
> Часть А = `mc` (всегда 5 вариантов ответа). Часть В = `open` (число/слово/комбинация цифр).
> `long` использовать только если ответ не авто-проверяем (в ЦЭ/ЦТ почти не встречается — там всё с коротким ответом).
> ⚠️ Маппинг — стартовый; при оцифровке КАЖДОГО варианта проверять реальную тему задания и при отклонении менять `subtopic`/`difficulty` вручную.
---
## 3. Форматы полей
### 3.1. `text_html`
Условие задания с формулами в KaTeX-разметке (`$...$` инлайн). HTML допустим (списки, `<br>`). Картинки/чертежи — в `figure_html`.
### 3.2. `figure_html`
Чертёж: предпочтительно inline `<svg>` (масштабируемо, тема). Допустимо `<img src="/img/ct/math/...">` (как уже практикуется в репозитории — см. `frontend/img/ct/math/`). NULL, если рисунка нет.
### 3.3. `opts_json` (только `mc`)
Массив пар `[метка, html]`, как в `exam9`:
```json
[["1","$-16$"],["2","$-12$"],["3","$12$"],["4","$26$"],["5","$-26$"]]
```
(В ЦЭ/ЦТ метки — цифры 1–5.)
### 3.4. `answer`
- `mc`: метка верного варианта, напр. `"5"`.
- `open`: строка-эталон ответа. Форматы части В:
- число: `"-26"`, `"24"`, `"153"`;
- комбинация цифр (В1-тип «выберите верные», порядок не важен): хранить нормализованно, напр. отсортированные цифры `"124"`; проверку делать как множество цифр;
- комбинация буква-цифра (В2-тип сопоставление): `"А5Б1В4"` (как в реальном бланке).
- ⚠️ Договориться о нормализации ответа на клиенте (тримминг, запятая/точка в дробях, регистр) — это логика проверки, не данные. В части В реального ЦТ ответ — целое/конечная десятичная дробь; условие часто просит «увеличьте в N раз», чтобы ответ стал целым (учитывать при вводе эталона).
### 3.5. `solution_html`
Полное решение в HTML+KaTeX. Рекомендуется завершать блоком ответа в стиле exam9:
```html
<div class="sol-ans">Ответ: $-26$</div>
```
(`import-exam-tasks.js` умеет парсить `answer` из такого блока — переиспользовать конвейер.)
### 3.6. `topic` / `subtopic` / `difficulty`
- `topic` = slug раздела, `subtopic` = slug подтемы (из [TOPICS_SEED.md](TOPICS_SEED.md)).
- Дефолт — по таблице §2; правка вручную при отклонении.
- `difficulty` 1–5: 1–2 = часть А и лёгкая В; 3 = средняя В; 45 = В12+, В14–В20. Рубрика — §4.
---
## 4. Рубрика сложности (difficulty 15)
| Балл | Признак | Где |
|---|---|---|
| 1 | одно действие/определение, устно | А1, А3, А4, А5 |
| 2 | 2–3 шага, базовая формула | А-часть, В2, В3, В8 |
| 3 | несколько шагов, выбор метода | В4–В11, А9 |
| 4 | многошаговое + ОДЗ/отбор/подобие | В12–В14, В18 |
| 5 | сложный метод (рационализация, отбор корней, координатный метод в 3D) | В15–В17, В19, В20 |
---
## 5. Конвейер оцифровки (рекомендуемый порядок шагов)
1. **Источник → структура.** Один вариант = 30 задач. Удобный промежуточный формат — JS-объект как в `frontend/js/exam9/variants/vNN.js` (`text`, `opts`, `sol` с `sol-ans`).
2. **Импорт.** Прогнать через `backend/scripts/import-exam-tasks.js` (автоопределение `mc`/`open` по наличию `opts`, парс `answer` из `sol-ans`).
3. **Классификация.** Проставить `topic`/`subtopic`/`difficulty` по §2 (можно скриптом по `task_idx`), затем выборочно проверить отклонения (по аналогии с `tag-exam-tasks.js`).
4. **Чертежи.** Для задач с рисунком — добавить `figure_html` (SVG/`<img>`); часть А2/А9/В1/В13/В17/В20 почти всегда с чертежом.
5. **Верификация.** Сверить `answer` с официальными ответами (папки `…\Ответы…`, DJVU-исходники) — критично для авто-проверки.
6. **Сборка вариантов.** Полные варианты доступны как `exam_mock_sessions` (пробники на 180 мин) автоматически — нужна только заполненность 30 задач варианта.
> OCR кириллицы+формул из PDF/DJVU ненадёжен на математике — формулы почти всегда перенабираются вручную в KaTeX. Это основной объём работы; приоритет источников — §6.
---
## 6. Приоритет источников для оцифровки
| Очередь | Источник | Почему |
|---|---|---|
| 1 | `ЦТ-ЦЭ\ЦЭ-ЦТ-2024 МАТ.pdf` | эталон текущего формата, есть ответы |
| 2 | `РТ\2022-2023 … 2024-2025` | свежие, формат совпадает, 3 этапа × 2 варианта |
| 3 | `ЦТ-ЦЭ\20172021` + DJVU-ответы | большой банк реальных заданий с ответами |
| 4 | `РТ\20162021` | расширение банка |
| 5 | `ДРТ\` | доп. варианты + разборы консультаций |
| 6 | старые `РТ/ЦТ 20042015` | архив, по мере необходимости |
Нумерация `variant`: сквозная, с префиксом-меткой источника в `solution_html`/комментарии (напр. «ЦЭ-2024», «РТ-2024 этап 2 в1»), чтобы не терять происхождение.
---
## 7. Входной диагностический тест
Цель: за ~30–40 минут определить уровень по каждому разделу → назначить трек и приоритетные модули.
### Состав (1 задание на ключевую подтему, смесь А и В, 12–15 задач)
| # | Подтема | Уровень-зонд | Источник-позиция |
|---|---|---|---|
| 1 | `num-real` | 🟢 | А1 |
| 2 | `eq-quadratic` | 🟢 | А5 |
| 3 | `trig-circle` | 🟢 | А3 |
| 4 | `expr-powers-roots` | 🟢 | А10 |
| 5 | `word-problems` | 🟡 | А7 / В7 |
| 6 | `seq-progressions` | 🟡 | В3 / В6 |
| 7 | `fn-properties` | 🟡 | В2 / В9 |
| 8 | `trig-identities` | 🟡 | В4 |
| 9 | `plan-triangles` | 🟡 | В5 |
| 10 | `ster-basics` | 🟡 | А2 / В1 |
| 11 | `eq-logarithmic` | 🔴 | В11 → В16 |
| 12 | `trig-equations` | 🔴 | В15 |
| 13 | `fn-derivative` | 🔴 | В19 |
| 14 | `ster-angles-distances` | 🔴 | В20 |
### Логика назначения трека (по результату)
- Доля верных среди 🟢-зондов < 75% **или** «проваленные» базовые разделы → стартовый трек **База**; провальные разделы проходятся с нуля.
- 🟢 уверенно, 🟡 ≥ ~50% → трек **Ядро**.
- 🟢+🟡 уверенно и хотя бы часть 🔴 решена → трек **Продвинутый**.
- Любой раздел с диагностикой < 50% → этот раздел всегда с уровня База, независимо от общего трека (правило ветвления §4.3 PLAN.md).
### Реализация на платформе
- Диагностика = `exam_mock_sessions` с `source='random'`/спец-набор `task_ids_json` из перечисленных подтем, либо practice-набор `strategy=weak`.
- Результаты пишутся в `exam_attempts` (по подтемам) → дашборд/детектор слабых тем сразу строит heatmap и список приоритетов.
- `exam_user_plan.weak_focus=1` — включить фокус на слабых темах (опционально).
---
## 8. Чек-лист «задание готово»
- [ ] `text_html` набран, формулы в KaTeX, читается;
- [ ] `figure_html` добавлен (если есть чертёж);
- [ ] `opts_json` для `mc` (5 вариантов) / отсутствует для `open`;
- [ ] `answer` сверен с официальным ключом, нормализован;
- [ ] `solution_html` с `sol-ans`;
- [ ] `topic`/`subtopic`/`difficulty` проставлены и проверены против реальной темы;
- [ ] `UNIQUE(exam_key, variant, task_idx)` не нарушен.