generated from VLADIMIR/template
up
This commit is contained in:
+89
-7
@@ -350,7 +350,7 @@ RustFS и создать `<marker>.continue` в течение минуты. Buc
|
||||
## Пакет результатов, версия 1 (ED-029, этап 9)
|
||||
|
||||
Это отдельный контракт: ZIP содержит ровно `manifest.json` и `results.json`,
|
||||
без сценария и файлов. Он ещё не применяется онлайн и не доступен через API/UI.
|
||||
без сценария и файлов. Серверное применение реализовано этапом 10; API/UI остаются этапом 11.
|
||||
|
||||
`game_results_package_service.NewGameResultsPackageService(repo, mode).Prepare(ctx,
|
||||
gameID, output)` доступен только в `venue`, для существующей игры из готового
|
||||
@@ -396,9 +396,10 @@ SHA-256 защищает от повреждения; это не подпись
|
||||
| `answers` | `team_id`, `question_code`, `answer`, nullable `score`, `created_at`, `updated_at` |
|
||||
|
||||
`source_id` совпадает с `id` для исходной записи и равен `0` для новой локальной.
|
||||
Все ссылки прогресса используют итоговый локальный `team_id`. Локальные ID новых
|
||||
команд, билетов, ходов и улик не являются свободными ID онлайн-базы: следующий
|
||||
этап должен выделять ID и сохранять соответствия.
|
||||
Все ссылки прогресса используют итоговый локальный `team_id`. Этап 10 уточняет
|
||||
выделение ID: новые команды сохраняют venue-ID и пароль для напечатанных QR;
|
||||
занятый чужой командой ID отклоняет весь возврат. Новым билетам, ходам и уликам
|
||||
выделяются онлайн-ID, соответствия сохраняются в закрытом реестре.
|
||||
|
||||
`creator_id` и `registration_delivery_id` итоговой команды берутся только из
|
||||
исходного снимка; для новой команды они отсутствуют. Текущий локальный создатель
|
||||
@@ -433,6 +434,87 @@ workspace. Стенд проверяет оба формата, свежую о
|
||||
сохранность прежнего ZIP, повторную подготовку после перезапуска и отсутствие
|
||||
изменений исходных игр. Пакеты и тестовые ресурсы удаляются после прогона.
|
||||
|
||||
Применение онлайн, разрешение конфликтов и идемпотентность возврата — этап 10;
|
||||
подготовка/скачивание и импорт через интерфейс — этап 11. До завершения возврата
|
||||
используются только тестовые игры.
|
||||
Подготовка/скачивание и возврат через интерфейс — этап 11. До завершения
|
||||
интерфейса и контрольного прогона используются только тестовые игры.
|
||||
|
||||
|
||||
## Применение результатов онлайн (ED-029, этап 10)
|
||||
|
||||
`game_results_package_service.NewGameResultsApplyService(repo, privateStorage,
|
||||
mode, sourceServer).Apply(ctx, input io.ReaderAt, size, initiatorID)` доступен
|
||||
только при `mode="prod"`. Это серверный сервис без нового API/UI и развёртывания.
|
||||
Возвращается закрытая запись реестра; будущий transport должен выдавать только
|
||||
публичный результат операции.
|
||||
|
||||
Входные байты один раз сохраняются в приватный временный файл и проверяются
|
||||
кодеком этапа 9; SHA-256 всего ZIP связывает повтор с этими же байтами.
|
||||
Сервис проверяет сервер-источник, игру, ID и SHA-256 исходного экспорта, читает
|
||||
его ZIP из закрытого хранилища, проверяет размер, контрольную сумму и контракт.
|
||||
`source` результатов сверяется с данными этого ZIP: команды, билеты, сценарий,
|
||||
материалы и вопросы нельзя подменить в загруженном пакете. Формат неизменяем.
|
||||
Все временные файлы/каталоги имеют права 0600/0700 и удаляются при успешном
|
||||
применении, отказе и отмене.
|
||||
|
||||
Пакет результатов считается источником истины для возвращаемых данных:
|
||||
онлайн-правки состава команд/билетов, прогресса, ответов, баллов, формата,
|
||||
статуса и фактических дат перезаписываются без сравнения с прежним состоянием.
|
||||
Игровой сценарий восстанавливается из сохранённого экспортного снимка с
|
||||
исходными онлайн-ссылками материалов. Если текущий сценарий отличается,
|
||||
создаётся отдельная копия для возвращаемой игры; сценарии других игр не меняются.
|
||||
Копия сохраняет оформление и playlist текущего сценария; неизменённый сценарий
|
||||
повторно не копируется. Название, описание, место, плановая дата, музыка, карта
|
||||
и экраны игры сохраняются. Отсутствующая игра не восстанавливается.
|
||||
|
||||
Полные итоговые снимки заменяют команды/участие и билеты с учётом удалений,
|
||||
ходы/MCP, материалы и выдачу, ответы и nullable баллы, статус `finish` и
|
||||
фактические даты. Баллы не пересчитываются. Удаление команды очищает её связи
|
||||
карты. Исходные команды/билеты сохраняют ID; новые команды сохраняют также
|
||||
venue-пароль. Новые билеты получают онлайн-ID и прежний хеш токена. Коллизия
|
||||
ID или хеша с чужой записью отклоняет весь пакет. Ходы и улики получают свежие
|
||||
онлайн-ID в порядке пакета, включая исправленный снимок. Реестр хранит
|
||||
соответствия каждого возврата; соответствия новых билетов сохраняются между
|
||||
исправлениями. Последовательности продвигаются монотонным `nextval`, без `setval`
|
||||
и глобальных блокировок обычных операций.
|
||||
|
||||
Материалы переводятся из portable-троек исходного ZIP в исходные онлайн-ссылки
|
||||
через сохранённый экспортный снимок. Новых загрузок файлов и скачивания внешних
|
||||
URL нет. Существующие онлайн-ссылки создателей и исполнителей и технические
|
||||
почтовые поля сохраняются; их изменение не считается изменением возвращаемых
|
||||
данных. У новых команд `creator_id=NULL`, у новых локально использованных
|
||||
билетов `used_by=NULL`; отсутствующий онлайн-аккаунт не восстанавливается.
|
||||
Локальные исполнители остаются только в закрытом реестре. Новые почтовые
|
||||
задания и токены не создаются; возвращённые игры исключены из очереди новых
|
||||
напоминаний об отзыве.
|
||||
|
||||
`game_returns` хранит ID/SHA-256 ZIP результатов, исходный экспорт, исходный ID
|
||||
игры, время подготовки/применения, соответствия ID (включая сценарий),
|
||||
локальных исполнителей и инициатора. Записи остаются после
|
||||
удаления игры. Тот же ID с теми же байтами возвращает первоначальную запись без
|
||||
изменений, даже после более нового пакета или удаления игры. Тот же ID с другими
|
||||
байтами — конфликт. Новый пакет требует `created_at` строго позже последнего
|
||||
применённого; время используется без поправок часов. UTC-время подготовки
|
||||
сохраняется строкой с фиксированными девятью знаками долей секунды, чтобы
|
||||
PostgreSQL не терял наносекунды при сравнении и повторе.
|
||||
|
||||
Чтение текущих ссылок пользователей, запись данных и реестра выполняются
|
||||
одной `SERIALIZABLE`
|
||||
транзакцией с блокировками игры, экспорта, сценария и затронутых записей.
|
||||
Serialization failure/deadlock повторяются не более трёх раз, затем возвращается
|
||||
безопасная повторяемая ошибка. Проверки ZIP/хранилища проходят до транзакции.
|
||||
`game.export` исчезает в чтении игры и списка после успешного возврата именно
|
||||
соответствующего экспорта; исходный экспорт остаётся `ready`, ZIP сохраняется
|
||||
для следующих проверок. Более старый экспорт вместо скрытого не показывается.
|
||||
|
||||
Проверки: `go test ./...` с отдельным `TEST_DATABASE_URL`, релевантный `go test
|
||||
-race`, `python3 tests/venue/flow.py --apply`. Стенд проверяет оба формата,
|
||||
настоящие venue-ZIP, prod PostgreSQL/private RustFS, перезапись онлайн-редактирования,
|
||||
исправление баллов, старый повтор после нового и перезапуска prod, прежние и
|
||||
новые ссылки, сохранение оформления и исчезновение офлайн-отметки.
|
||||
|
||||
Ограничения: ZIP не имеет криптографического подтверждения подлинности.
|
||||
Sequence-значения PostgreSQL не откатываются: большие разрывы venue-ID расходуют
|
||||
их даже при отказе. Продвижение ограничено пятью секундами, затем данные
|
||||
откатываются и возвращается повторяемая ошибка; INT32-потолок отклоняется.
|
||||
Перед поддержкой площадок с такими разрывами требуется расширить типы ID.
|
||||
ZIP на 1 ГиБ, 100 клиентов и Wi-Fi этим этапом не проверяются. До завершения
|
||||
этапа 11 и контрольного прогона используются только тестовые игры.
|
||||
|
||||
Reference in New Issue
Block a user