Формат пака
Пак — контракт между генератором и раннером. Оба зависят только от packcore, поэтому формат меняется в одном месте, а не в двух приложениях.
packs/<практика>/
domain.json
tasks.json
materializations/<task_id>.json
migrations/
common/ создание схемы
tasks/<id>/ INSERT-ы вариантов данных
report/index.md
theme/
state.json
mock_llm/ заготовленные ответы модели для --mock
domain.json
| Поле | Что содержит |
|---|---|
description | описание базы для студента |
ddl | SQL создания схемы |
objectives | темы курса: id, title, count: [min, max], required |
total | сколько всего заданий: [min, max] |
notes | пожелания автора к данным и покрытию, уходят в промт |
table_docs | пояснения к таблицам и колонкам для студента |
content_hash считается по всей области, кроме table_docs: тексты для студента можно править, не пересобирая практику.
tasks.json
| Поле | Что содержит |
|---|---|
id, title | идентификатор и короткое имя |
kind | select, dml или ddl |
business_statement | формулировка для студента, без имён таблиц |
statement | точная формулировка; по ней строятся проверки |
objectives | идентификаторы тем курса |
difficulty | 1–3 |
result | ожидаемая форма результата для select |
state_tables | таблицы, состояние которых сравнивается, для dml |
require_constructs, forbid_constructs | ограничения на текст решения |
source_hash считается по всему заданию, кроме business_statement.
materializations/<task_id>.json
| Поле | Что содержит |
|---|---|
task_id, source_hash | к какой версии задания это относится |
solution_sql | эталонное решение |
variants | описания вариантов данных: id, kind, seed, quotas |
checks | список проверок: type, section, params |
expected | ожидаемый исход эталона на каждом варианте |
negatives | намеренно неверные решения: label, sql |
Элемент expected содержит своё для каждого типа задания: result_hash и result_rows для select, table_state_hashes и table_state_rows для dml, schema_snapshot для ddl.
Проверки
type | Что сравнивает |
|---|---|
schema | набор и порядок колонок |
cardinality | число строк: одна, много, допустимо ноль |
result_exact | результат построчно |
result_hash | хэш нормализованного результата |
table_state | состояние таблиц после dml |
db_schema | структуру схемы после ddl |
sql_constraints | обязательные и запрещённые конструкции |
Поле section делит проверки на public и sealed. Открытые студент видит по именам, скрытые существуют только на бэкенде.
state.json
{
"domain_approved": "9d6654cf…",
"tasks_approved": "39bc8483…",
"tasks_domain_hash": "9d6654cf…"
}
Три хэша, из которых складывается вся логика «устарело»: что утверждено как область, что утверждено как набор заданий и к какой версии области этот набор собран. Материализация сверяет свой source_hash с текущим заданием сама.
Нормализация результата
Перед сравнением результат канонизируется:
- порядок строк приводится к каноническому, если задание не требует конкретного;
- числа округляются до объявленной точности —
40и40.00равны; - имена колонок сравниваются без учёта регистра;
NULLотличается от пустой строки и от нуля.
Одна и та же функция нормализации используется и при записи ожидаемых результатов, и при проверке решения студента, и при построчном сравнении в интерфейсе.
Совместимость
Версия движка данных записана в манифесте пака. Несовместимость по мажорной версии — отказ раннера запускать пак, а не молчаливое расхождение результатов. Имена токенов темы — отдельный контракт со своей версией в theme.json.