Реестр (registry.js) пополнен правами, которыми раньше нельзя было управлять:
• Учитель: classroom.host (онлайн-уроки), livequiz.host (живые викторины),
simbuilder.use (конструктор симуляций), flashcards.manage (общие колоды).
• Ученик: homework.submit (сдача ДЗ), materials.save («Мои материалы»),
assistant.use (ИИ-ассистент), games.play (учебные игры),
flashcards.access / exam.access (доступ к разделам).
Все default=1 → текущее поведение сохранено; админ может выключить по роли/классу/юзеру.
Энфорс на роутах: учительские — requirePermission (роуты уже teacher-only);
ученические на ОБЩИХ роутах (assistant/materials/games/flashcards/exam-prep) —
новый requirePermissionForStudents(key) (учитель/админ проходят всегда, проверка
только ученику — иначе isEnabled=false сломал бы учителя). PERM_DEFAULTS строится
из реестра → фолбэк до сидирования = enabled, никто не блокируется. Группы UI —
существующие (новых ярлыков нет). seedDefaults авто-сидит новые ключи на чтении.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Перенабор Вариант 1 из ЦТ 2011 В1-В10.pdf (тест полный, не только В), все 30
ответов сверены с официальной таблицей (полное совпадение). Уточнения по таблице:
A6 степень 3x+4 (→15·2^3x), A9=(3^-2)^-5→1/9, A7 корень -3, A8=10, A10=10π.
Фигурные A1/A2/B6 реконструированы (B6: y=x²-6x+9 ∩ y=1,25 → 4x₁x₂=31). Все В
числовые. Без авторских ссылок. Дедуп-гейт 0, KaTeX 30/30, DRY-RUN 30/30. Метка 121='ЦТ-2011'.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Перенабор Вариант 1 из ЦТ 2012.pdf, все 30 ответов сверены с официальной
таблицей (полное совпадение). Фигурные A1/A13/B6 реконструированы с явными
данными (A1 — углы 70/40→равнобедренный; B6 — середины сторон→S=4). A15
уточнена по таблице: √(5⁵·20)=250, знаменатель ⁴√10 → 25·⁴√10. Все В числовые.
Без авторских ссылок. Дедуп-гейт 0, KaTeX 30/30, DRY-RUN 30/30. Метка 120='ЦТ-2012'.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Перенабор Вариант 1 из ЦТ2013.pdf, все 30 ответов сверены с официальной
таблицей (полное совпадение). Фигурные A2/A3/A6/A16 реконструированы с явными
описаниями (A2 — образующая=AD, A6 — порядок лучей→40°, A16 — сечение 12×6=72).
Все В-задания числовые (long нет). Без авторских ссылок. Дедуп-гейт 0,
KaTeX 30/30, DRY-RUN 30/30. VARIANT_LABEL: 119='ЦТ-2013'.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Перенабор Вариант 1 из CT-2017.pdf, все 30 ответов сверены с официальной
таблицей (полное совпадение). Фигурные A1/A3/A9/A11/A14 реконструированы с
явными числами (A9 — биссектриса, AM/MC=AB/BC→13,8). Без авторских ссылок.
Прогнан через дедуп-гейт (0 совпадений с пулом) + KaTeX-структуру + DRY-RUN 30/30.
VARIANT_LABEL: 118='ЦТ-2017'.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Тренажёр-по-темам и практика брали FROM exam_tasks без фильтра по варианту — в пул
попадали год-пачки (variant=год≥2011) и variant=0, которые ДУБЛИРУЮТ выверенные
варианты-пробники (51 дубль чистый↔пачка, 20 через variant=0). Ученик мог получить
одну задачу дважды.
Добавлен фильтр variant BETWEEN MV_LO..MV_HI (тот же [101;1999], что у пикера) во все
7 запросов выборки/счёта задач: practiceRandom, practiceUnsolved, topicTasksUnsolved,
topicTasksAny, listTopicsWithCounts (счётчик подтем), weakBatchTasks, pickRandomByDifficulty
(×2). Хелперы MV_LO/MV_HI (для math9 без диапазона — всё, кроме variant=0).
Результат: практика ctmath = только варианты 101–117 (496 задач, 0 дублей между собой),
год-пачки (714 задач) остаются в БД для возможного будущего, но не показываются.
Обратимо, без удаления данных. Рантайм-проверка: 5 эндпоинтов практики/тем → 200.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Пробник ЦТ по математике 2021, Вариант 1. Формат: 32 задания (А1–А18 + В1–В14), А12/А16 —
с несколькими верными (тип open, ответ цифрами), В2/В3 множ.выбор, В1 на соответствие.
Источник: чистый PDF ЦТ 2021.pdf. ВСЕ 32 ответа решены и сверены с официальной таблицей
(стр.45, столбец Вариант 1) — полное совпадение, включая B9=324, B11=960, B13=460 (пары чисел),
B14=1375 (описанный четырёхугольник, r=60/7). Фигурные A7/A17/B1/B4 реконструированы; B5: в скане
∛(-7) → на деле ∛(-343)=-7 (иначе нецелый), ответ -98. Без авторских ссылок.
VARIANT_LABEL 117 -> 'ЦТ-2021'. DRY-RUN 32/32, self-check и структурный KaTeX — зелёные.
Запись в БД — пользователь: node backend/scripts/seed_ctmath_ct2021_v1.js --apply
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Пробник ЦТ по математике 2020, Вариант 1. ⚠️ Новый формат: 32 задания (А1–А20 + В1–В12),
В1 на соответствие, В2 множ.выбор. Машинерия параметризована N_TASKS=32. Источник: чистый
PDF ЦТ 2020.pdf. ВСЕ 32 ответа решены и сверены с официальной таблицей (стр.44, столбец
Вариант 1) — полное совпадение, включая A20=37√13/3, B5=-335, B8=-320, B9=160, B10=577,
B11=-16, B12=336 (сфера через 4 точки куба). Фигурные A9/A11 реконструированы; без авторских
ссылок (политика «все учебники наши»). VARIANT_LABEL 116 -> 'ЦТ-2020'.
DRY-RUN 32/32, self-check и структурный KaTeX — зелёные.
Запись в БД — пользователь: node backend/scripts/seed_ctmath_ct2020_v1.js --apply
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Пробник ЦТ по математике 2019, Вариант 1 (А1–А18 + В1–В12; В1 на соответствие, В2 множ.выбор)
для трека exam-prep ctmath. Источник: чистый PDF ЦТ 2019.pdf. Все 30 решены и сверены: столбец
Вариант 1 в таблице (стр.45) затемнён, но читаемые ячейки совпали; методы B5/B6/B7/B11/B12
перекрёстно подтверждены на Варианте 10 (его задания на стр.43-44, ответы читаемы → 81/56/-1071/
624/540 ровно по таблице). Тяжёлые: B7=-264 (период+нечётность), B11=288, B12=110 (т.Гульдина).
Фигурные A1/A7/A9 разрешены по столбцу 1 (D/2√34/2,4); B1/B2 — данные текстом.
VARIANT_LABEL 115 -> 'ЦТ-2019'. DRY-RUN 30/30, self-check и структурный KaTeX — зелёные.
Запись в БД — пользователь: node backend/scripts/seed_ctmath_ct2019_v1.js --apply
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Пробник ЦТ по математике 2018, Вариант 1 (А1–А18 + В1–В12, В1 на соответствие) для трека
exam-prep ctmath. Источник: чистый PDF ЦТ 2018.pdf. ВСЕ 30 ответов решены и сверены с
официальной таблицей (стр.32, столбец Вариант 1) — полное совпадение, включая B8=-18,
B9=-130 (двугранный угол), B11=32, B12=45 (координатный метод, PT=5/2).
Фигурные/несогласованные (А3 точки, А9 графики→пути, А11 квадраты, В1/В2 функция по узлам,
В8 экв. показательное, В10 множитель (6-x)² по ответу) реконструированы/адаптированы.
VARIANT_LABEL 114 -> 'ЦТ-2018'. DRY-RUN 30/30, self-check и структурный KaTeX — зелёные.
Запись в БД — пользователь: node backend/scripts/seed_ctmath_ct2018_v1.js --apply
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Пробник ЦТ по математике 2016, Вариант 1 (А1–А18 + В1–В12) для трека exam-prep ctmath.
Источник: чистый PDF ЦТ 2016.pdf. ВСЕ 30 ответов решены и сверены с официальной таблицей
(стр.35, столбец Вариант 1) — полное совпадение, включая B5=-22, B9=712, B11=56, B12=724.
Фигурные задания (А2 угол через MN||BC, А3 числа на прямой, А6 таблица, А7 площадь по
координатам, А8 область значений, А11 круговая диаграмма) реконструированы/адаптированы
в самодостаточные авто-проверяемые формы. VARIANT_LABEL 113 -> 'ЦТ-2016'.
DRY-RUN 30/30, self-check и структурный KaTeX — зелёные.
Запись в БД — пользователь: node backend/scripts/seed_ctmath_ct2016_v1.js --apply
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Актуальный формат экзамена: А1–А10 (8 mc + 2 open) + В1–В20 (1 long + 19 open).
Перенабор по PDF сборника РИКЗ; решений в источнике нет — решено вручную,
ВСЕ 30 ответов сверены с официальным ключом (стр.35, столбец Вариант 1).
Адаптации: А1 (точки на прямой) → равные промежутки в тексте; А6 (промежуток
на рисунке) → описан словами. Метка 111 (ЦЭ-2024) в VARIANT_LABEL.
Идемпотентный seed, --apply — пользователь.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Первый из ЦТ-годовых. Формат ЦТ: А1–А18 (18 mc) + В1–В12 (12 open) = 30.
Перенабор по PDF; решений в источнике НЕТ — решено вручную, ответы
сверены с официальным ключом (стр.34 сборника). Адаптации картинок:
А2 (симметричные фигуры, неразборчивы) → MC о симметрии точки; А6
(параллелограмм на сетке) → координаты вершин; А10/А15 — текстом.
Метка 110 (ЦТ-2014) в VARIANT_LABEL. Идемпотентный seed, --apply — пользователь.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
30 заданий (А1–А10 + В1–В20), перенабрано вручную в KaTeX по PDF РИКЗ
(РТ-1 23/24 В1). Геометрия закодирована текстом — чертежи не нужны.
Идемпотентный upsert, DRY-RUN по умолчанию, запись с --apply.
Верификация: node --check, валидация 30/30, KaTeX-рендер 413/413 сегментов.
+ метки вариантов 104–106 (РТ-2023/24 этап I/II/III) в routes/exam-prep.js.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Вместо «Вариант 101/102/103» (технические номера) показываем источник:
«РТ-2024/25 · этап I/II/III». examVariantLabel() в exam-prep.js — единый
источник подписи: listVariants (пикер/dropdown) + variant_label в ответе
mock/:id (строка прохождения и результата). Номера в БД остаются 101+
(нужны для фильтра-диапазона [101;1999] и провенанса). math9 — fallback
«Вариант N» (не затронут). Новые варианты (104+) — дописывать в VARIANT_LABEL.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- exam-prep.js: MOCK_VARIANT_RANGE — для ctmath показываем как пробники
только чистые 30-задачные варианты [101;1999]; год-пачки (variant=год
2011-2024 и 0, до 114 задач) остаются пулом для тренажёра по темам,
но скрыты из пикера/mock-start/просмотра вариантов. math9 (1..80) не затронут
(диапазон только для ctmath).
- mock.js: пикер «По варианту» — выпадающий список реальных вариантов
(через listVariants) вместо number-input 1..N; раньше для ctmath он
предлагал 1..18 и не доходил до 101 → пробник по варианту не запускался.
- cleanup_ctmath_bank.js: идемпотентный скрипт — ретайр битого id=1419
(mc с противоречивым ответом → long), variants_count → 3 (чистых вариантов).
- seed_*: variants_count считается по диапазону [101;1999] (консистентно с роутом).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Не было UI для управления exam_tracks.enabled (только флаг в БД, ставился
миграцией). Добавлена админ-секция «Экзамен-модули»:
- backend exam-prep.js: GET /admin/tracks (все треки, вкл. выключенные, + число
заданий) и PATCH /admin/track (exam_key, enabled), обе requireRole('admin').
Пути без :examKey, чтобы не задеть гейт content_access.
- frontend: секция sections/exams.js (список треков + переключатель enabled),
вкладка в admin.html (admin-only через ADMIN_ONLY_TABS, locked для не-админов),
регистрация в admin.js (ROUTE_TO_SECTION).
Выключенный трек скрыт у учеников и пропадает из каталога прав доступа (тот
берёт exam_tracks WHERE enabled=1). Доступ ученикам по-прежнему в «Доступ · контент».
Требует перезапуска бэкенда + Ctrl+F5.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1) exam-prep practice (strategy=random) возвращал около 0.6 от count: функция
distributeByDifficulty раскладывает count по 5 уровням сложности, а у трека
ctmath задания только уровней 1-3 (уровни 4-5 пустые) -> часть выборки терялась
(20 -> 12, 15 -> 10, 10 -> 6). В pickRandomByDifficulty добавлен добор до count
из доступных уровней. Трек math9 не затронут (там добор не требуется).
2) lesson.html: .lesson-nav-btn-title был inline-span, поэтому max-width и ellipsis
игнорировались и длинные заголовки вылезали за кнопку. Добавлен display:block.
Бэкенд-правка требует перезапуска сервера; фронт-правка видна после Ctrl+F5.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Coins were always 1:10 of XP. Now they have their own event log + a
helper that dedups by reason within a configurable window.
Backend:
• migration 032 creates coin_log (user_id, amount, reason, created_at)
with indices for the 'fired today?' check
• awardCoins now records into coin_log on every call (reason defaults
to 'xp_bonus' for the legacy XP-proportional path)
• awardCoinsOnce(userId, amount, reason, window) — fires the bonus
only if no row matches in the window:
'day' → DATE(created_at) = today
'week' → ISO week match
'forever' → never twice
Wired events (Phase 4 subset of the plan):
• Daily login — 10 coins, once/day. Hooked in updateStreak so the
bonus rides on the existing 'daily_activity' XP trigger.
• Daily goal completion — 15/25/40 coins (easy/medium/hard), once/day.
Sits next to the existing tier XP bonus in updateDailyGoal.
• Variant clear — 30 coins, once per (user, variant) forever. Fires
from the exam-prep attempts endpoint when the user's final correct
answer fills out a math9 variant.
Deferred (need invasive trigger hooks): weekly goal, paragraph close,
boss defeated, referral.
Verified end-to-end: awardCoinsOnce returns true→false on repeated
calls, coin_log records the first, coins balance moves once.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Recent-attempts widget on /exam-prep/:examKey was showing raw LaTeX
like '\dfrac{7}{9}' because stripPreview only removed HTML tags.
Now it also converts common LaTeX to readable unicode (fractions →
a/b, \sqrt → √, \cdot → ·, comparisons → ≤≥≠, Greek letters, etc.)
before truncating.
KaTeX rendering would be overkill for a 100-char preview row; this
just makes the existing text legible.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Practice (random) now picks tasks by ascending difficulty so the first
slot is always level 1 and the session ramps up. Adds ?exclude= to drop
specific subtopics from the random pool, with a per-section checkbox
modal in the UI.
Each task carries a topic_ref (textbook chapter + paragraph) shown as
a 'Учить тему · §N' button next to the solution, deep-linking to the
right section of /textbook/<slug>. Mapping seeded for all 15 math9
subtopics in migration 028.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>