feat(ct-math): уроки стереометрии (44-47) + скрипт мини-фикса 866/1248

- backend/scripts/seed_ctmath_lessons_stereo.js — 4 урока блока «Стереометрия»
  по PILOT_STEREOMETRY (расположение/сечения, многогранники, тела вращения,
  координатный метод В20) в курс 13; применён (lessons.id=44-47, 60 блоков).
- backend/scripts/fix_ctmath_misc.js — точечный фикс exam_tasks id=866
  (варианты-прямые в норму) и id=1248 (битый источник → long); dry/--apply,
  идемпотентен. Запись блокируется авто-режимом — запускает пользователь.
- README: статус (уроки стерео, сайдбар, остаток).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-15 11:36:56 +03:00
parent 1bc0cc247a
commit 623fbde38b
3 changed files with 179 additions and 6 deletions
+45
View File
@@ -0,0 +1,45 @@
'use strict';
/*
* Точечная полировка 2 mc-задач ctmath:
* - id=866: варианты-прямые вшиты в середину текста, opts = цифры-указатели →
* нормальный opts_json + чистый текст (answer сохраняем = 4).
* - id=1248: битый источник (нет верного варианта, опции не сходятся) → 'long'.
* Идемпотентно (проверяет текущее состояние). dry по умолчанию, запись --apply.
*/
const db = require('../src/db/db');
const APPLY = process.argv.includes('--apply');
const t866 = db.prepare('SELECT id,task_type,answer,opts_json FROM exam_tasks WHERE id=866').get();
const t1248 = db.prepare('SELECT id,task_type FROM exam_tasks WHERE id=1248').get();
const plan = [];
if (t866 && t866.task_type === 'mc') {
// opts уже нормальные? (значения не цифры-указатели)
let o = []; try { o = JSON.parse(t866.opts_json); } catch {}
const isDigit = o.length && o.every(p => /^[1-9]$/.test(String(p[1]).trim()));
if (isDigit) {
plan.push({
id: 866,
set: {
text_html: 'A16. Какая из прямых пересекает график функции $y=x^4-3x^2+11x$ в 11 добавочных точках?',
opts_json: JSON.stringify([['1', '$y=-3$'], ['2', '$y=-1{,}5$'], ['3', '$y=0$'], ['4', '$y=4k$'], ['5', '$y=2$']]),
answer: '4',
},
});
} else console.log('id=866 уже не цифровой — пропуск');
} else console.log('id=866 нет или уже не mc — пропуск');
if (t1248 && t1248.task_type === 'mc') {
plan.push({ id: 1248, set: { task_type: 'long', answer: null } });
} else console.log('id=1248 нет или уже не mc — пропуск');
console.log(APPLY ? '[APPLY]' : '[DRY-RUN]', 'к изменению:', plan.map(p => p.id).join(', ') || '(нет)');
for (const p of plan) console.log(' id', p.id, '→', JSON.stringify(p.set).slice(0, 160));
if (!APPLY) { console.log('DRY-RUN: запись НЕ выполнялась. Запись: --apply'); process.exit(0); }
for (const p of plan) {
const cols = Object.keys(p.set);
const sql = `UPDATE exam_tasks SET ${cols.map(c => c + '=@' + c).join(', ')} WHERE id=@id`;
db.prepare(sql).run({ ...p.set, id: p.id });
}
console.log('Обновлено:', plan.length);