diff --git a/backend/scripts/seed_ctmath_rt2223_e1v1.js b/backend/scripts/seed_ctmath_rt2223_e1v1.js
new file mode 100644
index 0000000..4152d86
--- /dev/null
+++ b/backend/scripts/seed_ctmath_rt2223_e1v1.js
@@ -0,0 +1,400 @@
+'use strict';
+/* ───────────────────────────────────────────────────────────────────────────
+ seed_ctmath_rt2223_e1v1.js
+ Чистый вариант-пробник для трека exam-prep `ctmath`.
+
+ Источник: РТ–2022/2023, Этап I, Вариант 1 (РИКЗ, «Тематическое
+ консультирование по математике»). 30 заданий: А1–А10 + В1–В20.
+ Перенабрано вручную в KaTeX по PDF (визуальное чтение, НЕ OCR):
+ F:\!Рабочие\ЦТ\Математика\Математика\РТ\2022-2023\МАТ РТ-1 22_23 В1.pdf
+
+ variant=107 — РТ-2022/23 Этап I (этап II — 108, этап III — 109).
+ Геометрия закодирована текстом. Адаптации заданий-«с-картинкой»:
+ • А5 (выбор графика y=x²−4 среди 5 рисунков) → самодостаточный MC о
+ расположении параболы (та же проверяемая идея, авто-проверка);
+ • В1 (числовой промежуток ↔ изображение на прямой) → сопоставление с
+ словесными описаниями промежутков (ответ тот же: А3Б6В2);
+ • В3 (столбчатая диаграмма) → те же данные в таблице (figure_html),
+ сопоставление вопрос↔месяц (ответ А1Б2В6).
+
+ Идемпотентность: upsert по UNIQUE(exam_key, variant, task_idx).
+ Запуск:
+ node backend/scripts/seed_ctmath_rt2223_e1v1.js # DRY-RUN (по умолчанию)
+ node backend/scripts/seed_ctmath_rt2223_e1v1.js --apply # запись в БД
+
+ ⚠️ Массовую запись в БД запускает ПОЛЬЗОВАТЕЛЬ вручную (авто-режим Claude Code
+ блокирует продакшн-записи). Без --apply ничего не пишется.
+ ─────────────────────────────────────────────────────────────────────────── */
+
+const { DatabaseSync } = require('node:sqlite');
+const path = require('path');
+
+const APPLY = process.argv.includes('--apply');
+const EXAM = 'ctmath';
+const VARIANT = 107;
+const PROV = 'РТ–2022/2023, Этап I, Вариант 1';
+const R = String.raw;
+
+const L = ['а', 'б', 'в', 'г', 'д'];
+const mc = (...html) => html.map((h, i) => [L[i], h]);
+
+/* ── figure_html для В3: данные диаграммы в виде таблицы (П — пробная версия,
+ ПЛ — купившие лицензию), по месяцам янв–июнь. Только HTML, без KaTeX. */
+const FIG_B3 = `
+
+ | Показатель |
+ Январь |
+ Февраль |
+ Март |
+ Апрель |
+ Май |
+ Июнь |
+
+
+ | П |
+ 58000 |
+ 66000 |
+ 64000 |
+ 62000 |
+ 50000 |
+ 56000 |
+
+
+ | ПЛ |
+ 22000 |
+ 16000 |
+ 14000 |
+ 12000 |
+ 10000 |
+ 14000 |
+
+
`;
+
+/* ── 30 заданий ─────────────────────────────────────────────────────────── */
+const TASKS = [
+ // ── Часть A: А1–А10 ──────────────────────────────────────────────────────
+ { idx: 1, type: 'mc', topic: 'numbers', subtopic: 'num-real', diff: 1,
+ text: R`Среди чисел $-\dfrac58$, $\ 2$, $\ \dfrac85$, $\ \dfrac58$, $\ -\dfrac85$ выберите положительное число, меньшее единицы.`,
+ opts: mc('$-\dfrac58$', '$2$', '$\dfrac85$', '$\dfrac58$', '$-\dfrac85$'),
+ answer: 'г',
+ sol: R`Положительны числа $2$, $\dfrac85$ и $\dfrac58$. Из них меньше единицы только $\dfrac58$ (так как $2>1$ и $\dfrac85>1$).`,
+ ref: 'Герасимов «Математика, 6 кл.», гл. 4, § 3' },
+
+ { idx: 2, type: 'mc', topic: 'numbers', subtopic: 'num-divisibility', diff: 2,
+ text: R`Среди данных утверждений укажите номер верного.
1) число $0$ — делитель числа $19$;
2) число $7$ — делитель числа $37$;
3) число $8$ — делитель числа $8$;
4) число $3$ — делитель числа $43$;
5) число $6$ — делитель числа $26$.`,
+ opts: mc('утверждение 1', 'утверждение 2', 'утверждение 3', 'утверждение 4', 'утверждение 5'),
+ answer: 'в',
+ sol: R`Делитель числа делит его без остатка. $\ 1)$ деление на $0$ не имеет смысла — неверно. $\ 2)$ $37=5\cdot7+2$ — неверно. $\ 3)$ $8:8=1$ — верно. $\ 4)$ $43=14\cdot3+1$ — неверно. $\ 5)$ $26=4\cdot6+2$ — неверно.`,
+ ref: 'Герасимов «Математика, 5 кл.», ч. 1, гл. 1, § 12' },
+
+ { idx: 3, type: 'mc', topic: 'planimetry', subtopic: 'plan-triangles', diff: 2,
+ text: R`Треугольники $ABC$ и $A_1B_1C_1$ подобны, причём $\angle A=105^\circ$ и $\angle C_1=30^\circ$. Найдите градусную меру угла $B$ треугольника $ABC$.`,
+ opts: mc('$55^\circ$', '$45^\circ$', '$50^\circ$', '$35^\circ$', '$40^\circ$'),
+ answer: 'б',
+ sol: R`У подобных треугольников соответственные углы равны, поэтому $\angle C=\angle C_1=30^\circ$. По теореме о сумме градусных мер углов треугольника $\angle B=180^\circ-\angle A-\angle C=180^\circ-105^\circ-30^\circ=45^\circ$.`,
+ ref: 'Казаков «Геометрия, 8 кл.», гл. 3, § 20' },
+
+ { idx: 4, type: 'mc', topic: 'equations', subtopic: 'eq-linear', diff: 1,
+ text: R`Среди чисел $-1$, $\ 2$, $\ \dfrac13$, $\ 1$, $\ -\dfrac13$ укажите то, которое является корнем уравнения $1-3x=2$.`,
+ opts: mc('$-1$', '$2$', '$\dfrac13$', '$1$', '$-\dfrac13$'),
+ answer: 'д',
+ sol: R`Из уравнения $1-3x=2$ получаем $-3x=1$, то есть $x=-\dfrac13$. Это число и есть корень.`,
+ ref: 'Арефьева «Алгебра, 7 кл.», гл. 3, § 15' },
+
+ { idx: 5, type: 'mc', topic: 'functions', subtopic: 'fn-graphs', diff: 1,
+ text: R`График функции $y=x^{2}-4$ — парабола. Укажите верное утверждение о её расположении на координатной плоскости.`,
+ opts: mc('ветви вверх, вершина в точке $(0;-4)$', 'ветви вниз, вершина в точке $(0;-4)$', 'ветви вверх, вершина в точке $(0;4)$', 'ветви вниз, вершина в точке $(0;4)$', 'ветви вверх, вершина в точке $(4;0)$'),
+ answer: 'а',
+ sol: R`График $y=x^{2}-4$ получается из графика $y=x^{2}$ сдвигом на $4$ единицы вниз вдоль оси ординат. Это парабола с ветвями вверх и вершиной в точке $(0;-4)$.`,
+ ref: 'Арефьева «Алгебра, 8 кл.», гл. 3, § 13' },
+
+ { idx: 6, type: 'open', topic: 'functions', subtopic: 'fn-properties', diff: 2,
+ text: R`Укажите номера функций, для которых выполняется неравенство $f(0)<-3$.
1) $f(x)=x^{2}-6$;
2) $f(x)=|x-4|$;
3) $f(x)=|x|-3$;
4) $f(x)=x^{3}-4$;
5) $f(x)=(x-8)^{2}$.
Ответ запишите цифрами в порядке возрастания, без пробелов.`,
+ answer: '14', ansShow: '1, 4',
+ sol: R`Найдём $f(0)$: $\ 1)$ $0-6=-6<-3$ — верно. $\ 2)$ $|-4|=4$ — нет. $\ 3)$ $|0|-3=-3$, не меньше $-3$ — нет. $\ 4)$ $0-4=-4<-3$ — верно. $\ 5)$ $(-8)^{2}=64$ — нет. Подходят функции 1 и 4.`,
+ ref: 'Арефьева «Алгебра, 9 кл.», гл. 2, § 6' },
+
+ { idx: 7, type: 'mc', topic: 'word-sequences', subtopic: 'word-problems', diff: 2,
+ text: R`Руда содержит $5\%$ чистого металла. Сколько тонн руды необходимо взять, чтобы получить $13$ т чистого металла?`,
+ opts: mc('$130$', '$230$', '$160$', '$260$', '$390$'),
+ answer: 'г',
+ sol: R`Пусть нужно взять $x$ т руды. Составим пропорцию: $x$ т — $100\%$, $13$ т — $5\%$. Тогда $x=\dfrac{13\cdot100}{5}=260$ (т).`,
+ ref: 'Герасимов «Математика, 6 кл.», гл. 2, § 1–2' },
+
+ { idx: 8, type: 'mc', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 1,
+ text: R`Найдите значение выражения $\dfrac{7\sqrt[3]{48}}{\sqrt[3]{6}}$.`,
+ opts: mc('$7\sqrt[3]{6}$', '$14$', '$7\sqrt[3]{2}$', '$7$', '$28$'),
+ answer: 'б',
+ sol: R`$\dfrac{7\sqrt[3]{48}}{\sqrt[3]{6}}=7\sqrt[3]{\dfrac{48}{6}}=7\sqrt[3]{8}=7\cdot2=14$.`,
+ ref: 'Арефьева «Алгебра, 10 кл.», гл. 2, § 14' },
+
+ { idx: 9, type: 'mc', topic: 'stereometry', subtopic: 'ster-polyhedra', diff: 2,
+ text: R`Дан прямоугольный параллелепипед $ABCDA_1B_1C_1D_1$. Найдите площадь его диагонального сечения $AA_1C_1C$, если диагональ основания $AC=2\sqrt6$, а диагональ $A_1C=7$.`,
+ opts: mc('$12\sqrt3$', '$4\sqrt{37}$', '$9\sqrt6$', '$14\sqrt6$', '$10\sqrt6$'),
+ answer: 'д',
+ sol: R`Сечение $AA_1C_1C$ — прямоугольник со сторонами $AC$ и боковым ребром $A_1A$. По теореме Пифагора в треугольнике $A_1AC$: $A_1A=\sqrt{A_1C^{2}-AC^{2}}=\sqrt{49-24}=\sqrt{25}=5$. Площадь сечения $AC\cdot A_1A=2\sqrt6\cdot5=10\sqrt6$.`,
+ ref: 'Латотин «Геометрия, 11 кл.», разд. 1, § 1' },
+
+ { idx: 10, type: 'open', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 2,
+ text: R`Укажите номера выражений, областью определения которых является множество всех действительных чисел.
1) $\sqrt{x}$;
2) $\dfrac{1}{1+x}$;
3) $2x-1$;
4) $\sqrt[3]{x}$;
5) $\operatorname{tg}x$.
Ответ запишите цифрами в порядке возрастания, без пробелов.`,
+ answer: '34', ansShow: '3, 4',
+ sol: R`$1)$ $\sqrt{x}$ определено при $x\ge0$ — нет. $\ 2)$ $\dfrac{1}{1+x}$ не определено при $x=-1$ — нет. $\ 3)$ $2x-1$ определено при всех $x$ — да. $\ 4)$ $\sqrt[3]{x}$ определено при всех $x$ — да. $\ 5)$ $\operatorname{tg}x$ не определено при $x=\dfrac{\pi}{2}+\pi n$ — нет. Подходят 3 и 4.`,
+ ref: 'Арефьева «Алгебра, 7 кл.», гл. 2, § 4' },
+
+ // ── Часть B: В1–В20 ──────────────────────────────────────────────────────
+ { idx: 11, type: 'long', topic: 'numbers', subtopic: 'num-real', diff: 2,
+ text: R`Установите соответствие между числовым промежутком А–В и его описанием 1–6.
Промежуток:
А) $(-4{,}2;+\infty)$;
Б) $(-\infty;5]$;
В) $[-4{,}2;5)$.
Описание:
1) открытый луч, направленный влево от точки $5$;
2) полуинтервал от $-4{,}2$ (включая) до $5$ (не включая);
3) открытый луч, направленный вправо от точки $-4{,}2$;
4) отрезок от $-4{,}2$ до $5$ (обе границы включены);
5) луч, направленный вправо от точки $-4{,}2$, включая её;
6) луч, направленный влево от точки $5$, включая её.
Ответ запишите сочетанием букв и цифр, например: А1Б1В4.`,
+ answer: 'А3Б6В2', ansShow: 'А3Б6В2',
+ sol: R`А) $(-4{,}2;+\infty)$ — открытый луч вправо от $-4{,}2$ (граница не включена) — описание 3. Б) $(-\infty;5]$ — луч влево, точка $5$ включена — описание 6. В) $[-4{,}2;5)$ — от $-4{,}2$ (включая) до $5$ (не включая) — описание 2.`,
+ ref: 'Арефьева «Алгебра, 8 кл.», гл. 1, § 5' },
+
+ { idx: 12, type: 'open', topic: 'expressions', subtopic: 'expr-polynomials', diff: 2,
+ text: R`Выберите верные утверждения.
1) выражение $\dfrac27 a^{2}b^{5}$ является одночленом;
2) выражения $5ab^{4}$ и $5a^{5}b$ являются одночленами пятой степени;
3) коэффициент одночлена $x\cdot3^{2}$ равен $1$;
4) при $x=0{,}5$ и $y=-1$ значение одночлена $-6xy^{3}$ равно $3$;
5) степень одночлена $-3ab^{2}c^{4}$ равна $7$;
6) выражение $-6x^{0{,}5}y^{3}$ является одночленом.
Ответ запишите цифрами в порядке возрастания, без пробелов.`,
+ answer: '145', ansShow: '1, 4, 5',
+ sol: R`$1)$ верно: $\dfrac27 a^{2}b^{5}$ — произведение числа и натуральных степеней переменных. $\ 2)$ неверно: степень $5ab^{4}$ равна $5$, а $5a^{5}b$ — равна $6$. $\ 3)$ неверно: $x\cdot3^{2}=9x$, коэффициент $9$. $\ 4)$ верно: $-6\cdot0{,}5\cdot(-1)^{3}=3$. $\ 5)$ верно: степень $-3ab^{2}c^{4}$ равна $1+2+4=7$. $\ 6)$ неверно: $x^{0{,}5}$ — не натуральная степень.`,
+ ref: 'Арефьева «Алгебра, 7 кл.», гл. 2, § 6' },
+
+ { idx: 13, type: 'long', topic: 'functions', subtopic: 'fn-graphs', diff: 2,
+ fig: FIG_B3,
+ text: R`В таблице приведено количество пользователей пробной версии (П) программного обеспечения и количество пользователей, купивших лицензию (ПЛ), за период шесть месяцев (с января по июнь). Установите соответствие между вопросами А–В и ответами 1–6.
Вопрос:
А) В каком месяце количество пользователей пробной версии составило $58000$?
Б) В каком месяце количество пользователей, купивших лицензию, равнялось $16000$?
В) В каком месяце количество пользователей, купивших лицензию, составило $25\%$ от количества пользователей пробной версии?
Ответ:
1) Январь; 2) Февраль; 3) Март; 4) Апрель; 5) Май; 6) Июнь.
Ответ запишите сочетанием букв и цифр, например: А1Б1В4.`,
+ answer: 'А1Б2В6', ansShow: 'А1Б2В6',
+ sol: R`А) Пробная версия равна $58000$ в январе — ответ 1. Б) Купивших лицензию $16000$ в феврале — ответ 2. В) Отношение купивших лицензию к пользователям пробной версии равно $25\%$ в июне: $\dfrac{14000}{56000}=0{,}25$ — ответ 6. (В остальных месяцах отношение иное: январь $\approx38\%$, май $20\%$ и т. д.)`,
+ ref: 'Герасимов «Математика, 5 кл.», ч. 2, гл. 3, § 16' },
+
+ { idx: 14, type: 'open', topic: 'stereometry', subtopic: 'ster-polyhedra', diff: 2,
+ text: R`Дана правильная призма, имеющая $12$ вершин. Выберите верные утверждения.
1) количество всех граней данной призмы равно $7$;
2) количество всех рёбер данной призмы равно $18$;
3) количество боковых граней данной призмы равно $6$;
4) градусная мера внутреннего угла основания данной призмы равна $120^\circ$;
5) количество боковых рёбер данной призмы равно $12$;
6) диагональным сечением данной призмы является шестиугольник.
Ответ запишите цифрами в порядке возрастания, без пробелов.`,
+ answer: '234', ansShow: '2, 3, 4',
+ sol: R`$12$ вершин $\Rightarrow$ в основаниях правильные шестиугольники (по $6$ вершин). $\ 1)$ неверно: граней $6+2=8$. $\ 2)$ верно: рёбер $6+6+6=18$. $\ 3)$ верно: боковых граней $6$. $\ 4)$ верно: внутренний угол правильного шестиугольника $\dfrac{180^\circ\cdot4}{6}=120^\circ$. $\ 5)$ неверно: боковых рёбер $6$. $\ 6)$ неверно: диагональное сечение призмы — четырёхугольник.`,
+ ref: 'Латотин «Геометрия, 11 кл.», разд. 1, § 1' },
+
+ { idx: 15, type: 'open', topic: 'planimetry', subtopic: 'plan-triangles', diff: 2,
+ text: R`В равнобедренном треугольнике $ABC$ с основанием $AC$ известно, что $\angle BAC=34^\circ$. Через вершину $A$ проведён луч $AD$ так, что $AD\parallel BC$ (точки $D$ и $B$ лежат по одну сторону от прямой $AC$). Угол $1$ образован лучами $AD$ и $AB$. Найдите градусную меру угла $1$.`,
+ answer: '112',
+ sol: R`Углы при основании равнобедренного треугольника равны: $\angle ACB=\angle BAC=34^\circ$. По теореме о сумме углов $\angle ABC=180^\circ-2\cdot34^\circ=112^\circ$. Угол $1$ и угол $ABC$ — накрест лежащие при $AD\parallel BC$ и секущей $AB$, поэтому $\angle 1=\angle ABC=112^\circ$.`,
+ ref: 'Казаков «Геометрия, 7 кл.», гл. 2, § 11; гл. 3, § 17' },
+
+ { idx: 16, type: 'open', topic: 'trigonometry', subtopic: 'trig-identities', diff: 2,
+ text: R`Найдите значение выражения $\dfrac{72}{\pi}\cdot\operatorname{arctg}\left(-\dfrac{\sqrt3}{3}\right)$.`,
+ answer: '-12',
+ sol: R`$\operatorname{arctg}\left(-\dfrac{\sqrt3}{3}\right)=-\operatorname{arctg}\dfrac{\sqrt3}{3}=-\dfrac{\pi}{6}$. Тогда $\dfrac{72}{\pi}\cdot\left(-\dfrac{\pi}{6}\right)=-12$.`,
+ ref: 'Арефьева «Алгебра, 10 кл.», гл. 1, § 7' },
+
+ { idx: 17, type: 'open', topic: 'word-sequences', subtopic: 'seq-progressions', diff: 2,
+ text: R`Найдите третий член арифметической прогрессии, у которой сумма $n$ первых членов выражается формулой $S_n=\dfrac{11-3n}{2}\cdot n$.`,
+ answer: '-2',
+ sol: R`$a_3=S_3-S_2$. $\ S_2=\dfrac{11-6}{2}\cdot2=5$; $\ S_3=\dfrac{11-9}{2}\cdot3=3$. Тогда $a_3=3-5=-2$.`,
+ ref: 'Арефьева «Алгебра, 9 кл.», гл. 4, § 15–16' },
+
+ { idx: 18, type: 'open', topic: 'equations', subtopic: 'eq-linear', diff: 3,
+ text: R`Света купила $6$ ручек и $5$ карандашей, а Коля купил $4$ такие же по цене ручки и $8$ таких же по цене карандашей и заплатил на $1$ рубль $60$ копеек меньше, чем Света. Сколько копеек заплатила за покупку Света, если карандаш дешевле ручки на $90$ копеек?`,
+ answer: '760',
+ sol: R`Пусть ручка стоит $x$ коп., карандаш $y$ коп. Тогда $\begin{cases}(6x+5y)-(4x+8y)=160,\\x-y=90,\end{cases}$ то есть $\begin{cases}2x-3y=160,\\x-y=90.\end{cases}$ Отсюда $y=20$, $x=110$. Света заплатила $6\cdot110+5\cdot20=760$ (коп.).`,
+ ref: 'Арефьева «Алгебра, 7 кл.», гл. 4, § 25' },
+
+ { idx: 19, type: 'open', topic: 'equations', subtopic: 'eq-exponential', diff: 3,
+ text: R`Найдите произведение наибольшего целого отрицательного и наименьшего целого положительного решений неравенства $(0{,}2)^{\,2x^{2}-72}<1$.`,
+ answer: '-49',
+ sol: R`Так как $1=(0{,}2)^{0}$, а основание $0{,}2<1$ (функция убывает), неравенство равносильно $2x^{2}-72>0$, то есть $x^{2}>36$, откуда $x<-6$ или $x>6$. Наибольшее целое отрицательное решение $-7$, наименьшее целое положительное $7$; их произведение $-49$.`,
+ ref: 'Арефьева «Алгебра, 11 кл.», гл. 2, § 6' },
+
+ { idx: 20, type: 'open', topic: 'planimetry', subtopic: 'plan-quadrilaterals', diff: 3,
+ text: R`Длина одной из сторон параллелограмма на $5$ больше длины другой стороны, а высоты, проведённые к этим сторонам, равны $8$ и $12$. Найдите площадь параллелограмма.`,
+ answer: '120',
+ sol: R`Пусть меньшая сторона равна $x$, тогда большая $x+5$. К большей стороне проведена меньшая высота $8$, к меньшей — большая $12$. Площадь $S=ah$ одна и та же: $(x+5)\cdot8=x\cdot12$, $8x+40=12x$, $x=10$. Тогда $S=x\cdot12=120$.`,
+ ref: 'Казаков «Геометрия, 8 кл.», гл. 2, § 14' },
+
+ { idx: 21, type: 'open', topic: 'functions', subtopic: 'fn-derivative', diff: 2,
+ text: R`Найдите $f'(-1)$ для функции $f(x)=\dfrac{x^{3}}{3}-1{,}5x^{2}+13x-2022$.`,
+ answer: '17',
+ sol: R`$f'(x)=\dfrac13\cdot3x^{2}-1{,}5\cdot2x+13=x^{2}-3x+13$. Тогда $f'(-1)=(-1)^{2}-3\cdot(-1)+13=1+3+13=17$.`,
+ ref: 'Арефьева «Алгебра, 10 кл.», гл. 3, § 19' },
+
+ { idx: 22, type: 'open', topic: 'equations', subtopic: 'eq-rational', diff: 3,
+ text: R`Найдите наименьшее целое решение неравенства $\dfrac{x-3}{(x+14)(x-6)}\ge0$.`,
+ answer: '-13',
+ sol: R`Нуль числителя $x=3$; при $x=-14$ и $x=6$ значения не существуют. Методом интервалов решение неравенства — множество $(-14;3]\cup(6;+\infty)$. Наименьшее целое решение равно $-13$.`,
+ ref: 'Арефьева «Алгебра, 9 кл.», гл. 3, § 13' },
+
+ { idx: 23, type: 'open', topic: 'stereometry', subtopic: 'ster-angles-distances', diff: 4,
+ text: R`Дана правильная четырёхугольная пирамида $SABCD$, у которой диагональ основания $AC=2\sqrt{10}$, а угол между боковым ребром и плоскостью основания $\angle SCO=60^\circ$ ($O$ — центр основания). Найдите значение выражения $S^{2}$, где $S$ — площадь боковой поверхности пирамиды.`,
+ answer: '2800',
+ sol: R`В основании квадрат $ABCD$ с диагональю $2\sqrt{10}$, значит сторона $AD=2\sqrt5$. Высота $SO=OC\cdot\operatorname{tg}60^\circ=\dfrac{AC}{2}\cdot\sqrt3=\sqrt{10}\cdot\sqrt3=\sqrt{30}$. Апофема $SK=\sqrt{SO^{2}+\left(\dfrac{AD}{2}\right)^{2}}=\sqrt{30+5}=\sqrt{35}$. Площадь боковой поверхности $S=\dfrac12\cdot P\cdot SK$, где $P=4\cdot AD$ — периметр основания: $S=2\cdot AD\cdot SK=2\cdot2\sqrt5\cdot\sqrt{35}=20\sqrt7$. Тогда $S^{2}=400\cdot7=2800$.`,
+ ref: 'Латотин «Геометрия, 11 кл.», разд. 2, § 3' },
+
+ { idx: 24, type: 'open', topic: 'equations', subtopic: 'eq-linear', diff: 3,
+ text: R`Найдите сумму всех целых решений совокупности неравенств $\left[\begin{array}{l}x+6\le0,\\-2-x\ge0,\end{array}\right.$ принадлежащих промежутку $[-7;3]$.`,
+ answer: '-27',
+ sol: R`$x+6\le0\Rightarrow x\le-6$; $\ -2-x\ge0\Rightarrow x\le-2$. Объединение лучей — множество $(-\infty;-2]$. Пересечение с $[-7;3]$ — отрезок $[-7;-2]$. Целые решения $-7,-6,-5,-4,-3,-2$; их сумма равна $-27$.`,
+ ref: 'Арефьева «Алгебра, 8 кл.», гл. 1, § 6' },
+
+ { idx: 25, type: 'open', topic: 'equations', subtopic: 'eq-rational', diff: 3,
+ text: R`Найдите сумму квадратов корней уравнения $\dfrac{x^{2}+7\sqrt3\,x-15}{(x-7)^{2}}=0$.`,
+ answer: '177',
+ sol: R`Дробь равна нулю, когда числитель равен нулю, а знаменатель отличен от нуля: $x^{2}+7\sqrt3\,x-15=0$ при $x\ne7$. По теореме Виета $x_1+x_2=-7\sqrt3$, $x_1x_2=-15$. Тогда $x_1^{2}+x_2^{2}=(x_1+x_2)^{2}-2x_1x_2=\left(7\sqrt3\right)^{2}+30=147+30=177$.`,
+ ref: 'Арефьева «Алгебра, 8 кл.», гл. 2, § 9' },
+
+ { idx: 26, type: 'open', topic: 'trigonometry', subtopic: 'trig-equations', diff: 3,
+ text: R`Найдите (в градусах) корень уравнения $\operatorname{tg}5x=1$ на промежутке $(0^\circ;45^\circ)$.`,
+ answer: '9',
+ sol: R`$\operatorname{tg}5x=1\Rightarrow 5x=45^\circ+180^\circ n$, откуда $x=9^\circ+36^\circ n$. Промежутку $(0^\circ;45^\circ)$ принадлежит только корень $9^\circ$ (при $n=0$).`,
+ ref: 'Арефьева «Алгебра, 10 кл.», гл. 1, § 8' },
+
+ { idx: 27, type: 'open', topic: 'equations', subtopic: 'eq-irrational', diff: 3,
+ text: R`Решите уравнение $\sqrt{x-1}+3\sqrt[4]{x-1}-18=0$. В ответ запишите его корень (произведение корней, если их несколько).`,
+ answer: '82',
+ sol: R`Пусть $t=\sqrt[4]{x-1}\ge0$, тогда $t^{2}=\sqrt{x-1}$ и уравнение примет вид $t^{2}+3t-18=0$, $t=3$ (корень $t=-6$ отброшен). Из $\sqrt[4]{x-1}=3$ получаем $x-1=81$, $x=82$.`,
+ ref: 'Арефьева «Алгебра, 10 кл.», гл. 2, § 17' },
+
+ { idx: 28, type: 'open', topic: 'planimetry', subtopic: 'plan-circle', diff: 4,
+ text: R`Вписанный в окружность угол $KMN$, косинус которого равен $\dfrac34$, опирается на дугу $KN$. Радиус окружности равен $4$. Найдите значение выражения $S^{2}$, где $S$ — площадь треугольника $KON$ ($O$ — центр окружности).`,
+ answer: '63',
+ sol: R`Пусть $\angle KMN=\alpha$. Центральный угол $\angle KON=2\alpha$. Из $\cos\alpha=\dfrac34$ находим $\sin\alpha=\sqrt{1-\dfrac{9}{16}}=\dfrac{\sqrt7}{4}$, тогда $\sin2\alpha=2\sin\alpha\cos\alpha=2\cdot\dfrac{\sqrt7}{4}\cdot\dfrac34=\dfrac{3\sqrt7}{8}$. Площадь $S=\dfrac12\cdot OK\cdot ON\cdot\sin\angle KON=\dfrac12\cdot4^{2}\cdot\dfrac{3\sqrt7}{8}=3\sqrt7$. Тогда $S^{2}=9\cdot7=63$.`,
+ ref: 'Казаков «Геометрия, 9 кл.», гл. 1, § 5; Арефьева «Алгебра, 10 кл.», гл. 1, § 11' },
+
+ { idx: 29, type: 'open', topic: 'word-sequences', subtopic: 'word-problems', diff: 4,
+ text: R`Катер в $10$ ч $30$ мин отправился по течению реки от пристани $A$ к пристани $B$. Пробыв $3$ ч у пристани $B$, катер отправился назад и прибыл к пристани $A$ не позднее $17$ ч $15$ мин того же дня. Найдите наименьшее возможное целое значение собственной скорости (в км/ч) катера, если скорость течения реки равна $3$ км/ч, а расстояние между пристанями равно $36$ км. (Собственная скорость катера не изменялась.)`,
+ answer: '20',
+ sol: R`Пусть собственная скорость $x$ км/ч. Время в пути и стоянка не превышают $17\dfrac14-10\dfrac12=6\dfrac34$ ч. Тогда $\dfrac{36}{x+3}+3+\dfrac{36}{x-3}\le\dfrac{27}{4}$, откуда $\dfrac{36}{x+3}+\dfrac{36}{x-3}\le\dfrac{15}{4}$. При $x>3$ это приводит к $5x^{2}-96x-45\ge0$, решение $x\ge\dfrac{48+3\sqrt{281}}{5}\approx19{,}7$. Наименьшее целое значение $x=20$.`,
+ ref: 'Арефьева «Алгебра, 9 кл.», гл. 3, § 10; § 13' },
+
+ { idx: 30, type: 'open', topic: 'stereometry', subtopic: 'ster-angles-distances', diff: 5,
+ text: R`$ABCA_1B_1C_1$ — правильная треугольная призма, у которой $CC_1=1$. Радиус окружности, описанной около основания $ABC$, равен $\sqrt2$. На ребре $BC$ взята точка $N$ так, что $BN:NC=1:3$. Найдите значение выражения $\dfrac{32}{\cos^{2}\varphi}$, где $\varphi$ — угол между прямыми $A_1N$ и $CC_1$.`,
+ answer: '188',
+ sol: R`Сторона основания $a$: из $R=\dfrac{a\sqrt3}{3}=\sqrt2$ получаем $a=\sqrt6$. Тогда $BN=\dfrac{\sqrt6}{4}$. Так как $CC_1\parallel AA_1$, угол между $A_1N$ и $CC_1$ равен $\angle NA_1A=\varphi$. По теореме косинусов в треугольнике $ABN$: $AN^{2}=BN^{2}+AB^{2}-2\cdot BN\cdot AB\cos60^\circ=\dfrac{6}{16}+6-\dfrac{6}{4}=\dfrac{78}{16}$. В прямоугольном треугольнике $A_1AN$: $A_1N^{2}=AA_1^{2}+AN^{2}=1+\dfrac{78}{16}=\dfrac{94}{16}$, $A_1N=\dfrac{\sqrt{94}}{4}$. Тогда $\cos\varphi=\dfrac{AA_1}{A_1N}=\dfrac{4}{\sqrt{94}}$, $\cos^{2}\varphi=\dfrac{16}{94}=\dfrac{8}{47}$, и $\dfrac{32}{\cos^{2}\varphi}=32\cdot\dfrac{47}{8}=188$.`,
+ ref: 'Латотин «Геометрия, 10 кл.», разд. 2, § 4' },
+];
+
+/* ── Сборка solution_html ────────────────────────────────────────────────── */
+function ansShowOf(t) {
+ if (t.ansShow != null) return t.ansShow;
+ if (t.type === 'mc') return `${t.answer})`;
+ return `$${t.answer}$`;
+}
+function buildSolution(t) {
+ const ans = ansShowOf(t);
+ let html = `${t.sol}Ответ: ${ans}
`;
+ if (t.ref) html += `Учебник: ${t.ref}
`;
+ return html;
+}
+
+/* ── Самопроверка (повтор логики checkAnswerServer из exam-prep.js) ────────── */
+const EPS = 1e-6;
+function srvToNumber(s) {
+ if (s == null) return NaN;
+ let t = String(s).trim().replace(/\$/g, '').replace(/\s+/g, '').replace(',', '.');
+ const f = t.match(/^(-?\d+(?:\.\d+)?)\s*\/\s*(-?\d+(?:\.\d+)?)$/);
+ if (f) { const n = Number(f[1]), d = Number(f[2]); return d === 0 ? NaN : n / d; }
+ const n = Number(t); return Number.isFinite(n) ? n : NaN;
+}
+function checkAnswerServer(userInput, canonical) {
+ if (userInput == null || canonical == null) return false;
+ const c = String(canonical).trim();
+ if (/^[а-д]$/.test(c)) return String(userInput).trim().toLowerCase() === c.toLowerCase();
+ if (/^[^;]+;[^;]+$/.test(c)) return false;
+ const cn = srvToNumber(c), un = srvToNumber(userInput);
+ if (Number.isNaN(cn) || Number.isNaN(un)) return false;
+ return Math.abs(cn - un) < EPS;
+}
+
+/* ── Валидация набора ──────────────────────────────────────────────────────── */
+const problems = [];
+if (TASKS.length !== 30) problems.push(`Ожидалось 30 заданий, получено ${TASKS.length}`);
+const seen = new Set();
+for (const t of TASKS) {
+ if (seen.has(t.idx)) problems.push(`Дубль task_idx=${t.idx}`); seen.add(t.idx);
+ if (t.idx < 1 || t.idx > 30) problems.push(`task_idx вне 1..30: ${t.idx}`);
+ if (!['mc', 'open', 'long'].includes(t.type)) problems.push(`#${t.idx}: тип ${t.type}`);
+ if (t.type === 'mc') {
+ if (!Array.isArray(t.opts) || t.opts.length !== 5) problems.push(`#${t.idx}: mc должен иметь 5 вариантов`);
+ if (!t.opts.some(o => o[0] === t.answer)) problems.push(`#${t.idx}: answer "${t.answer}" не среди меток`);
+ }
+ if (!t.text || !t.sol) problems.push(`#${t.idx}: пустой text/sol`);
+ if (t.type !== 'long' && !checkAnswerServer(t.answer, t.answer))
+ problems.push(`#${t.idx}: answer "${t.answer}" не проходит self-check (Unicode-минус? пробел?)`);
+ if (/−/.test(String(t.answer))) problems.push(`#${t.idx}: Unicode-минус в answer`);
+}
+
+/* ── Экспорт для тестов/тиража (без запуска main при require) ──────────────── */
+module.exports = { TASKS, buildSolution, ansShowOf, checkAnswerServer, EXAM, VARIANT, PROV };
+if (require.main !== module) return;
+
+/* ── Открытие БД ───────────────────────────────────────────────────────────── */
+const DB = path.join(__dirname, '..', 'data', 'learnspace.db');
+const db = new DatabaseSync(DB);
+
+const track = db.prepare(`SELECT exam_key, variants_count FROM exam_tracks WHERE exam_key=?`).get(EXAM);
+if (!track) { console.error(`✗ Трек '${EXAM}' не найден в exam_tracks. Прерывание.`); process.exit(1); }
+
+/* ── DRY-RUN сводка ────────────────────────────────────────────────────────── */
+console.log(`\n=== seed_ctmath_rt2223_e1v1 (${PROV}) variant=${VARIANT} ===`);
+console.log(`Режим: ${APPLY ? 'APPLY (запись)' : 'DRY-RUN (только проверка)'}\n`);
+
+const byType = TASKS.reduce((a, t) => (a[t.type] = (a[t.type] || 0) + 1, a), {});
+console.log('Типы:', JSON.stringify(byType), ' | с фигурой:', TASKS.filter(t => t.fig).length, '\n');
+
+console.log('idx | type | subtopic | d | answer');
+console.log('----+------+-----------------------+---+----------');
+for (const t of TASKS) {
+ console.log(`${String(t.idx).padStart(3)} | ${t.type.padEnd(4)} | ${String(t.subtopic).padEnd(21)} | ${t.diff} | ${String(t.answer)}`);
+}
+
+if (problems.length) {
+ console.error(`\n✗ ПРОБЛЕМЫ (${problems.length}):`);
+ problems.forEach(p => console.error(' - ' + p));
+ console.error('\nЗапись отменена из-за ошибок валидации.');
+ db.close();
+ process.exit(1);
+}
+console.log('\n✓ Валидация и self-check ответов пройдены (30/30).');
+
+/* ── APPLY: upsert ─────────────────────────────────────────────────────────── */
+if (!APPLY) {
+ console.log('\nDRY-RUN: ничего не записано. Для записи: node backend/scripts/seed_ctmath_rt2223_e1v1.js --apply\n');
+ db.close();
+ process.exit(0);
+}
+
+const upsert = db.prepare(`
+ INSERT INTO exam_tasks
+ (exam_key, variant, task_idx, task_type, text_html, figure_html,
+ opts_json, answer, solution_html, topic, subtopic, difficulty)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ ON CONFLICT(exam_key, variant, task_idx) DO UPDATE SET
+ task_type = excluded.task_type,
+ text_html = excluded.text_html,
+ figure_html = excluded.figure_html,
+ opts_json = excluded.opts_json,
+ answer = excluded.answer,
+ solution_html = excluded.solution_html,
+ topic = excluded.topic,
+ subtopic = excluded.subtopic,
+ difficulty = excluded.difficulty
+`);
+
+let n = 0;
+db.exec('BEGIN');
+try {
+ for (const t of TASKS) {
+ upsert.run(
+ EXAM, VARIANT, t.idx, t.type,
+ t.text,
+ t.fig || null,
+ t.type === 'mc' ? JSON.stringify(t.opts) : null,
+ t.answer,
+ buildSolution(t),
+ t.topic, t.subtopic, t.diff
+ );
+ n++;
+ }
+ const distinct = db.prepare(`SELECT COUNT(DISTINCT variant) c FROM exam_tasks WHERE exam_key=? AND variant BETWEEN 101 AND 1999`).get(EXAM).c;
+ db.prepare(`UPDATE exam_tracks SET variants_count=? WHERE exam_key=?`).run(distinct, EXAM);
+ db.exec('COMMIT');
+ console.log(`\n✓ Записано/обновлено ${n} заданий (variant=${VARIANT}).`);
+ console.log(`✓ exam_tracks.variants_count = ${distinct} (различных вариантов).`);
+ console.log(`\nПробник доступен: /exam-prep/ctmath → «Варианты» → «РТ-2022/23 · этап I».\n`);
+} catch (e) {
+ db.exec('ROLLBACK');
+ console.error('\n✗ Ошибка записи, откат транзакции:', e.message);
+ process.exitCode = 1;
+}
+db.close();
diff --git a/backend/src/routes/exam-prep.js b/backend/src/routes/exam-prep.js
index 2551805..45a7b38 100644
--- a/backend/src/routes/exam-prep.js
+++ b/backend/src/routes/exam-prep.js
@@ -41,6 +41,9 @@ const VARIANT_LABEL = {
104: 'РТ-2023/24 · этап I',
105: 'РТ-2023/24 · этап II',
106: 'РТ-2023/24 · этап III',
+ 107: 'РТ-2022/23 · этап I',
+ 108: 'РТ-2022/23 · этап II',
+ 109: 'РТ-2022/23 · этап III',
},
};
const examVariantLabel = (examKey, v) => VARIANT_LABEL[examKey]?.[v] || `Вариант ${v}`;