exchanger/docs/operations/RECOVERY_AND_MOCK_QA.md

7.8 KiB
Raw Permalink Blame History

Восстановление операций и проверка mock-сценариев

Дополнительные эксплуатационные инструкции: Windows kiosk setup, матрица доступа к настройкам и длительный soak-тест.

Назначение

Документ фиксирует безопасное поведение Exchanger при сбое приложения или потере связи до появления спецификации реального контроллера. Описанные правила не предполагают существование wire-команд, идентификаторов транзакций или запроса статуса, которых ещё нет в документации.

Локальный идентификатор операции

Каждая ветка оплаты получает уникальный OperationId. Это локальный диагностический идентификатор приложения, а не идентификатор банковской транзакции и не будущий идентификатор команды контроллера. После получения протокола эти значения можно будет связать отдельным полем, но смешивать их нельзя.

Журнал операций

Жизненный цикл записывается построчно в JSONL-файл:

user://logs/operations.jsonl

Запись содержит время UTC, тип события Started/Finished, локальный OperationId, способ оплаты, сумму, расчётное число жетонов, итог и типизированный код ошибки. В журнал запрещено записывать номер карты, данные магнитной полосы/чипа, платёжные токены, сырые ответы оборудования и персональные данные.

Повреждённая строка не мешает чтению остальных записей. При достижении текущим файлом настроенного лимита он переносится в operations-<timestamp>.jsonl. Архивы exchanger, operations и settings-audit автоматически очищаются по сроку хранения и общему объёму; активные файлы при очистке защищены.

Правила восстановления после перезапуска

При старте приложение ищет Started без соответствующего Finished и закрывает такую запись итогом UnknownAfterRestart. Автоматическая повторная оплата или выдача не запускается.

Для операции, прерванной в CardTerminalWait:

  1. Не считать платёж успешным или отклонённым без подтверждения терминала/контроллера.
  2. Не запускать новую оплату автоматически.
  3. Вернуть пользовательский интерфейс на домашний экран.
  4. Оператор сверяет время и OperationId с журналом терминала и будущими журналами контроллера.

Для операции, прерванной в Dispensing:

  1. Считать результат выдачи неизвестным.
  2. Не повторять команду выдачи и не предлагать пользователю повторную оплату.
  3. Оператор проверяет физически выданные жетоны, остаток и журнал контроллера.
  4. Автоматическое восстановление допускается только после документированного запроса статуса либо подтверждённой идемпотентности команды.

До получения протокола приложение не может автоматически различить «команда не дошла» и «команда выполнена, но подтверждение потеряно». Это намеренное безопасное ограничение.

Ручной mock-чек-лист

Панели эмуляции отображаются только в debug-сборке. Перед проверкой выполнить dotnet test Exchanger.sln, затем запустить главную сцену.

Сценарий Действия Ожидаемый результат
Наличные: успех Открыть оплату наличными, добавить тестовые купюры, нажать выдачу Сначала «Идёт выдача», затем подтверждённый успех; бинарный уровень запаса не изменяется без отдельного сигнала датчика
Карта: успех Выбрать сумму, нажать УСПЕХ (DEBUG) Выдача запускается один раз, успех показывается только после mock-подтверждения
Карта: отказ Нажать ОТКАЗ (DEBUG) Без выдачи показывается безопасная ошибка оплаты
Ошибка выдачи Нажать ОШИБКА ВЫДАЧИ Показывается типизированная ошибка; сырая строка mock-контроллера не выводится
Частичная выдача Выбрать сумму более одного жетона, нажать ЧАСТИЧНАЯ ВЫДАЧА Показывается обращение в поддержку; повтор выдачи недоступен
Потеря связи до выдачи Нажать ПОТЕРЯ СВЯЗИ на экране ожидания карты Операция завершается ConnectionLost, пользователь направляется в поддержку
Потеря связи во время выдачи Задать увеличенную DispenseDelaySeconds, подтвердить карту и вызвать SimulateConnectionLoss() через разрешённый godot-ai Итог DispenseStatusUnknown; интерфейс предупреждает не повторять оплату
Таймаут Не подтверждать оплату до истечения настроенного времени Выдача не запускается, итог PaymentTimeout
Повторный ввод Быстро нажать действие несколько раз Создаётся одна операция и не более одной выдачи
Перезапуск Завершить приложение с активной операцией, затем запустить снова Незакрытая запись получает UnknownAfterRestart; автоматического retry нет

После каждого сценария проверить user://logs/exchanger.log, user://logs/operations.jsonl, а также game/editor logs. В них не должно быть платёжных секретов, необработанных исключений и дублированных итогов одной операции.