generated from VLADIMIR/template
up
This commit is contained in:
@@ -346,3 +346,93 @@ RustFS и создать `<marker>.continue` в течение минуты. Buc
|
||||
|
||||
Интерфейс передачи остаётся этапом 7; полный билетный и игровой прогон — этапом 8.
|
||||
До готовности возврата результатов используются только тестовые игры.
|
||||
|
||||
## Пакет результатов, версия 1 (ED-029, этап 9)
|
||||
|
||||
Это отдельный контракт: ZIP содержит ровно `manifest.json` и `results.json`,
|
||||
без сценария и файлов. Он ещё не применяется онлайн и не доступен через API/UI.
|
||||
|
||||
`game_results_package_service.NewGameResultsPackageService(repo, mode).Prepare(ctx,
|
||||
gameID, output)` доступен только в `venue`, для существующей игры из готового
|
||||
импорта со статусом `finish` и заполненными датами проведения. Репозиторий
|
||||
читает исходный реестр и текущие игровые данные в read-only транзакции
|
||||
`REPEATABLE READ`. Подготовка ничего не меняет и не блокирует редактирование.
|
||||
Повторный вызов создаёт новый ID и снимок, включая последующее оценивание.
|
||||
|
||||
Для работы без БД используются `Pack(ctx, manifest, data, output)` и
|
||||
`Unpack(ctx, input io.ReaderAt, size)`. `Pack` задаёт версию, новый 128-битный
|
||||
случайный ID, UTC-время, размер и SHA-256 `results.json`. При любой ошибке caller
|
||||
отбрасывает выходной файл. `Unpack` возвращает только полностью проверенный
|
||||
`Bundle`, читает ограниченные JSON в память, не извлекает файлы и не обращается
|
||||
к сети/БД. Отмена контекста сохраняется в цепочке ошибки.
|
||||
|
||||
### manifest.json
|
||||
|
||||
| Поле | Значение |
|
||||
| --- | --- |
|
||||
| `version` | `1` |
|
||||
| `package_id`, `created_at` | ID именно пакета результатов, время подготовки |
|
||||
| `source_server`, `game_id` | Онлайн-источник и исходный ID игры |
|
||||
| `source_package_id`, `source_sha256` | ID и SHA-256 всего исходного ZIP игры из реестра импорта |
|
||||
| `size`, `sha256` | Размер и SHA-256 байтов `results.json` |
|
||||
|
||||
SHA-256 защищает от повреждения; это не подпись и не доказательство подлинности.
|
||||
Онлайн-применение должно сверять источник и исходный экспорт на этапе 10.
|
||||
|
||||
### results.json
|
||||
|
||||
Все массивы обязательны и являются полным снимком; пустой массив — `[]`,
|
||||
пропущенный или `null` массив не допускается.
|
||||
|
||||
| Поле | Содержимое |
|
||||
| --- | --- |
|
||||
| `source` | Исходные `teams`/`tickets` из сохранённого `game.json`, `scenario_id`, SHA-256 сериализованного исходного `story` в `scenario_sha256`, `materials` и `question_codes` |
|
||||
| `game` | `id`, `status=finish`, неизменённый `format`, `started_at`, `ended_at` |
|
||||
| `teams` | Итоговые поля команды из контракта игры плюс `source_id` и необязательный `local_creator_id` |
|
||||
| `tickets` | Итоговые поля билета из контракта игры плюс `source_id` и необязательный `local_used_by` |
|
||||
| `deleted_team_ids`, `deleted_ticket_ids` | Все исходные ID, отсутствующие в итоговом снимке |
|
||||
| `actions` | Локальные `id`, `team_id`, `code`, `via_mcp`, `created_at`; порядок по команде, времени и ID сохраняет повторные и неизвестные коды |
|
||||
| `applications` | Локальные `id`, `team_id`, исходные `name`/`image`/`file_type`, `status` (`need`/`done`), `created_at` |
|
||||
| `answers` | `team_id`, `question_code`, `answer`, nullable `score`, `created_at`, `updated_at` |
|
||||
|
||||
`source_id` совпадает с `id` для исходной записи и равен `0` для новой локальной.
|
||||
Все ссылки прогресса используют итоговый локальный `team_id`. Локальные ID новых
|
||||
команд, билетов, ходов и улик не являются свободными ID онлайн-базы: следующий
|
||||
этап должен выделять ID и сохранять соответствия.
|
||||
|
||||
`creator_id` и `registration_delivery_id` итоговой команды берутся только из
|
||||
исходного снимка; для новой команды они отсутствуют. Текущий локальный создатель
|
||||
сохраняется отдельно как `local_creator_id`. `used_by` билета восстанавливается
|
||||
из исходного снимка только для ранее использованного билета без локального
|
||||
исполнителя; текущий локальный исполнитель хранится в `local_used_by`.
|
||||
Эти пространства пользователей нельзя автоматически связывать или переносить
|
||||
с ними права. Пароли QR и хеши билетов сохраняются; SMTP-задания, токены писем,
|
||||
JWT, refresh-токены и локальные аккаунты в пакет не входят.
|
||||
|
||||
Материал — тройка `name`, `image`, `file_type`; имя очищается штатным cleaner,
|
||||
тип при отсутствии определяется штатным file storage. `image` указывает на
|
||||
`files/...` исходного пакета игры, а не на адрес/ключ локального RustFS.
|
||||
При сборке проверяется идентичность текущего игрового `story` исходному после
|
||||
штатного переименования медиа при импорте, а также ID сценария и формат игры.
|
||||
Изменённый сценарий и не связанные с ним материалы отклоняются. Музыка, карта,
|
||||
экраны и оформление не возвращаются. Баллы не пересчитываются: сохраняются
|
||||
выставленные значения, включая `0` и `null`, также в формате `offline`.
|
||||
|
||||
### Проверка и ограничения
|
||||
|
||||
Архив и распакованный объём ограничены 1 ГиБ; каждый из двух JSON — 8 МиБ
|
||||
(фактический максимальный объём данных меньше общего предела). Проверяются
|
||||
точный состав ZIP, обычные нешифрованные записи, отсутствие дублей, версия,
|
||||
размеры, CRC и SHA-256, обязательные поля, исходные/локальные идентификаторы,
|
||||
полнота удалений, уникальность хешей билетов, ссылки прогресса, материалы,
|
||||
вопросы и порядок ходов. Неизвестные поля и лишние JSON-документы отклоняются.
|
||||
|
||||
Проверки кодека: `go test ./internal/services/game_results_package_service`.
|
||||
Полный PostgreSQL/RustFS-flow: `python3 tests/venue/flow.py --results` из корня
|
||||
workspace. Стенд проверяет оба формата, свежую оценку и конкурентные снимки,
|
||||
сохранность прежнего ZIP, повторную подготовку после перезапуска и отсутствие
|
||||
изменений исходных игр. Пакеты и тестовые ресурсы удаляются после прогона.
|
||||
|
||||
Применение онлайн, разрешение конфликтов и идемпотентность возврата — этап 10;
|
||||
подготовка/скачивание и импорт через интерфейс — этап 11. До завершения возврата
|
||||
используются только тестовые игры.
|
||||
|
||||
Reference in New Issue
Block a user