Companion — MATx (Tom Kabel)
matx-hack учит моделированию — как из словесной задачи получить уравнение. MATx (github.com/tomkabel/MATx) учит решать это уравнение технически. Это два соседних звена одной цепочки, и они стыкуются естественно.
текст ──▶ модель (matx-hack) ──▶ уравнение ──▶ решение (MATx)Полная карта переходов между микронавыками — на странице Мост в MATx.
Кто за MATx
Заголовок раздела «Кто за MATx»Tom Kabel — автор и разработчик. Проект эстонский, для основной школы (7–9 класс). Стек: TypeScript + React (frontend) + Express (API) + Postgres + Drizzle ORM. Хостится на собственной инфраструктуре по адресу matxdev.duckdns.org.
Статус коллаборации. На момент написания репозиторий публичный, но без LICENSE-файла. Использование скриншотов и описаний в этом учебнике согласовано с автором в Slack. Любая техническая интеграция (см. ниже Phase 3) требует отдельного PR с явным согласием.
Что внутри MATx
Заголовок раздела «Что внутри MATx»Три топика с девятью competencies (термин Tom’а) — это его эквивалент наших микронавыков:
Реальные slugs в БД сняты через GET /api/topics —
matxdev.duckdns.org/api/topics
(публичный endpoint, без аутентификации).
1. abivalemid — Korrutamise abivalemid
Заголовок раздела «1. abivalemid — Korrutamise abivalemid»Õpi ja harjuta kolme abivalemit: summa ruut, vahe ruut ja ruutude vahe.
| Competency (id, name) | Формула |
|---|---|
| 1 — Summa ruut | |
| 2 — Vahe ruut | |
| 3 — Ruutude vahe |
2. protsendid — Protsentarvutus
Заголовок раздела «2. protsendid — Protsentarvutus»Lahenda protsentülesandeid ristkorrutise meetodil.
| Competency (id, name) | Что делает |
|---|---|
| 4 — Osa leidmine | Leia osa, kui tervik ja protsent on teada |
| 5 — Terviku leidmine | Leia tervik, kui osa ja protsent on teada |
| 6 — Protsendi leidmine | Leia protsent, kui tervik ja osa on teada |
3. vorrandid — Ühe tundmatuga võrrandid
Заголовок раздела «3. vorrandid — Ühe tundmatuga võrrandid»Lahenda võrrandeid samm-sammult, kirjutades välja iga teisenduse.
| Competency (id, name) | Форма / описание |
|---|---|
| 7 — Lihtsad võrrandid | |
| 8 — Sulgudega võrrandid | Võrrandid, kus tuleb esmalt sulud avada |
| 9 — Murdudega võrrandid | Võrrandid, kus tuleb esmalt murrud kaotada |
Дополнительно: docs/06-math-topics.md
у Tom’а (теоретическое описание); формальная схема таблиц —
shared/schema.ts.
Почему вместе сильнее
Заголовок раздела «Почему вместе сильнее»| matx-hack (мы) | MATx (Tom) | |
|---|---|---|
| Домен | Моделирование | Вычисление |
| Микронавыки | 9 (defining T1–T3 × три типа отношений) | 9 (3 топика × 3 competency) |
| Что отвечает ученик | Записать выражения через | Численный/символьный ответ |
| Что отслеживает | BKT по 9 defining-skills | Per-question results + error categories |
| Стек | Astro + React + Next.js (web/) | React + Express + Postgres |
| Аудитория | Эстонская школа, 7 класс | Эстонская школа, 7–9 классы |
| Язык контента | ET / RU / EN | ET |
Когнитивно — наш ученик завершает фазу «понять задачу и записать уравнение», после чего естественно переходит к фазе «решить уравнение до числа». Без MATx эта вторая фаза в нашей книге остаётся словесной; без нас MATx предполагает, что уравнение уже как-то получено.
Где попробовать
Заголовок раздела «Где попробовать»Живой dev-инстанс: matxdev.duckdns.org. Публичных страниц нет — нужно зайти под учётной записью (учитель/ученик). Tom разворачивает demo-аккаунт по запросу.
Прямые ссылки на topic-страницы (после логина):
- matxdev.duckdns.org/topics/abivalemid — Korrutamise abivalemid
- matxdev.duckdns.org/topics/protsendid — Protsentarvutus
- matxdev.duckdns.org/topics/vorrandid — Ühe tundmatuga võrrandid
Публичный API без аутентификации:
/api/topics— список топиков (id, slug, title, description)/api/topics/:slug— топик с массивом competencies
Roadmap интеграции
Заголовок раздела «Roadmap интеграции»Phase 1 — book pages (готово в этом релизе)
Заголовок раздела «Phase 1 — book pages (готово в этом релизе)»- Skill-bridge mapping — карта 9→9 с обоснованием на трёх языках
-
data/matx-bridge.json— single source of truth для маппинга - Эта companion-страница
Phase 2 — cross-links и deep-links (готово)
Заголовок раздела «Phase 2 — cross-links и deep-links (готово)»- Inline-карточки «Companion: MATx» на ключевых страницах: главная, Multi-skill, Симулятор, Q&A
- Прямые deep-links на три topic’а через slug + публичный API
- iframe-embed решили не делать:
connect.sidидёт сSameSite=Lax, поэтому залогиненный flow в iframe не работает — без него embed бесполезен. Лучше открыть в новой вкладке.
Phase 3 — BKT-модель в submit-handler MATx (план PR-ов)
Заголовок раздела «Phase 3 — BKT-модель в submit-handler MATx (план PR-ов)»Идея. Вынести нашу BKT-математику в pure-TypeScript пакет bkt-core
(zero runtime deps), Tom добавляет его одной зависимостью и одним
вызовом в storage.createResult. Никаких сетевых hop’ов, никакой
ML-инфраструктуры. Мерджабельно в два самостоятельных PR’а.
Что портируется в bkt-core
Заголовок раздела «Что портируется в bkt-core»| Источник в matx-hack | Что | Объём |
|---|---|---|
web/lib/microskills.ts | Типы BktParams, MicroSkill, Task, StudentState + константа DEFAULT_BKT | ~25 строк, без deps |
web/lib/bkt.ts | bktUpdate, pSolve, ensureMastery, applyAttempt, scoreTaskForStudent, recommend | ~150 строк, импортит только типы |
package.json пакета содержит только name, main, types, tsc.
Никаких production-зависимостей — это голая математика.
PR 1 — bookkeeping (минимум, ~70 строк, не меняет UI)
Заголовок раздела «PR 1 — bookkeeping (минимум, ~70 строк, не меняет UI)»Каждый attempt обновляет закрытую формулу BKT для соответствующей competency. Видимое поведение MATx не меняется — только в БД появляется новое поле.
1. Drizzle migration — новая таблица:
CREATE TABLE student_skill_state ( user_id text NOT NULL REFERENCES users(id) ON DELETE CASCADE, competency_id integer NOT NULL REFERENCES competencies(id) ON DELETE CASCADE, p_known double precision NOT NULL DEFAULT 0.2, attempts integer NOT NULL DEFAULT 0, last_updated timestamp DEFAULT now(), PRIMARY KEY (user_id, competency_id));Зеро-downtime (новая таблица, ничего не блокирует). Применяется через
существующий npm run db:push.
2. shared/schema.ts — добавить определение таблицы (~15 строк):
export const studentSkillState = pgTable("student_skill_state", { userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }), competencyId: integer("competency_id").notNull().references(() => competencies.id, { onDelete: "cascade" }), pKnown: doublePrecision("p_known").notNull().default(0.2), attempts: integer("attempts").notNull().default(0), lastUpdated: timestamp("last_updated").defaultNow(),}, (t) => ({ pk: primaryKey({ columns: [t.userId, t.competencyId] }) }));3. server/storage.ts.createResult (текущий, строки 150–152) — добавить upsert после insert (~20 строк):
import { bktUpdate, DEFAULT_BKT } from "@matx-hack/bkt-core";import { studentSkillState } from "@shared/schema";
async createResult(result: CreateResultRequest) { const [savedResult] = await db.insert(results).values(result).returning();
// — BKT update — const q = await this.getQuestion(result.questionId); if (q?.competencyId) { const [cur] = await db.select().from(studentSkillState).where(and( eq(studentSkillState.userId, result.userId), eq(studentSkillState.competencyId, q.competencyId), )).limit(1); const prior = cur?.pKnown ?? DEFAULT_BKT.pInit; const posterior = bktUpdate(prior, result.isCorrect, DEFAULT_BKT); await db.insert(studentSkillState).values({ userId: result.userId, competencyId: q.competencyId, pKnown: posterior, attempts: 1, lastUpdated: new Date(), }).onConflictDoUpdate({ target: [studentSkillState.userId, studentSkillState.competencyId], set: { pKnown: posterior, attempts: sql`${studentSkillState.attempts} + 1`, lastUpdated: new Date() }, }); }
return savedResult;}server/routes.ts (submit-handler на строках 292–345) не трогается — обновление инкапсулировано в storage layer.
PR 2 — smarter recommendation (~80 строк, опц.)
Заголовок раздела «PR 2 — smarter recommendation (~80 строк, опц.)»Заменить эвристику в getNextRecommendedQuestion (текущая, строки 878–940) на BKT-driven выбор через ZPD-target .
Текущая логика — три бакета notStarted / needsWork (mastery < 60%) / progressing (60–90%) с выбором по mastery asc — сохраняется как mapping слой обратно в Tom-овские эстонские объяснения (Harjuta..., Kinnista..., Korda...), чтобы UI/UX не менялся. Под капотом — наш recommend(state, tasks):
import { recommend } from "@matx-hack/bkt-core";
async getNextRecommendedQuestion(userId, topicId) { const skillStates = await db.select().from(studentSkillState) .innerJoin(competencies, eq(studentSkillState.competencyId, competencies.id)) .where(eq(competencies.topicId, topicId)); const state = { student_id: userId, mastery: Object.fromEntries(skillStates.map(s => [String(s.competency_id), s.p_known])), history: [], }; const qs = await db.select().from(questions).where(eq(questions.topicId, topicId)); const tasks = qs.map(q => ({ id: String(q.id), topic: String(topicId), microskills: q.competencyId ? [String(q.competencyId)] : [], difficulty: 0.5, prompt_et: q.text, answer: "", })); const top = recommend(state, tasks, 1)[0]; // … map score+pSolve back to existing reason buckets for UX continuity}Что нужно от Tom
Заголовок раздела «Что нужно от Tom»- Согласие на PR в
tomkabel/MATx(можно как experimental branch / feature flag). - Возможность миграции БД — это
npm run db:push, zero-downtime. - (Опц.) Tom сам пишет PR, мы отдаём
bkt-coreкак git submodule илиnpm pack-tarball для локальной установки до публикации в npm.
Audit-trail для EU AI Act
Заголовок раздела «Audit-trail для EU AI Act»bktUpdate — закрытая аналитическая формула. В любой момент аудитор
может взять (prior, observation, params) из логов и независимо
переиграть posterior. Никакого “black-box” обоснования не требуется.
Опционально: добавить audit_trace JSONB в student_skill_state — там
накапливается история (timestamp, prior, isCorrect, posterior) тапл’ов.
Это закрывает Annex III требования traceability + explainability
без отдельной compliance-инфраструктуры.
EU AI Act compliance
Заголовок раздела «EU AI Act compliance»Education / vocational training — high-risk Annex III категория по Regulation (EU) 2024/1689. Нормы на traceability, documentation, human oversight и explainability вступают в силу поэтапно с августа 2026 по август 2027.
Наша часть конвейера уже сейчас полностью детерминистична — нет ни одного LLM-вызова в production-пути:
- BKT-обновление — закрытое аналитическое выражение по Байесу.
- Объяснения — шаблонный движок (
web/lib/explain.ts) с фиксированным набором фраз. - Селектор — argmax по уверенности модели + правила topology (skill-graph).
После Phase 3 MATx наследует тот же профиль автоматически: одна строка
bktUpdate(...) в submit-handler — и audit-trail про принятие решения
о next-question строится без отдельной compliance-инфраструктуры.
Дополнительно поверх можно подключить eatf.eu — model attestation, response signing, audit одним API-вызовом — для централизованного хранения artefact’ов.
Связанные страницы
Заголовок раздела «Связанные страницы»- Прогрессионная матрица — наша 9-микронавыковая модель defining-skills.
- Мост в MATx — таблица соответствий microskill ↔ MATx-competency и Mermaid-граф переходов.
- Симулятор селектора — как BKT выбирает следующий defining-микронавык; после Phase 3 будет ссылаться и на MATx-competencies.
- Глоссарий — термины (microskill, competency, BKT и т.д.).