218 KiB
Дорожная карта проекта Exchanger
1. Назначение документа
Этот файл — единая точка отслеживания разработки полноэкранного приложения вендингового аппарата для выдачи жетонов. Он фиксирует текущее состояние, принятые архитектурные решения, порядок реализации, критерии готовности, риски и вопросы, требующие согласования.
Дата формирования первоначального плана: 2026-08-20.
Последняя актуализация состояния: 2026-09-07.
2. Легенда статусов
[ ]— задача не начата.[~]— задача выполняется.[x]— задача выполнена и проверена.[!]— задача заблокирована внешней зависимостью или решением.[?]— требуется уточнение или согласование.
Правило обновления: задача получает [x] только после выполнения указанных для неё проверок и критериев приёмки. При завершении этапа следует добавлять короткую запись в журнал прогресса в конце файла.
3. Цель продукта
Создать на Godot 4.7 Mono/C# надёжное портретное киоск-приложение для напольного разменника жетонов. Приложение должно:
- Показывать интерфейс с единственной встроенной fallback-темой, заменяемой при запуске одним внешним DLC со статическим фоном и отдельными анимированными 2D-спрайтами.
- Показывать цену жетона, бинарное состояние запаса «много/мало» и бонусные условия.
- Поддерживать отдельные сценарии оплаты наличными и картой.
- Безопасно отправлять команду выдачи жетонов через последовательный порт.
- Дожидаться результата выдачи и показывать успех либо понятную ошибку.
- Возвращаться в исходное состояние по таймаутам и после завершения сессии.
- Работать прежде всего на Windows x64 и не связывать UI с конкретной реализацией порта, чтобы в будущем заменить её на Android USB-Serial.
- Воспроизводить промо-контент на домашнем экране без влияния на основной сценарий.
- Соответствовать портретному корпусу и пиксельной космической айдентике из подтверждённых референсов.
4. Текущее состояние проекта
- Создан проект
Exchangerна Godot 4.7.1 Mono. - Настроена сборка C# под .NET 8; Android-конфигурация проекта указывает .NET 9.
- Выбран рендерер
mobile(Vulkan): он нужен runtime-расширению Native Video для MP4/MOV/M4V. - C#-решение собирается без ошибок и предупреждений.
- Подключены плагины
godot_ai,godotx_toast,logиreload_current_scene. - Подключён runtime GDExtension
native_video: настройки промо принимают OGV/MP4/MOV/M4V, а export сохраняет его Windows/Linux библиотеки; внешние MP4/MOV/M4V сохраняют исходный путь. Unicode-пути Windows передаются Native Video напрямую без копий, ссылок и ASCII-псевдонимов. - Устранён временный кэш player/stream:
Stop(),Stream = null, смена источника иQueueFree()проходят штатно; 50 циклов проверены в реальномAdvertisementPlayer. - Создана атомарная структура
src/core,src/scenes,src/ui,src/hardwareи каталогов ассетов; разработка тем полностью вынесена из репозитория приложения. - Созданы первые собственные C#-скрипты, ресурсы и сцены.
- Главной сценой назначена
src/scenes/App/App.tscn. - Добавлен пользовательский Input Action
kiosk_back; устаревшийdebug_cycle_themeудалён вместе с переключением тем. - Корневой
README.mdполностью переписан под Exchanger. - Ошибочный корневой
LICENSEот GodotX Toast удалён; лицензии сторонних компонентов сохранены рядом с ними. - Зафиксировано, что собственная лицензия Exchanger пока не объявлена.
- Проанализированы восемь изображений и видео интерфейса; выводы сохранены в
docs/REFERENCE_ANALYSIS.md. - Каталог
references/исключён из Git через.gitignoreи отмечен как непроизводственный источник концептов. - Динамический shader/particle-фон удалён; активная сцена использует
StaticBackgroundсо статическим цветом/изображением и отдельным слоем анимированных спрайтов. - Ландшафтный
StartScreenудалён и заменён портретнымHomeScreen; логический viewport синхронизирован с theme-preview на 720×1280. - Инициализирован локальный Git-репозиторий; remote и первый коммит будут настроены отдельным решением владельца проекта.
- Полный runtime переведён на C#/.NET 8, девять атомарных экранов и один внешний
self-contained DLC;
space-pixelпринят по manifest v2 с 481 обязательным биндингом. - Подтверждён целевой
DualHopperAuto: первый хоппер использует30X,IN1иIN24, второй —40X,IN4иIN25, сервисная кнопка —IN8. - Windows x64 release собран как один
Exchanger.exeсо встроенными PCK и .NET outputs; packaged smoke прошёл на mock и подтвердил авторизацию реального контроллера на COM3. - Windows export разделён на явные пресеты
Windows x64 ReleaseиWindows x64 Debug; staging-скрипт жёстко выбирает соответствующий--export-releaseили--export-debug. - Этапы 4 и 5 закрыты: COM-транспорт и полный MVP-сценарий реализованы и покрыты автоматическими проверками; оставшаяся физическая приёмка вынесена в раздел 4.1.
- В разделе «Сервис» добавлено немедленное скрытие элементов Home: учётного остатка, theme-owned персонажа справа и целого промо-блока; скрытые панели исключаются из маршрутов питомца.
- Точный учёт жетонов и запрет покупки сверх остатка управляются раздельно: можно продолжать показывать/списывать остаток, не ограничивая им оплату; отключение учёта скрывает сервисные действия.
- [~] Добавлен и проверен one-file Linux x86_64 export для Debian 13; платформенная валидация serial-path завершена, udev/dialout и kiosk остаются открытыми.
4.1. Проверки на автомате
Этот раздел — единая очередь проверок, требующих физического автомата, его панели, контроллера, платёжной периферии или целевого системного блока. Они не переоткрывают завершённые программные этапы. Перед каждым аппаратным запуском требуется проверить фактическое подключение и занятость порта, подготовить автомат и получить отдельное разрешение на конкретную группу тестов.
Интерфейс, панель и производительность
- Проверить читаемость с рабочего расстояния и при ярком освещении.
- Проверить управление пальцем и в перчатках: все девять экранов, прокрутку Settings, текстовую и цифровую клавиатуры, первое касание и отсутствие действий по hover.
- Проверить масштабирование сетки 720×1280, ориентацию, калибровку touch и размеры зон на фактическом разрешении панели.
- Повторить performance baseline на целевом ПК: FPS, CPU-время, память и draw calls
в fallback и
space-pixel, в полном и облегчённом режимах. - Профилировать одновременную работу анимированных спрайтов DLC и декодера реального MP4/OGV-промо-ролика в Mobile/Vulkan.
- Проверить отключение/возврат дисплея, потерю фокуса, kiosk/autostart и watchdog.
Контроллер, платежи и хопперы
- Повторить безопасную приёмку COM3: framing, AES-handshake, точный
READY!,INPUT, status-запросы, безопасное исходное состояние и несколько штатных reconnect-циклов. - Проверить физическое отключение/возврат USB-COM: UI не зависает, worker не дублируется, незавершённая выдача не повторяется, позднее подтверждение не завершает новую операцию.
- Проверить
IN8/SERVICE, уровни запасаIN1иIN4, удержание кнопки без повторов и открытие/закрытие Settings с включённым и выключенным PIN. - Проверить монетник и купюроприёмник: включение/отключение каналов,
MONEY:*,ASK:*, накопление суммы, отмену, таймаут и отсутствие двойного учёта. - Проверить безналичную оплату: точное совпадение суммы
163иMONEY:CASHLESS,ASK:CASHLESS, отмену, timeout/decline и keep-alive161реже 180 секунд. - Проверить обычную выдачу обоих хопперов:
309N/409N, пакеты 1–99,APPEND=N, по одному подтверждению на каждыйHOPPER1/2 OK, маршрутизацию и раздельное списание остатка. - Проверить частичную/ошибочную выдачу:
ERROR→CREDIT=N, запросы3090/4090, отсутствие автоматического retry и единственный итог операции. - Проверить сервисный пересчёт обоих хопперов:
301/300и401/400, учёт толькоHOPPER1/2 PULSE=1, завершение после 10 секунд тишины и безопасную остановку мотора. - Проверить три сочетания политики на реальном автомате: учёт с лимитом, учёт без лимита и полностью выключенный учёт; подтвердить блокировку card/cash до аппаратной команды, работу бонусов, продолжение списания без лимита, скрытие сервисных действий и пересчёт перед включением.
- Проверить перезапуск/потерю питания во время операции: запись получает
UnknownAfterRestart, оплата и выдача автоматически не повторяются.
Длительная и установочная приёмка
- Выполнить непрерывный 24-часовой soak с повторными сессиями, оплатой, выдачей, SERVICE, автосохранением, ротацией логов и периодическим отключением/возвратом дисплея.
- Провести чистую установку Windows-релиза на целевом устройстве; проверить доверие подписи, конфигурацию, внешний DLC, автозапуск, обновление и откат.
- После программной Linux-адаптации запустить ELF на Debian 13 и принять графику, touch,
внешний DLC, USB-UART, udev/dialout, kiosk/autostart и watchdog.
Предварительное обнаружение выполнено: Debian распознал Silicon Labs CP2102
10c4:ea60штатнымcp210xи создал/dev/ttyUSB0; права и обмен с Exchanger ещё не проверялись. - Если будет выбран Android-порт, провести на целевом ARM64-устройстве export/runtime, USB permission/reconnect, Mobile renderer, touch, системные жесты, поворот, энергосбережение и полный регрессионный сценарий.
5. Зафиксированные архитектурные решения
5.1. Рендерер
Использовать Mobile renderer (Vulkan) как базовый режим. Это обязательное требование
runtime-расширения Native Video для MP4/MOV/M4V; оно совместимо с 2D-пиксельным UI и целевой
Windows/Linux конфигурацией. Compatibility нельзя включать, пока требуется Native Video. Для
слабого GPU остаётся ReducedEffects; производительность и аппаратное декодирование должны быть
приняты на целевом железе в разделе 4.1.
5.2. Слои приложения
Пользовательский интерфейс и экраны
↓
Контроллер сессии и конечный автомат операции
↓
Сервис протокола контроллера
↓
IHardwarePort
↙ ↘
MockHardwarePort SerialPortHardware
↘
UsbSerialHardware (stub)
UI не должен знать о SerialPort, потоках и формате строк протокола. Он реагирует на типизированные состояния и события контроллера сессии.
5.3. Состояния пользовательской сессии
Home
├→ CashAccepting
│ → Dispensing
│ → Completed
└→ CardAmountSelection
→ CardCustomAmount (опционально)
→ CardTerminalWait
→ Dispensing
→ Completed
→ Home
Любое активное состояние
→ PaymentDeclined, Error или Cancelled
→ Home
Переход в Completed разрешён только после подтверждения выдачи контроллером. Сам факт отправки DISPENSE не считается успешной выдачей.
5.4. Сцены и глобальные сервисы
- Главная сцена:
src/scenes/App/App.tscn. Appсоздаёт дваCanvasLayer: фон сlayer = 0и UI сlayer = 1.- Экраны — отдельные атомарные сцены
Controlсо своим C#-скриптом и локальными ресурсами. ThemeManagerиScreenManagerрегистрируются как Autoload, как требует ТЗ.SessionController, адаптер протокола и аппаратный сервис принадлежат главной сцене или отдельному композиционному узлу приложения; их не следует без необходимости превращать в глобальные Singleton.ScreenManagerпереключает сцены экранов и не содержит бизнес-логику оплаты или выдачи.SessionControllerявляется единственным владельцем состояния текущей операции.HomeScreenсразу показывает цену, запас, способы оплаты, промо-fallback и контакты поддержки.- Платёжные сцены разделяются по назначению:
CashPaymentScreen,CardAmountScreen,CardCustomAmountScreenиCardTerminalScreen. AdvertisementPlayerявляется пассивным UI-компонентом домашнего экрана и останавливает декодирование, когда экран скрыт.
5.5. Формат темы
В Exchanger существует одна программная fallback-тема. Разрабатываемые темы полностью вынесены в соседний ExchangerThemeDlcBuilder и подключаются только как один внешний Godot .pck. После загрузки runtime-представление VendingThemeDefinition содержит:
- стабильный идентификатор и отображаемое имя темы;
Themeдля Control-интерфейса;- необязательную статическую
Texture2Dфона; - необязательные
PackedSceneфоновых слоёв/декораций и именованных пассивных визуальных слотов экранов; - для manifest v2 — полный набор из девяти пассивных визуальных сцен экранов с каноническими именами и metadata binding-id;
- fallback-цвет; облегчённый режим хранится в конфигурации приложения.
Сам фон всегда статичен: ColorRect с fallback-цветом и, при наличии, неподвижный TextureRect. Анимированные спрайты темы добавляются отдельной PackedScene; такая сцена может содержать AnimatedSprite2D и AnimationPlayer, но обязана быть пассивной декорацией и не зависеть от экранов приложения. Фоновые шейдеры, частицы и видео не используются. Промо-ролик допускается только внутри отдельного UI-блока AdvertisementPlayer на HomeScreen.
Полносценовая тема не содержит бизнес-логику: приложение инстанцирует собственные C#-контроллеры,
до _Ready заменяет встроенный визуальный корень сценой DLC и разрешает кнопки, поля и динамические
области через стабильную metadata exchanger_binding_id. Вложенность узлов темы свободна. Manifest
v1 сохраняет обратную совместимость как стилевой пакет; v2 требует все девять сцен целиком и
точную копию каталога из 481 обязательного биндинга. Host закрепляет SHA-256 каталога и до
активации отклоняет неверные пути, root-имена, неизвестные или неверно типизированные binding-id
и дубли. Отсутствующий обязательный binding восстанавливается по каноническому FallbackPath
узлом старой сцены либо готовым элементом встроенной темы-заглушки.
В основном проекте нет каталога themes/ и исходных ресурсов тем. Путь к единственному внешнему DLC берётся из пользовательского appsettings.json; пакет имеет версионированный manifest, изолированное пространство res://exchanger_theme_dlc/, монтируется без замены ресурсов приложения и требует перезапуска для обновления.
5.6. Потоки и последовательный порт
- Только реализация
SerialPortHardwareработает сSystem.IO.Ports. - Чтение выполняется в отдельном потоке с корректной отменой и освобождением ресурсов.
- Фоновый поток не вызывает API Godot и не обращается к Node/Resource/UI.
- Принятые строки и изменения соединения передаются в поток Godot через
ConcurrentQueueлибоCallDeferred. - Разбор строк протокола выполняется отдельно от транспорта и покрывается тестами.
- Повтор команды выдачи после неизвестного результата запрещён без идемпотентного идентификатора операции или явного подтверждения, что первая команда не была принята.
5.7. Конфигурация
- Встроенные безопасные значения:
res://config/default_settings.json. - Пользовательские настройки:
user://config/appsettings.json. - При первом запуске создаётся пользовательский файл на основе значений по умолчанию.
- Ошибочный файл не должен ломать запуск: ошибка логируется, применяются безопасные значения по умолчанию.
- Планируемые параметры: порт, baud rate, таймауты, путь и разрешение внешнего DLC темы, режим имитации оборудования, уровень эффектов, общая громкость и громкость промо-ролика, mute, параметры логирования, цена жетона, карточные суммы, бонусные правила, бинарное mock-состояние запаса, способы оплаты, телефон поддержки и плейлист промо-роликов.
- Секреты платёжного терминала в конфигурации приложения не хранятся; платёжная интеграция находится на стороне внешнего контроллера.
5.8. Критические эксплуатационные ограничения
- Godot может включить borderless fullscreen и перехватывать обычные действия приложения, но не может надёжно запретить Alt+Tab, Ctrl+Alt+Del или системные жесты Windows. Полная блокировка обеспечивается Windows Assigned Access/Shell Launcher, политиками ОС и учётной записью киоска.
- Тач-ввод принимает только первое касание (
Index == 0). Дополнительные касания игнорируются централизованно. - Минимальная интерактивная область — 64×64 px, основной текст — не меньше 24–32 px на целевом разрешении.
- В интерфейсе нет функций, доступных только по hover.
- Целевой UI проектируется в портретном 9:16 с нативным viewport 720×1280; панели большего разрешения используют масштабирование
canvas_items/expand.
5.9. Требования из визуальных референсов
- Корпус — высокий напольный автомат с зелёной рамой, портретным экраном, физическими приёмниками справа и лотком выдачи ниже экрана.
- Основной стиль — пиксельная космическая тема: тёмно-синий фон, салатовые акценты, белые панели, НЛО и зелёный маскот.
- Домашний экран сразу показывает цену жетона, остаток, выбор наличной/карточной оплаты, действие выдачи, промо-ролик и контакты поддержки.
- Наличная оплата отображает накопленный баланс и инструкции для купюро- и монетоприёмника.
- Карточная оплата содержит пресеты сумм, ввод другой суммы, ожидание терминала и отдельный результат.
- Бонусные жетоны рассчитываются конфигурируемыми правилами, а не зашиваются в UI.
- Референсные файлы не являются production-ассетами; права, финальные исходники, тарифы и бренд требуют подтверждения.
6. Целевая структура каталогов
res://
├── config/
│ └── default_settings.json
├── src/
│ ├── core/
│ │ ├── Configuration/
│ │ ├── Logging/
│ │ ├── ThemeManager/
│ │ ├── Navigation/
│ │ └── Session/
│ ├── hardware/
│ │ ├── Abstractions/
│ │ ├── MockHardware/
│ │ ├── SerialPortHardware/
│ │ ├── UsbSerialHardware/
│ │ └── ControllerProtocol/
│ ├── scenes/
│ │ ├── App/
│ │ ├── HomeScreen/
│ │ ├── CashPaymentScreen/
│ │ ├── CardAmountScreen/
│ │ ├── CardCustomAmountScreen/
│ │ ├── CardTerminalScreen/
│ │ ├── SuccessScreen/
│ │ └── ErrorScreen/
│ ├── ui/
│ │ ├── StaticBackground/
│ │ ├── AdvertisementPlayer/
│ │ ├── TokenStockStatus/
│ │ └── TouchInputGuard/
│ └── vfx/
│ └── SuccessEffect/
└── tests/
├── Unit/
├── Integration/
└── Fixtures/
Структура уточняется по мере реализации, но сохраняется правило атомарности: сцена, скрипт и специфичные ресурсы элемента лежат в одной тематической папке.
7. План реализации
Этап 0. Базовые решения и гигиена репозитория — завершён
Цель: получить однозначную техническую основу до реализации UI и оборудования.
- Зафиксировать продуктовые требования в
ROADMAP.md. - Зафиксировать исходный Compatibility renderer как исторический baseline.
- Обновить корневой
README.md: назначение, требования, запуск, структура, конфигурация и состояние проекта. - Удалить ошибочную корневую лицензию GodotX Toast, сохранив лицензии сторонних аддонов; собственную лицензию пока не объявлять.
- Инициализировать локальный Git-репозиторий; подключение remote и первый коммит оставить отдельным решением владельца.
- Решить хранение проектных инструкций:
.agents/AGENTS.mdверсионируется и не исключается через.gitignore. - Добавить файл архитектурных решений
docs/architecture/decisions.md. - Зафиксировать границу протокола: до появления документации wire-формат и команды не выдумываются; документация является входом Этапа 3, реальный COM — Этапа 4.
- Принять универсальную аппаратную стратегию: не привязывать UI, конфигурацию и бизнес-логику к отсутствующему целевому ПК/GPU/тач-контроллеру.
- Отложить выбор модели контроллера и проверку реального COM-обмена до добавления владельцем списка команд и документации в
references/. - Зафиксировать контроллер единственным источником сведений об оплате, запасе, приёмниках, выдаче и аппаратных ошибках; конкретные сообщения определит будущая документация.
Критерий выхода выполнен: стабильны платформонезависимая граница IHardwarePort, универсальные требования к UI и правило не проектировать неизвестный протокол. Аппаратно-зависимые детали оформлены как входные данные Этапов 3–4 и не блокируют UI, mock-сценарии и бизнес-логику ранних этапов.
Этап 1. Первый вертикальный срез: запуск, тема и стартовый экран — завершён
Цель: получить запускаемое полноэкранное приложение с первой темой и безопасной заглушкой оборудования.
1.1. Настройки приложения
- Установить базовый viewport 1920×1080 и режим растяжения
canvas_items/expand. - Включить borderless fullscreen для production-профиля.
- Предусмотреть удобный оконный debug-режим через конфигурацию или аргумент запуска.
- Сохранить исходный Compatibility renderer как исторический baseline.
- Настроить ограничение/целевую частоту 60 FPS и поведение при потере фокуса.
- Добавить главную сцену
Appи назначить её вapplication/run/main_scene. - Проверить запуск на 1920×1080 и другом соотношении сторон: 1024×768, а также fullscreen 2560×1440.
1.2. Конфигурация и логирование
- Реализовать типизированную модель
AppSettingsс валидацией диапазонов. - Реализовать загрузку defaults → пользовательский JSON → аргументы запуска.
- Добавить безопасное восстановление после битого/неполного JSON.
- Реализовать журнал ключевых событий с временными метками и категориями.
- Добавить ротацию/ограничение размера файлов в
user://logs. - Не записывать в лог платёжные секреты и лишние персональные данные.
1.3. Тема, статический фон и анимированные спрайты
- Создать
VendingThemeDefinition. - Создать базовый UI Theme со шрифтами, размерами, отступами и состояниями кнопок.
- Создать первую тему
cosmic. - Реализовать
ThemeManagerAutoload; первоначальный реестр позднее заменён моделью fallback + один DLC. - Исключить жёсткие пути к теме из экранов.
- Применять одну активную тему ко всем экранам; горячая смена позднее удалена в пользу замены DLC при перезапуске.
- Создать
StaticBackground: обязательныйColorRectи необязательный статическийTextureRect. - Передавать fallback-цвет и статическую текстуру из определения темы.
- Поддержать отдельную тематическую сцену анимированных 2D-спрайтов через
PackedScene. - Отключать необязательные анимированные спрайты в облегчённом режиме, сохраняя статический фон.
- Удалить из активной темы фоновые шейдеры и частицы как не соответствующие референсам.
1.4. StartScreen и аппаратная заглушка
- Создать атомарную сцену
StartScreenс логотипом и кнопкой «Начать». - Обеспечить области касания не меньше 64×64 px и читаемый текст.
- Временная debug-кнопка смены темы была реализована для прототипа и позднее полностью удалена.
- Создать
IHardwarePortбез зависимости от Godot UI. - Создать
MockHardwarePort, который логирует команды и воспроизводит ответы по сценарию. - Создать
UsbSerialHardwareкак явно неподдерживаемый Android stub. - Создать каркас
SerialPortHardware, не открывая реальный порт при старте сцены. - Проверить наличие
System.IO.Ports: сборка отсутствует в установленных reference/shared packs .NET. - Получено разрешение устанавливать необходимые NuGet-пакеты;
System.IO.Portsбудет добавлен только при фактическом начале Этапа 4.
Критерии приёмки этапа:
- приложение запускается в главную сцену без ошибок;
- стартовый экран корректен в fullscreen и debug-window режимах;
- единая активная тема применяется к UI и фону; позднее источником стал fallback либо один внешний DLC при запуске;
- fallback-фон включается настройкой;
- mock получает тестовую команду, а UI не зависит от конкретного транспорта;
- повторная C#-сборка и запуск из Godot проходят без ошибок.
Этап 2. Портретный интерфейс, навигация и жизненный цикл сессии — завершён
Цель: перестроить технический прототип под портретный аппарат из референсов и реализовать детерминированные переходы без реального оборудования.
- Перевести viewport и debug-window в портретный режим; после сверки с theme-preview закрепить нативную сетку 720×1280.
- Реализовать
ScreenManagerAutoload и контейнер экранов вApp. - Загружать экраны через централизованный
ScreenRegistry, а не из разрозненных жёстких путей. - Сохранить общий статический фон между экранами и добавить короткие fade-переходы только для UI.
- Блокировать ввод на время перехода полноэкранным
TransitionInputBlocker; устранить перенос отпускания тача на новый экран. - Заменить
StartScreenнаHomeScreenс ценой, запасом, двумя способами оплаты, промо-fallback и контактами поддержки. - Создать
CashPaymentScreenс балансом, расчётом жетонов/бонуса и инструкциями физических приёмников. - Создать
CardAmountScreenс конфигурируемыми пресетами сумм. - Создать
CardCustomAmountScreenс цифровой клавиатурой, ограничениями и подтверждением. - Создать
CardTerminalScreenс ожиданием, отменой и обратным отсчётом. - Создать
SuccessScreenс режимамиDispensingиCompleted. - Создать
ErrorScreenс отдельными визуальными состояниями отказа оплаты, связи, запаса и выдачи. - Реализовать
AdvertisementPlayerс локальным видео, циклом, fallback-постером и остановкой на скрытых экранах. - Добавить модели
PricingSettings,BonusRule,PaymentPreset,BrandingSettingsиAdvertisementSettings. - Добавить компонент
TokenStockStatusтолько с состояниямиEnough/Low/Unknown, без числового остатка иEmpty. - Реализовать
SessionControllerи явные состояния сессии. - Реализовать общий таймаут бездействия 30–60 секунд для платёжных экранов.
- Реализовать отдельный таймаут карточного терминала 120 секунд.
- Реализовать возврат после успеха через 10 секунд.
- Сбрасывать выбранную сумму/способ оплаты, таймеры и временные данные при возврате в
Home. - Централизованно фильтровать мультитач и принимать только первое касание.
- Защитить навигацию, платёжные действия и выдачу от повторного тапа, переноса отпускания и повторной команды.
- Восстанавливать безопасный HomeScreen после неизвестного состояния сессии.
Критерии приёмки этапа:
- весь сценарий проходится на mock без реального COM-порта;
- назад, отмена и каждый таймаут приводят к определённому состоянию;
- быстрые повторные касания не создают две сессии и не дублируют выдачу;
- все экраны используют текущую тему и не владеют бизнес-логикой.
- портретный UI соответствует композиции референса, нативно рендерится в 720×1280 и масштабируется на панели 9:16;
- промо-ролик не продолжает декодироваться вне HomeScreen и имеет рабочий fallback.
Этап 3. Протокол контроллера и симулятор оборудования — завершён
Цель: отделить строковый протокол от транспорта и проверить все ветки сценария.
Условие входа выполнено: владелец проекта добавил в references/ документацию контроллера 2.3.5 и список команд. Этап закрывает документированный wire-профиль и безопасное поведение для отсутствующих форматов. Production-команда силового канала, физические номера входов и проверка AES на плате относятся к последующей аппаратной интеграции и не подменяются предположениями.
- Изучить спецификацию универсального контроллера 2.3.5 и описать поддерживаемую часть в
docs/hardware/PERIPHERY_CONTROLLER_2_3_5.md. - Реализовать ASCII-фрейминг по
CR/LFс лимитом буфера, минимальной длиной и timeout 100 мс. - Реализовать типизированные команды авторизации, оплаты, отмены, status-запросов и legacy-хоппера; отсутствующий production-профиль силового канала представлен явным безопасным
Unsupported. - Реализовать типизированные ответы startup-баннера
periphery controller ver_<version>,CHAL,RAES,AUTH_PC_OK,AUTH_CNT_OK, точногоREADY!,MONEY:*,HOPPER1 APPEND/OK/ERROR/CREDIT/PULSE, совместимые ответы второго хоппера,SERVICE,INPUTи обобщённые ошибки; недокументированные status/heartbeat-ответы безопасно классифицируются как неизвестные. - Привязать подтверждённые входы новой прошивки: active-low
IN8публикует сервисный запрос по одному фронту,IN1задаёт бинарный запас первого хоппера,IN4— второго.IN24сохранён как физический датчик первого канала, но runtime считает подтверждения строками платы; оба канала30X/40Xвключены и остаются конфигурируемыми. - Добавить бинарное состояние запаса
Enough/Lowиз реальногоINPUT<bitmask>(вариант с пробелом тоже принимается) без вымышленного точного количества; до первого снимка либо при отключённом входе используетсяUnknown. - Добавить события принятой наличной суммы и обязательные подтверждения
ASK:COINS/BILL. - Добавить запуск/отмену Вендиста, keep-alive и
ApprovedпоMONEY:CASHLESS; несовпадение суммы даётDeclined, аCancelled/Timeoutвоспроизводятся доменным mock и таймером сессии, поскольку отдельных wire-сообщений в спецификации нет. - Связать действия с аппаратными последовательностями: наличные
162 → 141 → 151, остановка наличных142 → 152, подтверждение карточной суммы142 → 152 → 161 → 163<amount>, отмена/таймаут карты162; повторная отмена не засоряет FIFO одинаковыми командами. - Обработать частичные строки, несколько сообщений в одном чтении, timeout, переполнение, не-ASCII и неизвестные кадры.
- Добавить доменную таблицу типизированных ошибок и безопасных текстов; документированные hopper/transport/controller ошибки сопоставлены, неизвестные коды сворачиваются в безопасный
Unavailableбез утечки сырого кадра. - Сырые строки оборудования и внутренние исключения не передаются в пользовательский интерфейс.
- Mock покрывает успех, отказ, отмену, таймаут, disconnect, полную/частичную ошибку и задержку;
PeripheryControllerSimulatorдополнительно прогоняет настоящий handshake/parser, malformed-кадр, оплату, датчик и legacy-выдачу без COM-порта. - Добавлен debug-only режим ручной эмуляции оплаты, потери связи и ошибок выдачи.
- Зафиксировать at-most-once-политику выдачи: адаптер подавляет повторную команду и не выполняет retry после обрыва или ошибки; новая явная операция разрешена без перезапуска приложения.
- Для обоих хопперов отправлять пакеты
309N/409Nбез разделителя (1–99 жетонов), считатьAPPEND=Nподтверждением очереди и ждать N соответствующих кадровOK; послеERRORдождатьсяCREDIT=Nактивного канала и вернуть частичный результат. Большие выдачи разбиваются и маршрутизируются по раздельным учётным остаткам;3090/4090запрашивают остаток кредита.
Критерий выхода выполнен: все ветви конечного автомата воспроизводимы детерминированно без физического аппарата, parser/authenticator/simulator не зависят от Godot Node, а unsupported-возможности не активируются по предположениям.
Этап 4. Реальный Windows COM-порт — завершён
Цель: подключить аппаратный транспорт без нарушения потоковой безопасности Godot.
-
Реализовать открытие/закрытие
SerialPortс port name и параметрами протокола 115200 8N1/None. -
Реализовать отдельный worker-поток чтения/записи и механизм отмены.
-
Реализовать потокобезопасные очереди входящих событий и исходящих команд.
-
Публиковать события соединения и кадры только в главном потоке Godot через
ProcessPendingEvents(). -
Реализовать последовательную очередь отправки команд с окончанием
CRLF. -
Добавить read/write timeout и периодическую попытку повторного открытия порта с конфигурируемым интервалом.
-
Не выполнять автоматический повтор выдачи, если результат первой команды неизвестен.
-
Корректно отменять worker, закрывать и освобождать порт при выходе/перезапуске.
-
Программно обрабатывать исчезновение USB-COM и повторное открытие устройства; логика и 200 циклов симуляции проверены, физическая приёмка кабеля вынесена в раздел 4.1.
-
Не журналировать сырые кадры и секрет handshake; неизвестные/developer-кадры логируются только по категории.
-
Добавить атомарный сервисный индикатор
Disconnected/Authenticating/Ready/Faulted: в production штатныйReadyскрыт, а обрыв и ошибка видимы без раскрытия COM-порта и протокольных данных. -
Провести автоматический стресс-тест 200 последовательных переподключений с обрывом во время выдачи; команда не повторяется, отложенное подтверждение не принимается, переходы состояния не накапливаются.
-
Подготовить отдельный аппаратный NUnit-набор для платы: safe handshake/status/input/reconnect, ручные SERVICE/cash/sensor, отдельно подтверждаемые real payment, hopper и USB-cable сценарии с TRX-отчётом. Критерии приёмки этапа:
-
ни один фоновый поток не обращается к Godot API;
-
отключение кабеля не замораживает UI;
-
реконнект не создаёт лишних потоков и подписок;
-
выдача не дублируется после таймаута или обрыва связи;
-
приложение корректно закрывает порт.
Этап завершён: транспорт, потоки, reconnect, at-most-once и безопасное освобождение порта
реализованы и проверены автоматически; ранее COM3/framing/AES-handshake, INPUT, безопасные
status-запросы и три reconnect-цикла подтверждены на плате. Полная физическая приёмка автомата
ведётся отдельно по разделу 4.1 и не является незавершённой программной задачей этапа.
Этап 5. Полный MVP-сценарий автомата — завершён
Цель: интегрировать оплату, выдачу, обратную связь и пользовательские состояния.
- При выборе способа оплаты создавать уникальный локальный контекст операции и запись в журнале.
- Реализовать расчёт жетонов по цене и бонусным правилам для наличной и карточной веток.
- Блокировать начало оплаты при
Unknown; разрешать приEnoughиLow, не имитируя проверку несуществующего точного остатка. - Для наличной ветки обновлять баланс по типизированным событиям и явно определять момент начала выдачи.
- Для карточной ветки передавать выбранную сумму аппаратной границе и различать Approved/Declined/Cancelled/Timeout.
- На экране ожидания терминала разделить действия: верхняя кнопка «Назад» отменяет активный безналичный запрос и возвращает к выбору суммы, красная «ОТМЕНА» завершает сессию.
- Перейти в ожидание оплаты и принять только релевантный сигнал текущего состояния.
- Игнорировать просроченное подтверждение от предыдущей mock-сессии.
- После подтверждения оплаты один раз сформировать команду выдачи.
- Поддержать крупные тарифы: общее количество выдаётся последовательными пакетами
309N, следующий пакет отправляется после N кадровHOPPER1 OKпредыдущего. - Показывать состояние «Идёт выдача», не преждевременный успех.
- Обновлять прогресс/счётчик по каждому подтверждённому контроллером импульсу выдачи.
- Показывать «Получите жетоны» только после подтверждения завершения.
- Сопоставить ошибки с типизированными безопасными действиями
ReturnHome/TryAnotherPaymentMethod/ContactSupport. - Не показывать действие «Повторить» после ошибок: экран ошибки разрешает только возврат домой, смену способа оплаты либо обращение в поддержку и никогда не повторяет выдачу.
- Логировать начало и единственный итог с локальным
OperationIdбез платёжных секретов; отсутствующий в протоколе transaction ID не эмулируется и не используется для небезопасной сверки. - Выполнить автоматический сброс после успеха и управляемый сброс после ошибки.
- При старте закрывать незавершённые локальные записи как
UnknownAfterRestartбез автоматического retry; при отсутствии документированного запроса статуса операция не повторяется.
Критерий готовности MVP выполнен программно: полный сценарий от Home до подтверждённой выдачи
проходит через типизированный mock и детерминированный wire-симулятор, а известные ошибки
завершаются безопасным и понятным состоянием. Сквозная физическая проверка на автомате вынесена
в раздел 4.1.
Этап 6. Киоск-режим, настройки и эксплуатационная надёжность — завершён
Цель: подготовить приложение к работе без постоянного оператора и дать авторизованному сервисному персоналу безопасный способ изменять эксплуатационные параметры без ручного редактирования JSON.
- Настроить borderless fullscreen и скрытие курсора в production.
- Подготовить инструкцию Windows kiosk/shell setup для блокировки системных действий.
- Добавить автоматический запуск приложения после входа/загрузки Windows.
- Добавить watchdog/перезапуск процесса средствами ОС.
- Добавить обработку потери фокуса, смены разрешения и состава дисплеев.
- Не позволять пользовательскому вводу открывать debug/service функции:
F10работает только в debug-сборке изHome, production-вход начинается только с аппаратногоSERVICE. - Реализовать защищённый PIN-вход в сервисный режим с лимитом попыток и временной блокировкой; единый PIN включается и впервые задаётся внутри приложения, в конфигурации хранится только PBKDF2-хеш с солью.
- Исключить из настроек владельца версию, тему/DLC, порт и контроллер, окно/FPS, диагностику, журналы и тестовую выдачу; технические параметры оставить только в deployment-конфигурации.
6.1. Редактор настроек программы
- Провести инвентаризацию
AppSettingsи разделить параметры на операторские, инженерные, debug-only и секретные; AES-ключ, платёжные секреты и сырые команды контроллера никогда не показывать и не сохранять через UI. - Ввести единый
SettingsService/репозиторий конфигурации: экраны работают с валидированной рабочей копией и неизменяемым активным снимком, а не записывают JSON напрямую. - Создать атомарный экран настроек владельца внутри защищённого режима с пятью разделами: «Общие», «Звук», «Промо», «Тарифы» и «Оплата».
- Добавить общую громкость 0–100%, mute и отдельную громкость промо-ролика; применять значения через выделенные Godot audio buses и сохранять их в пользовательской конфигурации.
- Добавить безопасную кнопку проверки звука, которая не запускает оплату, выдачу или полноразмерный промо-ролик.
- Сделать редактируемой стоимость одного жетона
TokenPriceRubles; показывать рядом предварительный расчёт количества жетонов для типовых сумм и запрещать нулевое/отрицательное значение. - Реализовать редактор дополнительных жетонов
BonusRules: строки «минимальная сумма → бонусные жетоны», добавление, удаление и изменение правил, сортировка порогов, запрет дублей и отрицательных значений. - Явно зафиксировать в UI семантику бонусов: применяется одно максимальное подходящее правило, бонусы разных строк не суммируются; до сохранения показывать итог «базовые + бонусные» для контрольных сумм.
- Реализовать настройку карточных пресетов: добавление/удаление сумм, сортировка, отсутствие
дублей, максимальная сумма и шаг ручного ввода; валидировать суммы относительно цены жетона и
правил
PricingPolicy. - Добавить отдельное включение/отключение наличной и карточной оплаты; не позволять сохранить конфигурацию, в которой отключены оба пользовательских способа оплаты.
- Сделать настраиваемыми пользовательские таймауты бездействия, ожидания оплаты и показа результата в безопасных пределах; рядом объяснить влияние каждого параметра.
- Добавить редактирование названия автомата, подзаголовка и телефона поддержки с ограничениями длины и preview итогового текста.
- Добавить настройки промо: включение, список промо-роликов, poster, fallback-текст, mute и громкость; проверять существование и допустимость локальных путей до сохранения.
- Добавить экранный ввод для настроек: RU/EN/спецсимволы для текстовых полей, отдельную
цифровую клавиатуру для
SpinBox, Shift, каретку, удаление/очистку и кнопку скрытия справа сверху; автоматически поднимать активное поле над клавиатурой и применять число при выходе. - Оставить путь к внешнему DLC,
ReducedEffects, журналирование, параметры окна, mock-режим, COM-порт и соединение только в deployment-конфигурации, полностью исключив их из UI владельца. - Выделить аппаратную deployment-конфигурацию в отдельный
user://config/technical_settings.toml: основной порт, безопасные параметры связи, наличие обоих хопперов, их входы/полярности и сервисная кнопка валидируются целиком и применяются только после перезапуска; при повреждении пользовательского файла используется встроенный mock-профиль. - Не давать изменять тарифы, бонусы, способы оплаты, тему и аппаратные параметры во время активной операции; открытая сессия всегда завершается со снимком настроек, с которыми началась.
- Реализовать валидируемое автосохранение с debounce 0,5 с: промежуточный некорректный ввод
не записывается, ошибки остаются рядом с полями, а повторный фронт
IN8сохраняет ожидающие допустимые изменения и закрывает настройки. Экранная кнопка «Сохранить и выйти» в неподвижном нижнем футере использует тот же безопасный путь завершения редактирования. - Сохранять
appsettings.jsonатомарно через временный файл и замену, перед изменением держать последнюю корректную резервную копию и автоматически восстанавливаться после повреждения. - Валидировать весь набор настроек до записи и показывать ошибки рядом с конкретным полем; частичное применение некорректной конфигурации запрещено.
- Разделить параметры на применяемые немедленно и требующие перезапуска; после автосохранения показывать понятный статус и не выполнять самопроизвольный restart во время операции.
- Добавить безопасный журнал изменения конфигурации: дата/время, роль, раздел и факт изменения без старого/нового секретного значения, полного пути, платёжных данных и сырых кадров контроллера.
- Покрыть нормализацию, граничные значения, round-trip JSON, миграцию версии, резервную копию, бонусные правила и запрет изменения активной операции unit/integration-тестами.
- Провести runtime-проверку редактора владельца на 1080×1920 и 720×1280: пять доступных вкладок, отсутствие технических панелей, тач-действия, PIN-клавиатура и длинные/некорректные значения; собственные текстовая и цифровая клавиатуры проверяются в fallback и внешней теме, а работа пальцем и в перчатках остаётся физической приёмкой Этапа 8.
Критерий готовности настроек: владелец может безопасно изменить звук, цену жетона, бонусы, карточные суммы, доступность способов оплаты, таймауты, поддержку и промо; после перезапуска значения сохраняются, повреждённый файл восстанавливается, а начатая операция никогда не меняет тарифы или аппаратную конфигурацию посередине сценария.
6.2. Эксплуатационная надёжность
- Добавить очистку/ротацию старых логов и ограничение объёма
user://. - Проверить восстановление после повреждения конфигурации, обрыва питания во время записи и несовместимой версии файла без потери последней корректной резервной копии.
- Добавить ускоренную модель 24 часов (1440 минут, 480 выдач), стресс 10 000 жизненных циклов
SessionFlowи процессный runner для 24-часового прогона; runner проверен минутным прогоном 12/12 сэмплов, пик working set 217.73 МБ. Реальный 24-часовой прогон переносится в физическую приёмку Этапа 8, поскольку целевой ПК пока отсутствует.
Этап 7. Производительность, UX и доступность — выполняется
Цель: обеспечить стабильные 60 FPS и понятный интерфейс на целевом оборудовании.
- Локальный baseline FPS, CPU-времени, памяти и draw calls зафиксирован
(
docs/operations/PERFORMANCE_BASELINE.md); повтор на автомате вынесен в раздел 4.1. - Проверить статический fallback-фон и актуальный
space-pixelв полном/облегчённом режимах: decoration переключается1 → 0 → 1, сохраняются 60 FPS, draw calls снижаются с 26 до 24. - Перевести production-темы на доверенный runtime: разрешить theme-owned GDScript и стандартные Godot-узлы без прежнего decoration budget, лимитов узлов/кадров/FPS/скорости или размера PCK; сохранить строгую проверку namespace, manifest, экранов, биндингов и запрет подмены ресурсов host.
- Отключать обработку всех скрытых экранов через
ProcessMode.Disabledи включать её только для текущего экрана; переход Home → Settings проверен в runtime. - Добавить явную прокрутку Settings перетаскиванием одним пальцем и зажатой ЛКМ; обработчик использует deadzone 12 px, не перехватывает короткое нажатие и не зависит от того, передал ли вложенный Control drag штатному ScrollContainer. Физическая приёмка остаётся в 4.1.
- Проверить контраст normal/pressed/disabled/error/success во fallback и
space-pixel; CheckButton дополнительно получил тёмный текст и встроенные крупные ON/OFF-индикаторы. - Убрать зависимость от hover и мелкие интерактивные элементы: все девять экранов пройдены runtime-аудитом, цифровые клавиатуры имеют равные крупные колонки, логика не использует hover.
- Синхронизировать runtime-композицию с девятью preview-сценами
space-pixel: перевести host на нативную сетку 720×1280, перенести геометрию панелей и подключить безопасные именованные visual slots. - Перевести DLC-контракт на manifest v2 с полными визуальными сценами всех девяти экранов, app-owned контроллерами, стабильными element binding-id и обратно совместимым v1 fallback.
- Реорганизовать
ExchangerThemeDlcBuilderвthemes/exampleиthemes/<theme-id>, добавить валидатор имён/типов/биндингов и preview-overlay, показывающий binding-id каждого элемента. - Адаптировать host к самодостаточным production-сценам Builder: проверять metadata, собственный
Theme/фон/decoration, единый режим всех девяти экранов и отсутствие дублирующих глобальных слоёв;
при
ReducedEffectsскрывать и отключать обработку толькоBackgroundDecoration, не ограничивая остальную доверенную runtime-логику темы. - Запретить host переоформлять самодостаточные сцены: Settings больше не назначает внешним
узлам
WhitePanel/семантические variations, keypad-контроллеры не меняют их размеры и стили,ThemeManager.ApplyToоставляет Theme/геометрию полноэкранного view нетронутыми. - Убрать runtime-достраивание самодостаточных сцен: Home, карточные суммы и изменяемые списки Settings работают с готовыми узлами и фиксированными слотами темы; host только подключает события и передаёт функциональные значения, не добавляя и не удаляя Control-узлы.
- Добавить в Settings theme-owned текстовую и цифровую клавиатуры: 57 новых биндингов,
состояния preview
OFF/TEXT/NUM, неизменяемое визуальное дерево и общую C#-логику поля ввода; каталог DLC расширен до 460 обязательных биндингов. - Добавить владельцу раздел «Сервис» с отдельным атомарным учётом остатка, ручным добавлением через двойное подтверждение и списанием только фактически подтверждённых выдач.
- Реализовать автоматический пересчёт прямыми командами
301/300или401/400: считать толькоHOPPER1/2 PULSE=1, не дублировать учёт поINPUT, завершать после 10 секунд тишины, позволять исправить результат перед записью и безопасно останавливать мотор при отмене/закрытии. - Расширить self-contained theme-контракт сервисными и четырьмя состояниями индикатора запаса до 477 элементов; template
и
space-pixelсодержат готовые Service-панель и диалог, host меняет только значения и события. - Проверить деградацию при временной просадке FPS: таймауты используют монотонное реальное время и завершаются корректно даже при единственном обновлении после скачка на 120 секунд.
Программные ограничения, профили эффектов и локальный baseline реализованы. Проверка критерия 60 FPS, панели и декодера промо на автомате ведётся централизованно в разделе 4.1.
Этап 8. Тестирование и контроль качества — выполняется
Цель: сделать регрессии воспроизводимыми до установки на автомат.
- Выбрать C# test runner: NUnit 4 для чистого доменного ядра и проверок файлов проекта.
- Конфигурация, тарифы, валидация суммы, переходы
SessionFlow, framing, parser и handshake покрыты unit-тестами. - Добавить интеграционные тесты
SessionFlow + IMachineController test double; productionMockMachineControllerдополнительно проверять в Godot runtime. - Добавить автоматическую проверку наличия/заголовков всех сцен, валидатор manifest DLC и runtime smoke-загрузку каждого экрана через Godot Editor.
- Добавить тесты таймаутов с управляемым источником времени, без реального ожидания 120 секунд.
- Проверить duplicate action, повторный
DISPENSE, поздние события, disconnect/reconnect и неизвестные/malformed wire-ответы. - Проверить полные наличный и безналичный wire-сценарии от действия сессии до
ASK:*, выключения приёмников и выдачи; отдельно проверить пакет 515 жетонов как пять30999и один30920, подтверждённые соответствующим числомHOPPER1 OK. - Проверить отсутствие накопления подписок и стабильность многократных последовательных сессий.
- Проверять C#-сборку и NUnit-набор после каждого завершённого блока.
- Проверять Godot editor/game logs после изменений сцен и ресурсов.
- Составить ручной чек-лист приёмки на физическом аппарате. Физические проверки панели, SERVICE, дисплея и 24-часовой soak вынесены в раздел 4.1.
Этап 9. Сборка, установка и обновление Windows-версии — выполняется
Цель: получить воспроизводимый устанавливаемый релиз.
- Создать export preset Windows x64 и воспроизводимый staging-сборщик.
- Проверить включение self-contained .NET runtime,
GodotSharp.dllиSystem.IO.Ports.dll. - Явно исключить
references/, тесты, документацию, инструменты и dev-only addons из production-экспорта; в проверенной сборке нет test DLL и addon-файлов. - Проверить
res://иuser://коротким headless smoke-run экспортированного EXE (exit code 0). - Исправить one-EXE runtime: встроенные JSON/TOML материализуются через Godot
FileAccess,config/*.tomlвключается в PCK, а runtime-autoload GodotxToast не удаляется export-фильтром. - Проверить итоговый one-file release: каталог
artifacts/windows/test_qсодержит ровно одинExchanger.exeразмером 190229328 байт; packaged mock и COM3 smoke завершились без ошибок. - Определить расположение пользовательской конфигурации и логов для сервисного персонала.
- Добавить номер версии сборки в UI сервисного режима и журналы.
- Подготовить сценарий установки, обновления и отката.
- [~] Добавить цифровую подпись: текущий EXE подписан самоподписанным сертификатом
CN=Robotailс timestamp DigiCert; остаётся определить production-модель доверия и установить доверенный корень на целевые устройства либо использовать сертификат доверенного CA. - Зафиксировать контрольную версию конфигурации контроллера и приложения.
Чистая установка и проверка релиза на целевом устройстве вынесены в раздел 4.1.
Этап 9.1. Linux x86_64 для Debian 13 — выполняется
Цель: перенести desktop runtime на Debian без изменения UI, бизнес-логики и wire-протокола.
- Добавить Godot export preset
Linux x86_64 (Debian 13)с production-фильтрами Windows-пресета. - Встроить PCK и managed build outputs; актуальный self-contained ELF x86_64 имеет размер
155351952 байта, RID
linux-x64и nativeSystem.IO.Ports. - Проверить заголовок артефакта: ELF64, AMD64/x86_64.
- Разрешить в технической конфигурации
/dev/ttyUSB*,/dev/ttyACM*и стабильные/dev/serial/by-id/*, сохранив строгую валидацию Windows COM-портов. - Собрать отдельный Linux Debug ELF с расширенной безопасной диагностикой UART и handshake, не перезаписывая release-артефакт.
- Подготовить udev/dialout и доступ сервисного пользователя к USB-UART.
- Подготовить Linux kiosk/autostart/watchdog и процедуру обновления/отката. Физический запуск и приёмка на Debian 13 вынесены в раздел 4.1.
Этап 10. Подготовка Android-порта после MVP
Цель: заменить платформенный транспорт без переработки UI и бизнес-логики.
- Выбрать и согласовать USB-Serial Android-плагин.
- Реализовать
UsbSerialHardwareза существующимIHardwarePort. - Добавить запрос USB permission и обработку переподключения устройства.
- Проверить ограничения Android kiosk/lock task mode.
- Адаптировать пути конфигурации/логов и жизненный цикл pause/resume.
Физическая Android-приёмка целевого ARM64-устройства вынесена в раздел 4.1.
8. Сквозные требования к реализации
- Все новые скрипты по возможности пишутся на C#.
- Скрипты Godot Node/Resource объявляются как
partial class. - Комментарии в C# ведутся единообразно; для проекта выбран русский язык документации и пояснений сложной логики.
- Экраны не открывают порт, не парсят аппаратные строки и не управляют потоками.
- Ресурсы экранов и компонентов хранятся атомарно в соответствующих папках.
- Пути тем и экранов централизованы в реестрах/конфигурации.
- Сигналы и подписки освобождаются при завершении жизненного цикла узла.
- Таймауты и переходы состояний должны быть детерминированы и тестируемы.
- Новые внешние зависимости и NuGet-пакеты добавляются только при фактической необходимости; разрешение владельца на необходимые NuGet-пакеты получено, назначение и версия каждой зависимости фиксируются в документации.
- После существенных изменений обновляются этот ROADMAP, документация и
agentmemory.
9. Основные риски и меры снижения
| Риск | Последствие | Мера снижения |
|---|---|---|
| Неопределённый протокол контроллера | Переделка транспорта и сценария выдачи | Зафиксировать протокол и реальные примеры обмена до интеграции COM |
Повтор DISPENSE после обрыва |
Двойная выдача жетонов | Transaction ID/статус операции; запрет слепого retry |
| Поздний ответ от старой сессии | Выдача не тому сценарию | Идентификатор и поколение сессии, сброс входного контекста |
| UI обращается к Godot из COM-потока | Падения и гонки | Queue/CallDeferred, строгая граница транспорта |
| Слабый GPU | Просадки FPS и задержки тача | Compatibility, лимиты эффектов, fallback-фон, профилирование |
| Ожидание, что Godot заблокирует Alt+Tab | Выход пользователя из киоска | Настройка Windows Assigned Access/Shell Launcher |
| Несовместимый или повреждённый DLC темы | UI не может загрузить внешние ресурсы | Версионированный .pck, строгий manifest и программная fallback-тема |
| Неограниченные логи | Заполнение диска | Ротация, лимит размера и срока хранения |
| Android-зависимости проникают в UI | Дорогой порт | IHardwarePort и platform-specific composition |
| Неясный результат операции при аварии | Финансовая/операционная ошибка | Журнал транзакций, запрос статуса, безопасный сервисный сценарий |
| Текущий UI остаётся ландшафтным | Несоответствие реальному корпусу | Первым шагом Этапа 2 перейти на 1080×1920 и провести визуальную QA 720×1280 |
| Промо-ролик декодируется всегда | Лишняя нагрузка и просадки FPS | Останавливать плеер вне HomeScreen, ограничить формат/разрешение, иметь постер |
| Референсные цифры приняты за спецификацию | Неверные тарифы и бонусы | Хранить всё в конфигурации и запросить подтверждение владельца |
| Референсные ассеты попали в релиз без прав | Лицензионный риск | references/ в .gitignore; исключить каталог в export preset и использовать только подтверждённые production-исходники |
10. Вопросы для владельца продукта
- [?] Подтвердить цену жетона: 10 рублей в референсе или другое production-значение.
- [?] Подтвердить таблицу бонусов, включая пример «100 + 50 в подарок».
- [?] Подтвердить карточные пресеты 10/50/100/150/200/300/400/500 рублей и предел другой суммы.
- [?] Есть ли выдача сдачи/возврат наличных и что происходит при отмене наличной операции?
- [?] Что именно запускает кнопка «Выдать» на домашнем и наличном экранах?
- [?] Кто является источником подтверждения оплаты и в каком формате приходит событие?
- [?] Может ли контроллер подтвердить фактический результат выдачи, включая частичную выдачу?
- [?] Поддерживает ли протокол идентификатор транзакции и запрос статуса последней операции?
- [?] Что должен делать автомат после подтверждённой оплаты и частичной/неуспешной выдачи?
- [?] Нужны ли возврат средств или обращение к оператору, и кто их выполняет?
- [?] Требуется ли локальное хранение истории операций и каков срок хранения?
- [?] Нужны ли удалённая диагностика, телеметрия или выгрузка логов?
- Сервисный вход открывается по аппаратному
SERVICE; опциональный единый PIN настраивается в приложении при первом входе, матрица разрешений зафиксирована вdocs/operations/SETTINGS_ACCESS_MATRIX.md. - [?] Подтвердить финальные бренд, логотип, телефон, персонажа и права на референсные материалы.
- [?] Уточнить форматы промо-роликов, плейлист, звук и способ обновления контента.
- [?] Требуется ли локализация кроме русского языка?
- [?] Какой максимально допустимый простой и кто отвечает за автоматический перезапуск?
11. Ближайший рабочий пакет
Этапы 0–6 закрыты. Этапы 7, 8, 9 и 9.1 остаются в работе. Все проверки, требующие физического автомата, собраны в разделе 4.1. Ближайший программный пакет:
- Подготовить установку, обновление и откат Windows-релиза.
- Определить production-модель доверия цифровой подписи.
- Зафиксировать контрольную пару версий приложения и прошивки.
- Подготовить udev/dialout и доступ сервисного пользователя к USB-UART в Debian 13.
- Подготовить Linux kiosk/autostart/watchdog и процедуру обновления/отката.
Аппаратная очередь не дублируется здесь и полностью ведётся в разделе 4.1.
12. Журнал прогресса
2026-09-07 — Формат «К ВЫДАЧЕ» унифицирован для наличной и карточной оплаты
- Готовая и ручная карточная сумма показывают базовые жетоны слева и бонус отдельно справа:
+ N ЖЕТОНОВ\nВ ПОДАРОКлибоБЕЗ БОНУСА; длинная объединённая строка больше не используется. - Заголовок
БАЛАНС ЖЕТОНОВна экране наличной оплаты заменён наК ВЫДАЧЕ. - Для отдельного бонуса CardAmount добавлен supplemental runtime binding с побиндинговым fallback; immutable JSON-каталог сохраняет 481 ID и прежний SHA-256. Документация Theme Builder и обе внешние темы синхронизированы отдельно.
- Debug-сборка проходит без предупреждений, 487/487 NUnit-тестов, встроенная тема и свежие PCK
проходят headless
PaymentRewardFormattingSmokeна mock-оборудовании без обращения к COM/UART. - Предыдущий установленный
space-pixelтакже проходит compatibility-smoke: отсутствующий новый CardAmount Bonus подключается как один встроенный fallback binding без отказа всего DLC. - Builder contract/validator/preview/PCK smoke и визуальный QA
720×1280прошли для обеих тем. Новые пакеты:example.pck— 464876 байт, SHA-25602B8505FB7F0EF4F4E9C2905D97E8F8751A1DDE86DDF460AFC958CCE6AF51994;space-pixel.pck— 1436988 байт, SHA-2564D9AA00FE2096794331B348916D1766B47A45D9EDFEE60BEAB0E424ED4761A67. Пользовательскийactive_theme.pckне заменялся.
2026-09-07 — Учёт жетонов и ограничение покупки разделены
- В разделе «Сервис» появились два включённых по умолчанию переключателя: ведение точного учёта и независимый запрет покупки сверх остатка с учётом бонуса. При отключении самого учёта скрываются точные остатки, кнопки пересчёта/добавления и приблизительное число на Home; сохранённый файл остаётся для последующего восстановления режима.
- Если учёт включён, а ограничение выключено, остатки остаются видимыми и продолжают списываться, но не блокируют оплату. При включённом ограничении карточная сумма отклоняется до запроса терминалу, наличная — до команды выдачи; пресеты и ручной ввод показывают тот же лимит.
- Выключенный режим не списывает сохранённый остаток;
DualHopperAutoиспользует hopper 1 и сохраняет последовательное разбиение по 99 без автоматического failover. - Конфигурация повышена до версии 23. Новые элементы темы оформлены в Builder как supplemental runtime bindings; immutable JSON-каталог остаётся на 481 ID с прежним SHA-256.
- Debug/Release проходят 483/483 NUnit-теста. Встроенная тема и предыдущие
example.pck/space-pixel.pckпрошли отдельный runtime-smoke без реального COM/UART; проверка на автомате добавлена в раздел 4.1. Старые PCK получают новый переключатель побиндинговым fallback. - Свежие Builder-пакеты прошли contract/validator/preview/PCK smoke, визуальную проверку
720×1280и host runtime-smoke без fallback-подстановок:example.pck—464268байт, SHA-256AC03334354D285E36A25BFB81D60880F829700F083AF5D728F10AB15C764B63D;space-pixel.pck—1436492байта, SHA-256166660916913E4766FC91437155BB8B78A405150B3A599CF401CD78A83DFB727. Установленный пользовательскийactive_theme.pckне заменялся.
2026-09-07 — Упрощён раздел общего текста в настройках
- Поле «Название» скрыто, «Короткий текст» переименован в «Свой текст», отдельный branding-preview удалён из отображения раздела «Общие».
Branding.ApplicationNameсохранён в модели и JSON для обратной совместимости, но больше не редактируется и не может скрытой ошибкой заблокировать сохранение формы владельца.- Binding ID, пути, типы и fallback не менялись: legacy-узлы остаются скрытыми контрактными слотами, поэтому версия и SHA-256 binding-каталога не изменяются.
- Встроенная сцена,
exampleиspace-pixelсинхронизированы. Debug/Release unit-наборы прошли по460/460; host runtime-smoke прошёл для встроенной темы и новогоspace-pixel.pck, а обе DLC-темы прошли Builder contract/validator/preview/PCK smoke и визуальную проверку720×1280. - Новые пакеты:
example.pck—463324байта, SHA-25625E90059652EC26BD1779F7D6761F1CD1248A458F8C93F8E242596D3988FDE9F;space-pixel.pck—1435548байт, SHA-256E5941A4E7437BA996945E85551714F8B6E11F77A64808C68B29A8B88F66629AB. Активная пользовательская тема автоматически не заменялась.
2026-09-04 — Сниженная высота питомца оставлена только для sitting
- Theme-owned компонент
space-pixelсохраняет локальную поправку(0,0)дляsittingи применяет(0,-24)ко всем другим анимациям. Root, navigation, hit box иGROUND_OFFSET=(64,96)не меняются. - Builder verifier подтвердил переход
(0,0) → (0,-24) → (0,0)и неподвижность root; contract, validator, preview smoke, build и PCK verifier прошли. Preview720×1280учитывает union-envelope состояний и подтвердил Nearest без clipping/пересечения с заголовком. - Полный host
InteractivePetBehaviorSmokeс явным новым PCK и mock-оборудованием прошёл: drag/drop, поверхности и production-loader сохранили прежнее поведение. - Новый PCK: 1435452 байта, SHA-256
390C9E3F83B026304F0E75E5A6AAD4458684BBCDFC847FFB542B6CFB1AC278E9; активная пользовательская тема автоматически не заменялась.
2026-09-04 — Питомец space-pixel увеличен на 30%
- Theme-owned
RUNTIME_SCALEизменён с0.65на0.845; host-код и сцены Exchanger не переделывались. Точка лап и hit-area масштабируются существующей общей формулой. - Builder contract/test/validator/preview smoke/build и PCK verifier прошли; preview
720×1280подтвердил Nearest без clipping. Новый PCK: 1435004 байта, SHA-25660E41BA7C1043348AB7C3FEED72C352AE3FBFA58BDACB00F4036F1CD0EB56088. - Production-loader Exchanger и полный
InteractivePetBehaviorSmokeс явным новым PCK прошли на mock-оборудовании: drag/drop, поверхности, смена сцен и четыре танца сохранены.
2026-09-04 — Физическая сервисная кнопка сохранена поверх клавиатуры
- Блокировка «Сохранить и выйти» ограничена её экранным обработчиком и GUI hit-test футера.
Аппаратный
ServiceRequestedпо-прежнему напрямую вызываетTryFinishEditing(). - Повторное физическое нажатие при открытой клавиатуре закрывает её, завершает сохранение и возвращает Home по прежнему маршруту; незавершённые сервисные операции всё ещё блокируют выход.
- Runtime-smoke воспроизводит физическое нажатие через общий debug-action при открытой клавиатуре на встроенной и установленной DLC-темах. Debug/Release без предупреждений, NUnit — 459/459.
2026-09-04 — Футер больше не блокирует нижний ряд экранной клавиатуры
- Установлено, что
Button.Disabledне исключает кнопку и родительскую панель из hit-test, поэтому перекрывающая геометрия фиксированного футера перехватывала физические нажатия нижнего ряда. - Пока клавиатура открыта, футер и «Сохранить и выйти» используют
MouseFilter.Ignore; после её закрытия восстанавливаются исходные фильтры, а обработчик выхода остаётся защищён отдельно. - Runtime-smoke проверяет реальный GUI hit-test нижних клавиш обеих панелей и координатный клик текстовой клавиши. Встроенная и установленная DLC-темы прошли; Debug/Release без предупреждений, NUnit — 458/458.
2026-09-04 — Ввод экранной клавиатуры применяется без задержки
- Исправлена рассинхронизация, при которой вставленный экранной клавиатурой текст был виден в
LineEdit, но не попадал в рабочую копию Settings до первого удаления. - Каждая операция вставки, удаления, очистки и замены выделения теперь формирует ровно одно
уведомление
TextChanged; числовое поле дополнительно немедленно применяет значениеSpinBox. - Runtime-smoke контролирует событие после первой буквы и после каждой введённой цифры на встроенной и установленной DLC-темах. Debug/Release: 0 предупреждений, NUnit — 458/458.
2026-09-04 — Выход из Settings заблокирован поверх экранной клавиатуры
OnScreenKeyboardControllerсообщает об открытии и закрытии любой своей панели; фиксированная кнопка «Сохранить и выйти» отключается синхронно с этим состоянием.- Обработчик выхода отдельно проверяет фактическую видимость клавиатуры и игнорирует программное
нажатие, даже если состояние
Button.Disabledбыло обойдено. - Runtime-smoke проверяет текстовую, обычную цифровую и сервисную цифровую клавиатуры на встроенной и установленной DLC-темах. Debug/Release собраны без предупреждений, NUnit — 458/458.
2026-09-04 — Переподключение платы переведено на технический интервал 30 секунд
- Подтверждено, что авторитетный параметр уже находился в
[controller].reconnect_interval_seconds; шаблон и активная локальная конфигурация изменены с 5 на 30 секунд, остальные монтажные параметры не затронуты. - При отсутствии платы после первой немедленной попытки порт повторно открывается каждые 30 секунд. После обрыва работавшего транспорта отсчёт начинается заново от момента обнаружения обрыва, поэтому устаревший стартовый дедлайн больше не вызывает немедленный reconnect.
- Планировщик повторно ставит дедлайн после каждой неудачной попытки; оплату и выдачу не повторяет. Оба сценария покрыты детерминированными unit-тестами без COM/UART.
- Debug/Release собраны без предупреждений, NUnit — 458/458; headless mock подтвердил фактическую
загрузку
reconnectSeconds=30из текущего пользовательского TOML.
2026-09-04 — Ручной ввод суммы получил однозначное удаление цифры
- Левая кнопка нижнего ряда CardCustomAmount переименована из «ОТМЕНА»/«СБРОС» в «СТЕРЕТЬ» и
удаляет только последнюю введённую цифру; после удаления последней цифры экран показывает
0. - Legacy binding
clear_buttonсохранён ради совместимости, а отдельный обязательныйbackspace_buttonскрыт, чтобы в интерфейсе не было двух одинаковых действий. - Runtime-smoke подтвердил последовательность
12 → 1 → 0на старом установленном PCK; Debug/Release собраны без предупреждений, NUnit — 455/455. - Обе темы прошли Builder validator/preview/build/PCK verify. В
space-pixelнадпись полностью помещается при 720×1280; новый PCK прошёл production-loader приложения на mock-оборудовании.
2026-09-04 — В Settings добавлен фиксированный футер сохранения
- Кнопка «Сохранить и выйти» вынесена из прокручиваемого содержимого в закреплённый нижний футер; drag по футеру не прокручивает список, а нижний зазор позволяет показать последние поля над ним.
- Кнопка завершает ожидающее атомарное автосохранение через общий
TryFinishEditing()и возвращает Home только после успеха; физическая сервисная кнопка сохраняет прежнее поведение. - Пока открыта текстовая или цифровая экранная клавиатура, кнопка отключена; обработчик также отклоняет программное нажатие, чтобы клавиатура не могла случайно инициировать выход.
- Для новых DLC добавлены supplemental bindings футера, кнопки и нижнего зазора. Старые PCK получают только эти отсутствующие элементы из встроенной темы-заглушки.
- Встроенная тема, ранее установленный PCK и новый полный
space-pixel.pckпрошли runtime-smoke на mock-оборудовании; Debug/Release собраны без предупреждений, NUnit — 454/454.
2026-09-04 — Добавлена побиндинговая обратная совместимость DLC-тем
- Отсутствующий обязательный binding больше не отключает весь DLC: runtime сначала принимает
совместимый узел старой темы по каноническому
FallbackPath, а при его отсутствии переносит готовый элемент встроенной темы-заглушки вместе с её оформлением. - Если точечно собрать экран невозможно, встроенным становится только этот экран; остальные корректные сцены внешней темы сохраняются. Неизвестные ID, дубли, неверные типы, root и повреждённый контракт по-прежнему отклоняются.
- Реальный ранее установленный
space-pixel.pckпринят без пересборки: Home восстановил один, Settings — четыре новых биндинга. Запуск прошёл на mock без обращения к COM/UART. - Release-сборка прошла без ошибок и предупреждений, NUnit — 452/452.
2026-09-04 — В сервис добавлено скрытие элементов домашнего экрана
- В новой панели «Скрытие элементов меню» независимо управляются учётный остаток жетонов, theme-owned персонаж справа и весь промо-блок; старые настройки мигрируют с показом всех трёх.
- Изменения автосохраняются и применяются к уже созданному Home без перезапуска приложения.
- Host меняет только видимость готовых узлов fallback/DLC. Скрытые остаток и промо исключаются вместе с маршрутами питомца, поэтому он не садится на невидимые поверхности.
- Обе темы прошли Builder validator/preview-smoke и PCK verifier; новый
space-pixel.pckдополнительно загружен production loader приложения на mock-оборудовании без ошибок. - Release-сборка прошла без ошибок и предупреждений, NUnit — 448/448.
2026-09-03 — Debug-сборка получила расширенную диагностику подключения платы
- Добавлен компилируемый только в Debug уровень
[DEBUG]; Release не содержит вызовов и строк расширенной диагностики. - Журнал фиксирует платформу и параметры UART, открытие устройства, reset DTR/RTS, запуск и завершение worker, безопасную причину транспортной ошибки, reconnect и переходы handshake.
- Сырые кадры, AES challenge/response, ключи и платёжные payload не выводятся; показываются только тип этапа, состояние, длина и безопасные счётчики.
- Runtime summary в разделе «Диагностика» Debug-сборки показывает transport/auth state.
- Debug и Release собраны без ошибок и предупреждений, обе конфигурации прошли NUnit 444/444;
Debug headless-smoke на mock подтвердил фактическую запись
[DEBUG]в журнал. - Собран отдельный Linux Debug ELF: 155630576 байт, SHA-256
A1FB92126D6ED753DF968180075D7409678E5F0A7C454CB6D2B954DC024682B6.
2026-09-03 — Последовательный порт адаптирован для Windows и Linux
- Общая валидация выбирает правила по фактической ОС процесса: Windows принимает только
COM1…COM256, Linux —/dev/ttyUSB*,/dev/ttyACM*и/dev/serial/by-id/*. - При
use_mock = trueимя порта не проверяется и безопасный общий шаблон сCOM3остаётся пригодным для mock-запуска Linux-сборки. SerialPortHardwareостался единым desktop-транспортом наSystem.IO.Ports; сообщения транспорта больше не привязаны к термину COM.- Unit-тесты отдельно покрывают обе платформенные ветки и недопустимые Linux-пути.
- Release-сборка прошла без ошибок и предупреждений, NUnit — 444/444.
- Linux release повторно экспортирован одним ELF64 AMD64-файлом размером 155351952 байта,
SHA-256
7312E79514842EB5EA3193604F71CAAE412654957640032B62D66E202802284C.
2026-09-02 — Экранная клавиатура подключена к ручному пополнению хоппера
- При открытии диалога «Добавить в хоппер» поле количества после появления модального слоя автоматически получает фокус, выделяет текущее значение и показывает цифровую клавиатуру.
- Контроллер клавиатуры учитывает, что сервисное поле находится вне основного ScrollContainer, и не пытается прокручивать скрытый список настроек.
- Сцены темы не менялись: host использует существующие binding-id поля, диалога и готовой theme-owned цифровой клавиатуры.
- Runtime-smoke открывает сервисный диалог, проверяет видимость клавиатуры и фокус поля, затем
закрывает оба слоя. Fallback и
space-pixel.pckпрошли с mock-оборудованием. - Сборка прошла без ошибок и предупреждений, NUnit — 410/410; 18 hardware-тестов пропущены.
2026-09-02 — Выдача двух хопперов переведена на строгий приоритет первого
- Для запроса
Nплан выдачи теперь всегда равенH1=min(N, остаток H1),H2=N-H1: второй хоппер используется только для недостающей разницы после первого. - Удалён прежний выбор стартового хоппера по датчикам уровня и сравнительному остатку, из-за которого выдача могла начинаться со второго хоппера.
- При недостаточном суммарном учётном остатке ни одна команда выдачи не отправляется. Аппаратная ошибка во время уже начатой выдачи по-прежнему не вызывает автоматический retry/failover.
- Mock приведён к тому же правилу и больше не создаёт фиктивное подтверждение сверх остатка.
- Интеграционный тест подтверждает последовательность
H1=6,H2=20, запрос10: сначала3096, после шестиHOPPER1 OK—4094, итоговый раздельный учёт(6, 4). - Для обоих хопперов отдельно закреплена последовательная пакетная выдача 205 жетонов:
30999 → 30999 → 3097либо40999 → 40999 → 4097.APPEND=Nне запускает следующий пакет; он отправляется только после всех 99OK. Смешанный план 180 при остатках(150, 50)даёт30999 → 30951 → 40930, не запуская второй хоппер раньше завершения первого. - Сборка прошла без ошибок и предупреждений, NUnit — 409/409 (18 hardware-тестов пропущены),
runtime-smoke с
space-pixel.pckи mock-оборудованием прошёл без binding-ошибок.
2026-09-02 — Исправлено склонение слова «жетон» в пользовательском потоке
- Добавлен единый форматтер русских окончаний:
1 жетон,2–4 жетона,5–20 жетонов, включая исключение11–14и повторяющиеся разряды (21,22,111,124). - Исправлены тексты выбора суммы, наличной оплаты, произвольной карточной суммы, ожидания терминала, прогресса выдачи и финального сообщения, в том числе количество подарочных жетонов.
- Внешние сцены не изменялись: host обновляет только динамический текст существующих Label.
- Сборка прошла без ошибок и предупреждений, NUnit — 395/395 (18 hardware-тестов пропущены),
runtime-smoke с
space-pixel.pckи mock-оборудованием прошёл без binding-ошибок.
2026-09-02 — Добавлен раздельный остаток жетонов по хопперам
- Settings показывает точный общий остаток и отдельные значения для хоппера 1 и хоппера 2;
данные берутся из сохранённого
TokenInventorySnapshotи обновляются после подтверждённой выдачи, пересчёта и ручного добавления. - Host использует существующие theme-owned
Hopper1Label/Hopper2Label; геометрия и оформление внешней темы приложением не меняются. - В контракт добавлены два Label-binding: всего 481 биндинг, SHA-256 каталога —
DDDC89118BEEA78A820561464001656136ED42AC1AD5710FB109D25ADAF44143. - Сборка прошла без предупреждений и ошибок, NUnit — 376/376 (18 hardware-тестов пропущены).
exampleиspace-pixelпрошли contract/validator/preview smoke; fallback и собранныйspace-pixel.pckпрошли host runtime-smoke с mock-оборудованием. Сервисная панельspace-pixelвизуально проверена в Theme Builder при720×1280без наложений и обрезания текста.
2026-09-02 — Windows Debug и Release разведены по отдельным пресетам
- Неоднозначный
Windows x64заменён наWindows x64 ReleaseиWindows x64 Debugс разными output-путями, custom features, console wrapper и настройками debug symbols/C# sources. tools/export-windows.ps1принимает-Configuration Release|Debug, по умолчанию собирает Release и передаёт Godot соответствующий--export-releaseлибо--export-debug.- Release создаёт
Exchanger.exe, Debug —Exchanger.Debug.exe; каталоги содержат конфигурацию и timestamp, поэтому варианты не перезаписывают друг друга. - Оба режима фактически экспортированы официальным Godot 4.7.1 Mono и прошли packaged headless smoke с mock-оборудованием: Debug содержит основной EXE и console wrapper, Release — один EXE. Контрольные файлы не подписаны; Authenticode остаётся отдельным release-шагом.
2026-09-02 — Разделены таймауты наличной и безналичной оплаты
- Конфигурация v20 получила независимые
CashPaymentSecondsиCashlessPaymentSeconds; прежнийPaymentSecondsмигрируется без потери значения, а наличный таймаут наследует прежнийSessionIdleSeconds. SessionFlowиспользует наличный таймаут на экране приёма денег и продлевает его при активности или изменении баланса; ожидание карточного терминала использует отдельный безналичный таймаут.- В Settings добавлены два самостоятельных поля с отдельной валидацией. Fallback,
exampleиspace-pixelсодержат готовые theme-owned элементы; C# только подключает их по биндингам. - Host-контракт синхронизирован до 479 биндингов и одновременно закрыл прежний блокер
card_terminal.content.top_bar.back_button; SHA-256 каталога —B33F34A50837560AF8C3589B3E0AA19BB03B7B534AF6A27001C4FA19DE4155BF. - Release/Debug собираются без предупреждений, NUnit — 372/372. Обе темы прошли contract,
validator и preview smoke; установленный
space-pixelпрошёл Exchanger headless smoke с mock-оборудованием без binding-ошибок и без доступа к реальному COM.
2026-09-02 — CardTerminal «Назад» возвращает к выбору суммы
- Host подключает существующий binding верхней кнопки
BackButton, не изменяя сцену внешней темы. - Перед возвратом из
CardTerminalWaitвызываетсяCancelActiveOperation(), поэтому Вендист выключается и предыдущий результат оплаты игнорируется вне состояния ожидания терминала. - Красная кнопка «ОТМЕНА» сохраняет прежнее поведение: завершает карточную сессию и возвращает Home.
kiosk_backтеперь соответствует верхней кнопке «Назад»; добавлен регрессионный тест перехода.- Release-сборка прошла с 0 ошибок/0 предупреждений, NUnit — 367/367; headless Godot smoke
с
--mock-hardware=trueзагрузил актуальнуюspace-pixelбез исключений и без обращения к COM3.
2026-09-01 — Этапы 4 и 5 закрыты, физическая приёмка централизована
- Этап 4 закрыт по готовности COM-транспорта, worker-потока, reconnect и at-most-once; оставшиеся действия с реальным контроллером перенесены в раздел 4.1.
- Этап 5 закрыт по фактической безопасной политике UI: кнопки повторной выдачи нет, ошибки ведут
домой, к другому способу оплаты либо в поддержку, а
UnknownAfterRestartне запускает retry. - Все актуальные проверки панели, производительности, платежей, обоих хопперов, пересчёта, USB-reconnect, soak и целевых платформ собраны в «4.1. Проверки на автомате» и удалены из этапов.
- Ближайший рабочий пакет теперь содержит только программные и эксплуатационные задачи.
2026-09-01 — Дорожная карта синхронизирована с one-file export и текущим контроллером
- Удалено устаревшее утверждение, что плата отключена: последний packaged Windows smoke успешно авторизовал COM3, однако новые аппаратные действия по-прежнему требуют отдельного разрешения.
- Зафиксированы one-file Windows release, исправления embedded PCK/TOML/autoload и текущее состояние подписи.
- Добавлен отдельный этап Linux x86_64 для Debian 13: export готов, целевой runtime, serial-path, udev/dialout, kiosk и физическая приёмка остаются открытыми.
- Ближайший рабочий пакет синхронизирован с фактическими задачами Этапов 5, 7, 8, 9 и 9.1.
2026-08-31 — Включён полноценный учёт и выдача двух хопперов
- Временный запрет второго хоппера отменён: целевой профиль
DualHopperAutoиспользует30Xи40X, подтверждения принимаются только от активного канала. - Точный остаток хранится отдельно для каждого хоппера; ручное добавление и автоматический пересчёт доступны раздельно, а подтверждённая выдача списывается с фактически сработавшего канала.
- Покупателю на главном экране справа от полоски запаса показывается только приблизительный общий остаток:
<100, шаг 100 до 1000 включительно и шаг 500 выше 1000. - Владельцу в разделе «Сервис» показывается точный учётный остаток с человекочитаемым склонением слова «жетон»; приблизительные диапазоны из интерфейса настроек удалены.
- Главная индикация получила четыре состояния: пустая полоска «нет жетонов», красная 25% «мало», красная 50% «достаточно», зелёная 100% «много». Состояние вычисляется совместно по общему учёту и active-low датчикам
IN1/IN4. - Внешний DLC-контракт дополнен предсозданными визуалами четырёх состояний; приложение только переключает их видимость и не перестраивает сцену темы.
- Конфигурация поднята до версии 18 и мигрирует старые одноканальные профили в
DualHopperAuto. - Обычный набор расширен тестами двух остатков, округления, правил индикации,
40X, второго пересчёта и двух датчиков. Аппаратные тесты и COM не запускались.
2026-08-31 — Интегрирован протокол новой прошивки первого хоппера
Историческая запись промежуточного состояния. Ограничение одного хоппера отменено записью выше.
- На тот момент разводка:
IN8— сервисная кнопка;IN1/IN24— запас и физическая выдача первого хоппера;IN4— запас второго. Вход выдачи второго хоппера пока неизвестен. - До исправления прошивки второго канала runtime работает только в
Hopper1Auto, отправляет только30Xи отклоняетHopper2Autoбез записи40Xв COM. - Выдача использует
309N, типизированные ответыHOPPER1 APPEND=N,HOPPER1 OK,HOPPER1 ERROR,HOPPER1 CREDIT=Nи запрос остатка3090. Ошибка не защёлкивает хоппер до перезапуска и не вызывает автоматический повтор команды. - Подтверждено ограничение одной команды: N = 1–99;
309100возвращаетERROR:30:invalid count (0-99). Runtime использует общую константу 99 и разбивает крупную выдачу на последовательные пакеты. - Для будущего второго канала сохранён симметричный контракт
409100 → ERROR:40:invalid count (0-99); симулятор и тесты его знают, но runtime продолжает запрещать любые40X. - Автоматический пересчёт запускается
301, считает только строкиHOPPER1 PULSE=1и останавливает мотор командой300после 10 секунд тишины. - Вендиста поддерживается командой
161в idle/card-состоянии с интервалом 120 секунд, то есть заведомо чаще требуемых прошивкой 180 секунд; на время наличной оплаты и выдачи используется162. - Конфигурация поднята до версии 17 и мигрирует прежний целевой
Hopper2AutoнаHopper1Auto; на том этапе второй датчик выдачи сохранялся как-1, позднее владелец подтвердил его привязку кIN25. - Код, симулятор, unit-тесты, аппаратный runner и документация синхронизированы. После фиксации предела пакета обычный набор прошёл 323/323, решение собрано без предупреждений и ошибок. Аппаратные тесты и любые обращения к COM не выполнялись, потому что плата отключена.
2026-08-31 — Авторизация синхронизирована с актуальным plate_config_app
- После открытия COM-порта выполняется аппаратный reset: очистка буферов, DTR=false, RTS=true на 100 мс, затем RTS=false.
- Контроллер должен прислать точный startup-баннер
periphery controller ver_<version>; после паузы 2000 мс выполняется07 → CHAL → 08 → RAES. - Корректный
RAES,AUTH_PC_OKиAUTH_CNT_OKявляются промежуточными стадиями. Рабочие команды разрешаются только после точного кадраREADY!. - Синхронизировать таймауты с актуальным
plate_config_app: startup-баннер — 20 с, обязательная пауза — 2000 мс,CHALиRAES— по 2000 мс, финальныйREADY!— 5 с. Конфигурация v19 переводит только старое стандартное значение 5000 мс на 2000 мс и сохраняет явно заданные пользовательские значения. - Входящие
CHALиRAESразбираются совместимо сplate_config_app: поддерживаются слитный HEX-payload, пробел или двоеточие после префикса. - Симулятор, unit/integration-тесты и безопасный аппаратный probe приведены к тому же контракту.
- Решение собирается без предупреждений; программный NUnit-набор проходит 310/310.
- Физический auth-probe на COM3 прошёл 1/1;
Safeпрошёл 8/9. Новый handshake,91/IN1,140,150,409?,99и три reconnect-цикла подтверждены. - Единственный открытый аппаратный результат — отсутствие ответа на
160в двух независимых запусках. Это не блокирует авторизацию, но требует проверки подключения/режима Вендиста.
2026-08-28 — Исправлена пакетная выдача второго хоппера
- Реальный обмен показал формат прошивки:
40910ставит в очередь 10 жетонов, после чего плата отвечаетHOPPER2 queued 10 prizesи десять разHOPPER2 OK. Hopper2Autoпереведён с ошибочной схемы «одна409→ опросIN25» на409N → N × HOPPER2 OK; короткие импульсыIN25больше не могут быть пропущены периодическим опросом и не дублируют подтверждения платы.- Пакеты ограничены 99 жетонами; выдача 515 жетонов детерминированно разбивается на пять
40999и один40920, следующий пакет отправляется только после завершения предыдущего. - Parser типизирует
HOPPER2 queued N prizes, симулятор воспроизводит реальный порядок кадров. Обычный набор прошёл 289/289; 17 аппаратных тестов безопасно пропущены без явного разрешения на запуск мотора.
2026-08-27 — Целевой хоппер исправлен на второй
- Владелец уточнил фактическую разводку:
IN1иIN25принадлежат второму хопперу, аIN2/IN24— будущему первому. - Добавлен режим
Hopper2Autoи типизированныеHOPPER2 OK/ERROR. Первоначальная трактовка одиночной409и подсчётаIN25позднее заменена подтверждённым пакетным форматом409N; актуальное поведение описано в записи от 2026-08-28. - Status-запрос аппаратного runner переведён с исторического
309?на409?для второго хоппера; формат ответа ещё нужно подтвердить безопасным прогоном COM3. - Конфигурация версии 15 автоматически мигрирует прежний
Hopper1AutoнаHopper2Auto, если он использовал целевую паруIN1/IN25; локальный COM3-профиль уже обновлён. - Регрессии того блока покрывали прежнюю интерпретацию
409/IN25; после проверки прошивки они заменены тестами409N,HOPPER2 queuedиHOPPER2 OK. Актуальный набор и результаты указаны выше.
2026-08-27 — Платёжные действия повторно сверены с протоколом платы
- Для наличной ветки зафиксирована и протестирована последовательность
162 → 141 → 151, обязательныеASK:COINS/BILL, а перед выдачей/при отмене —142 → 152. - Для безналичной ветки выбор способа не включает терминал до подтверждения суммы; подтверждение
отправляет
142 → 152 → 161 → 163<amount>,MONEY:CASHLESSсначала получает обязательныйASK:CASHLESS, затем терминал выключается162. Несовпадающая сумма выдачу не запускает. - Платёжные каналы стали явно взаимоисключающими, а повторные Cancel/End не добавляют одинаковые команды в последовательную очередь платы.
- Последующее уточнение разводки показало, что
IN1/IN25относятся ко второму хопперу; поэтому прежняя реализация309/Hopper1Autoдля целевого автомата была заменена на409/Hopper2Autoв следующем блоке работ. - Полные cash/card сценарии и пакет 515 жетонов прошли через настоящий parser, authenticator,
PeripheryMachineController,SessionFlowи wire-симулятор. Набор: 283/283 unit/integration; 17 аппаратных тестов по-прежнему требуют явных флагов, реальные деньги и мотор не запускались. - После изменений безопасная аппаратная группа повторно запущена на CP210x/COM3: 9/9, включая
handshake,
INPUT, активныйIN1 → Low,140,150,160,309?,99и три reconnect-цикла. Отчёт:artifacts/board-tests/board-safe-20260827-161454.trx. Реальные деньги и мотор не запускались; один краткийUnauthorizedAccessExceptionпри переоткрытии восстановлен retry.
2026-08-27 — Настраиваемый короткий текст в речевом bubble
- Добавлена отдельная настройка
Branding.ShortTextс понятным названием «Короткий текст», лимитом 48 символов, автосохранением, валидацией и preview. HomeScreenподставляет значение только в авторский Label речевого bubble по биндингуhome.scroll.content.speech_text; старыйSubtitleи его биндинги не возвращаются.- Конфигурация поднята до версии 14: существующий профиль получает безопасный текст по умолчанию и атомарно сохраняется с резервной копией.
- Theme Builder добавил новый HOME-биндинг и три SETTINGS-биндинга
short_text; актуальный контракт содержит 460 ID и имеет SHA-2561FA54C9B9A0A7DFF71A5FAD38A5E9036E6C2D8F3D0BD298F003524A3E752FA10.
2026-08-26 — Исправлена полярность датчика запаса IN1
- Подтверждено по протоколу платы и утилите тестирования входов: цифровые входы используют pull-up, поэтому активный сигнал на
IN1сбрасывает бит маски. - Production-сопоставление исправлено на
IN1 bit 0 → LowиIN1 bit 1 → Enough; обновлены defaults, аппаратные runner/tests и документация. - Конфигурация поднята до версии 13: профиль с подтверждённым входом
IN1автоматически мигрирует с ошибочной active-high полярности на active-low, а прежний JSON сохраняется в.bak. - На подключённой плате COM3 безопасная группа прошла 9/9; текущий активный IN1 был интерпретирован как
Low. Модульные тесты прошли 262/262.
2026-08-26 — Короткое описание полностью удалено
- Удалено поле короткого описания из модели
BrandingSettings, нормализации, валидации, настроек владельца, preview и HOME. - Конфигурация поднята до версии 12: старое JSON-поле
Subtitleигнорируется и удаляется при автоматической миграции с сохранением предыдущего файла в.bak. - Из контракта DLC и обеих тем были удалены четыре HOME/SETTINGS-биндинга короткого описания; на этом шаге контракт содержал 456 обязательных биндингов и имел SHA-256
E77F754AB2C3913928B7DF18DD3D8F3205000D1531C414CC5B621E21CDF03ECF.
2026-08-26 — Экранные клавиатуры настроек
- В
src/ui/OnScreenKeyboardдобавлен общий C#-контроллер: русский и английский алфавиты, Shift, 33 спецсимвола, каретка, пробел, очистка/удаление и отдельный цифровой режим. - Все
LineEditиSpinBoxSettings, включая динамические fallback-строки и фиксированные слоты внешней темы, регистрируются автоматически; native virtual keyboard отключён, числовой ввод подтверждается черезSpinBox.Apply(), а активное поле поднимается над нижней панелью. - Fallback и обе темы содержат заранее созданные текстовую и цифровую панели с кнопкой скрытия справа сверху. Runtime не создаёт и не перестраивает их Control-узлы.
- Theme Builder получил общий компонент, preview-состояния
KEYBOARD: OFF/TEXT/NUMи 57 новых metadata binding-id. Контракт расширен с 403 до 460 биндингов; SHA-256 каталога:4552F55F78E744DF90DC4D8153330D4A6A6C156673C12B384E828D99AA93CE3A. - NUnit-набор расширен до 262 тестов; fallback Settings импортируется и запускается headless без ошибок. Отдельный runtime smoke подтвердил ввод букв и числа, показ и скрытие обеих панелей как во fallback, так и в установленной внешней теме. Ручная проверка пальцем и в перчатках остаётся частью физической приёмки Этапа 8.
- Установлен
space-pixel.pckразмером 672840 байт, SHA-256:752710CB91BD7D4A5FCC60A80B427671B2E98CE937203CD24A5648943008399A. Предыдущий пакет сохранён какactive_theme.pre-onscreen-keyboard.pck(634888 байт, SHA-256:22359A8D488352BA3E2C5E6E294C6822EEDEA853BD66ADF429C861D6C7B00DD8). - У бонусного
SpinBoxудалена приписка «жет.» во fallback и во всех 16 фиксированных слотах обеих тем: многозначное количество дополнительных жетонов теперь показывается полностью. Установлен исправленныйspace-pixel.pckразмером 672520 байт, SHA-256:5CC976A4B8EB07A15571F00DCB74BD7D46F1CBC8BDEAF97E1A994131763321E7; предыдущий пакет сохранён какactive_theme.pre-bonus-suffix-fix.pck.
2026-08-26 — Host адаптирован к самодостаточным сценам Theme Builder
- Поддержана новая структура
themes/example,themes/space-pixelиthemes/<theme-id>; production-сцены теперь сами содержат Theme, статическийThemeBackgroundиBackgroundDecorationс metadataexchanger_self_contained_visuals = true. - Loader проверяет структуру каждой сцены, запрещает смешивать два режима внутри одного PCK и отклоняет глобальные background/decoration пути, которые дублировали бы экранную композицию.
ReducedEffectsтеперь скрывает и полностью останавливает decoration внутри текущего экрана; единый лимит узлов, CanvasItem, анимаций и кадров применяется и к самодостаточной decoration.- Устранено runtime-переоформление готовых сцен: прежний проход Settings принудительно назначал
панелям
WhitePanelи менял внешний вид относительно preview; теперь визуальные семантики и размеры keypad применяются только к встроенному fallback, а self-contained view сохраняется. - Root внешней сцены больше не переименовывается в
ThemeViewи не получает повторный layout preset; бюджет decoration стал чистой проверкой без изменения FPS/speed_scaleресурса. - Удалены семь зон runtime-достраивания: запас, связь и промо Home, кнопки карточных сумм, правила бонусов, суммы оплаты и список промо Settings. На этом шаге контракт был расширен до 403 обязательных биндингов; самодостаточная тема заранее содержит все визуальные элементы и фиксированные слоты.
- Актуальный
space-pixel.pckразмером 632992 байта установлен в стандартныйuser://; SHA-256:122A6F16ED727080AC1F8EC407E94CD5D9E6CDBDF0A0465F27E1AF6C26ADAF6E. Предыдущий пакет сохранён рядом какactive_theme.pre-binding-only.pck; более ранняя копия также сохранена какactive_theme.pre-self-contained.pck. - Solution собирается без предупреждений; 254 unit/integration-теста проходят, 17 физических hardware-тестов безопасно пропущены без явного запуска на плате.
2026-08-25 — Завершён полносценовый DLC-контракт v2
- Все девять C#-контроллеров экранов отделены от визуального дерева: внешний DLC заменяет только
SafeMarginна собственныйThemeView, а оплата, навигация, настройки и оборудование остаются в основном приложении. - Зафиксированы шаблон имён
screen_<key>.tscn, root-именаThemeScreen_<Name>, metadataexchanger_screen_binding_idиexchanger_binding_id; расположение элементов внутри темы больше не влияет на привязку. - В host добавлен закреплённый SHA-256 каталога из 187 обязательных биндингов. До активации PCK проверяются девять сцен, ID, Godot-типы, полнота, отсутствие неизвестных биндингов, дубли и полный запрет скриптов.
- Обратная совместимость manifest v1 сохранена как стилевой режим с единственной встроенной fallback-темой.
ExchangerThemeDlcBuilderреорганизован вthemes/_templateиthemes/space_pixel; preview использует реальные production-сцены, показывает 9 вкладок и overlay binding-id с live reload._templateиspace_pixelпроходят full-scene validator. Итоговый PCK размером 407832 байта установлен в стандартныйuser://; SHA-256 пакета:CB1EC8F6C6F908139CD6B602E5A7A401E271F8AD5F69BF5C3943B4FD6D10FF47.- Runtime smoke подтвердил внешний
ThemeViewу всех девяти контроллеров, отсутствие app-owned Timer/AudioStreamPlayer внутри темы и чистый журнал Godot. Solution собирается без предупреждений; 247 unit/integration-тестов проходят, 17 физических hardware-тестов безопасно пропущены без явного запуска на плате.
2026-08-25 — Runtime-интерфейс синхронизирован с preview темы
- Логический viewport приложения переведён с 1080×1920 на нативные для theme-builder 720×1280; пиксельный текст больше не проходит через промежуточное уменьшение 2/3.
- Главная, наличная и карточная ветки, терминал, успех, ошибка и сервисный вход получили геометрию,
панели, кнопки и общий footer из соответствующих preview-сцен
space_pixel. - DLC manifest v1 обратно совместимо расширен именованными
VisualSlotsдля пассивной графикиhome,cash,cardиresult; host сохраняет поверх них собственные тексты и бизнес-логику. - Для decoration добавлен явный
BackgroundDecorationScale; текущий фон 1080×1920 масштабируется до нативной сетки коэффициентом 0.666667 без влияния на screen-specific слоты. - Настройки владельца пересчитаны в нативные координаты 720×1280, при этом пять разрешённых вкладок и автоматическое сохранение сохранены; технические разделы не возвращались.
- Актуальный
space_pixelPCK собран и установлен. Сборка без предупреждений; 234/234 модульных теста прошли, 17 аппаратных тестов безопасно пропущены без явного запуска на плате.
2026-08-25 — Настройки переориентированы на владельца автомата
- Из навигации
SettingsScreenудалены вкладки «Тема», «Оборудование» и «Диагностика»; в шапке оставлен только короткий заголовок «НАСТРОЙКИ» без ролей и поясняющего подзаголовка. - Убраны внешний DLC и путь
.pck, сводка применения темы, технический итог промо, COM/mock/reconnect, окно/FPS, состояние приложения, предупреждения, журналирование и тестовая выдача. - Владельцу оставлены пять разделов: «Общие», «Звук», «Промо», «Тарифы» и «Оплата», включая PIN, оформление главного экрана, цены, бонусы, способы оплаты и время ожидания.
- Скрытые deployment-параметры исключены из валидации формы владельца и больше не могут заблокировать автосохранение доступных полей.
- Runtime QA на 720×1280 подтвердила пять вкладок, понятные формулировки и отсутствие всех технических панелей; сборка без предупреждений, 228/228 модульных тестов прошли, 17 аппаратных безопасно пропущены.
- Удалены избыточные пояснения о назначении проверочного звука и общем диапазоне карточных сумм; высота соответствующих карточек и шапки уменьшена без пустых зон.
- Тексты всех доступных владельцу разделов и экрана ввода PIN переписаны простым языком: убраны термины
fallback, «таймаут», «порог», «конфигурация» и технические формулировки автосохранения; пример тарифа теперь показывает готовое количество жетонов с правильным склонением. - В
space_pixelи встроенной резервной теме полностью отключены тени текста и обводка кнопок; светлый текст переведён в чистый белый, а текст на светлых и зелёных поверхностях — в более тёмный контрастный оттенок. Обновлённый PCK собран и установлен вuser://theme_dlc/active_theme.pck. - Исторические записи ниже описывают прежний инженерный UI на момент его реализации и считаются заменёнными этой записью.
2026-08-24 — PIN перенесён в настройки приложения
- Удалена зависимость сервисного входа от
EXCHANGER_SERVICE_OPERATOR_PINиEXCHANGER_SERVICE_ENGINEER_PIN. - На вкладке «Общие» добавлены включение защиты и сброс PIN; изменения по-прежнему сохраняются автоматически.
- Первый вход после включения или сброса предлагает дважды ввести 4–12 цифр, затем открывает инженерные настройки; последующие входы проверяют PIN и блокируются на 30 секунд после пяти ошибок.
- В конфигурации версии 11 сохраняются только случайная 16-байтовая соль, PBKDF2-SHA256-хеш длиной 32 байта и 210000 итераций; открытый PIN не попадает в JSON, audit или логи.
- Одинаковая политика применяется к физическому IN0 и debug-действию F10; при выключенной защите они открывают настройки напрямую.
- Runtime-проверка прошла полный цикл создания, подтверждения и повторной проверки PIN; тестовая пользовательская конфигурация после проверки восстановлена. Сборка без предупреждений, 225/225 модульных тестов прошли, 17 аппаратных тестов безопасно пропущены без явного профиля запуска.
2026-08-24 — Цифровые входы привязаны к хопперу
- Добавлена именованная production-разводка:
IN0— active-low сервисная кнопка, активныйIN1(бит 0) — мало жетонов,IN25— active-low импульс выдачи. Позднее владелец уточнил, что эта пара относится ко второму хопперу;IN2/IN24зарезервированы для первого. IN0публикует одно событие только при переходе в активный уровень; debug-сборка открываетSettingsнапрямую, release-сборка использует защищённый путьServiceAccess → Settings, а следующий фронт закрывает настройки после автосохранения. При настроенном входе IN0 дублирующий кадрSERVICEигнорируется, поэтому один физический нажим не выполняет два перехода.IN1обновляетEnough/Lowтолько при реальном изменении и никогда не создаёт числовой остаток.IN25считает один жетон на active-low фронт только во время активной выдачи. В целевомHopper2AutoкадрыHOPPER1игнорируются; без исходного снимка выдача блокируется безопасной ошибкой.- Быстрые входы резервно опрашиваются командой
91каждые 100 мс; индексы, полярности и интервал вынесены в конфигурацию. Конфигурация версии 13 исправляет production-полярность на active-low:IN1 bit 0 → Low,IN1 bit 1 → Enough. - Безопасная проверка COM3 прошла 9/9; текущий
IN1=0корректно преобразован вEnough. Мотор, платёжные приёмники и банковский терминал не запускались. - Сборка завершилась с 0 предупреждений и ошибок; модульный набор прошёл 212/212.
2026-08-24 — Handshake сверен с Unity, Python и реальной платой
- На дату записи Unity использовался как источник криптографической проверки
RAES. Позднее актуальныйplate_config_appстал источником обязательной startup-последовательности с баннером, паузой иREADY!; AES-проверка Exchanger при этом сохранена. - Exchanger теперь восстанавливает ключ как Unity. Контрольная пара спецификации
8C70…0F7A → 99ED…B0E1воспроизводится точно. - Probe на COM3 подтвердил
RAES == AES-256-ECB-Encrypt(07). Исторический переход в Ready сразу послеRAESвпоследствии отменён записью от 2026-08-31: актуальный контракт требует точныйREADY!. - Реальный ответ цифровых входов имеет вид
INPUT<decimal>без обязательного пробела; parser принимает оба варианта и защищён регрессионными тестами. - Безопасная аппаратная группа прошла 8/8: handshake,
91,140,150,160,309?,99и три reconnect-цикла. Ни оплата, ни выдача не запускались. - Сборка завершилась без предупреждений и ошибок; модульный набор прошёл 204/204.
2026-08-24 — Первый безопасный прогон реальной платы
- Windows определила контроллер как Silicon Labs CP210x на COM3; порт 115200 8N1/None открывается стабильно.
- Первый запуск обнаружил реальный Windows edge case:
SerialPort.Readпри штатном закрытии бросаетOperationCanceledException. Worker теперь безопасно завершает поток; добавлены 6 регрессионных проверок, общий NUnit-набор вырос до 203/203. - Первые восемь production-попыток стабильно получили
CHALиRAES, но завершились доReady: обфусцированный массив ошибочно использовался как эффективный AES-ключ. Причина устранена последующей сверкой с Unity. - Добавлен изолированный
HardwareProbe: случайный07, ответ08через production AES-256 ECB/NoPadding, классификацияRAESбез сохранения сырых блоков. - Первый probe подтвердил отсутствие
AUTH_CNT_OKи несовпадение при ошибочном прямом ключе. После XOR0x37повторный probe подтвердил корректныйRAES, а Safe прошёл 8/8 без обхода авторизации. - Следующий аппаратный шаг: отдельно выполнить Interactive/Payment/Dispense/Cable с явными подтверждениями и физической подготовкой стенда.
2026-08-24 — Завершён Этап 6
- Release-профиль получил borderless fullscreen, скрытый курсор, восстановление окна после focus/display/resolution change;
F10жёстко ограничен debug-сборкой и состоянием Home. - Добавлены Windows watchdog, установка/удаление задачи автозапуска и эксплуатационная инструкция; PowerShell разобран без ошибок, installer проверен через
-WhatIf, watchdog — одноразовым процессным запуском. - Первоначально реализованы физический
SERVICE→ PIN-клавиатура → роли Operator/Engineer, пять попыток и 30-секундная блокировка; последующая запись выше заменила environment-PIN единым PIN приложения. SettingsScreenзавершён восемью вкладками, полной валидацией, инженерными COM/window настройками, safe reset, подтверждением dirty-exit, отдельным повторным подтверждением restart-only сохранения и итогом без автоматического restart/reconnect.- Диагностика показывает версию 0.6.0, тему, безопасное состояние порта/соединения/запаса, последние очищенные предупреждения и тестовую выдачу одного жетона с двойным подтверждением.
- Добавлены безопасный audit конфигурации, уровни/лимиты журналирования, очистка по сроку и общему объёму; пути, значения, PIN, платёжные данные и сырые протокольные кадры не записываются.
- Ускоренный soak моделирует 1440 минут, 480 подтверждённых выдач и 10 000 циклов
SessionFlow; process-runner прошёл 12/12 пятиисекундных сэмплов с пиком working set 217.73 МБ, CSV дополнительно исправлен и повторно проверен под русской локалью. - Runtime QA пройдена на 720×1280 и 1080×1920: роли, Equipment/Diagnostics, field validation, discard/continue, test dispense и двухэтапное restart-only сохранение. Тестовые изменения пользовательской конфигурации восстановлены; game/editor logs чистые.
- Контрольная сборка завершилась с 0 ошибками и 0 предупреждениями; 197/197 NUnit-тестов прошли, 15 hardware-тестов безопасно пропущены без подключённой платы.
- Реальный 24-часовой wall-clock soak, проверка собственной экранной клавиатуры на физической панели и поведение дисплея перенесены в аппаратную приёмку Этапа 8 и явно отмечены как внешняя зависимость, а не незавершённая программная задача Этапа 6.
2026-08-21 — Подтверждён профиль AES платы
- Рабочая реализация владельца подтвердила
AES-256,CipherMode.ECB,PaddingMode.Noneи шифрование одного 16-байтового блока черезTransformFinalBlock. - Существующий
Aes256EcbBlockCipherуже полностью соответствовал этой реализации;ControllerAesMode: "ECB"включён по умолчанию. - Конфигурация повышена до версии 6; старые пользовательские настройки с пустым AES-режимом автоматически мигрируют на
ECB. - Позднейшая сверка с Unity показала, что сохранённый массив нужно декодировать XOR
0x37; после исправления старыйRAES-пример и реальная плата совпали.
2026-08-21 — Handshake приведён к фактическому порядку платы
- На основании предоставленного тогда рабочего метода порядок был уточнён до
07 → CHAL → 08 → RAES. Эта историческая схема заменена 2026-08-31 строгим startup-контрактомbanner → 2000 ms → 07/CHAL/08/RAES → READY!. - Добавлены состояния ожидания
CHALи доказательства платы; обязательное ожиданиеAUTH_CNT_OKвпоследствии удалено по фактической трассе. - Реализованы быстрый CHAL-timeout
min(1200, max(250, timeout/4)), общий настраиваемый timeout и отмена ожидания при disconnect. - Конфигурация обновлена до версии 5 с
HandshakeTimeoutMilliseconds: 5000. - Wire-симулятор и интеграционные тесты переведены на новый порядок; набор расширен до 98 тестов, включая закрытие порта при неверном доказательстве платы.
2026-08-21 — Завершён Этап 3
- Документированный профиль протокола 2.3.5 закрыт: framing, parser, double handshake, платежи, обязательные
ASK:*, Вендист,SERVICE,INPUTи legacy-хоппер отделены от транспорта и Godot Node. - Добавлен
PeripheryControllerSimulator, который проходит настоящий handshake и воспроизводит card success, malformed-кадр, бинарный датчик, полную и частичную выдачу без COM-порта. - Протокольный адаптер игнорирует бизнес-кадры до криптографически подтверждённого
RAES, подавляет повторныйDISPENSE, не выполняет автоматический retry и блокирует legacy-хоппер после аппаратной ошибки. - Добавлены типизированные команды status-запросов
140,150,160,99; неизвестные форматы ответов остаются безопасно неподдерживаемыми. - Внешние неопределённости AES, силового канала и физической распиновки вынесены в аппаратную проверку следующих этапов и не подменены предполагаемыми командами.
- Набор расширен до 91 теста; проверены все результаты card-сессии, несовпадение суммы, pre-auth-фильтрация, service/error, malformed recovery, границы параметров, at-most-once и partial hopper failure.
2026-08-21 — Фиктивный числовой остаток полностью удалён
- Аппаратная граница использует только
MachineStockLevel:Enough,Lowили техническийUnknown. - Числовой остаток,
MachineStockSnapshot,ExactCount,Empty,Pricing.InitialStockи пороги удалены из real/mock-контроллеров, сессии, UI и конфигурации. - Добавлен parser ответа
INPUT<bitmask>/INPUT <bitmask>, polling командой91и конфигурация номера входа/полярности датчика. - UI и mock работают только с «МНОГО»/«МАЛО»; успешная выдача не изменяет уровень без нового сигнала датчика.
Unknownблокирует начало оплаты,Lowразрешает работу без ложной проверки точного остатка.- Тестовый набор расширен до 77 тестов, включая polling датчика и сброс уровня в
Unknownпри disconnect.
2026-08-21 — Добавлен предоставленный ключ контроллера
- 32-байтовый
AesEncryptedKeyдобавлен вPeripheryControllerSecurityи документацию протокола. - Переменная
EXCHANGER_CONTROLLER_AES_KEYсохранена как необязательное переопределение для другой ревизии платы. - Позднее выяснилось, что массив является обфусцированным: после XOR
0x37AES-256 ECB/NoPadding воспроизводит примерRAESи обмен с реальной платой.
2026-08-21 — Начата интеграция периферийного контроллера 2.3.5
- Добавлен
System.IO.Ports8.0.0 и реальный Windows-транспорт 115200 8N1 без flow control. - COM-чтение/запись выполняются одним worker-потоком; события передаются в Godot через очереди и главный
_Process. - Реализован ASCII-фреймер
CR/LF, timeout 100 мс, лимит кадра и безопасное восстановление после мусора/переполнения. - Добавлены parser/formatter команд
READY, handshake,MONEY:*,ASK:*,SERVICE, Вендиста и legacy-хоппера. - Реализован double-handshake state machine и AES-256 ECB cipher; на этом шаге активация ещё ожидала подтверждения режима, которое владелец предоставил позднее.
PeripheryMachineControllerуправляет smart-монетником, купюроприёмником, Вендистом, keep-alive и обязательными подтверждениями платежей.- Приём оплаты блокируется, пока не настроен безопасный production-способ выдачи; автоматический retry выдачи отсутствует.
- Добавлен периодический reconnect COM-порта и повторная авторизация после подключения.
- Тестовый набор расширен до 72 тестов, включая framing, команды, handshake, AES-вектор, проверку встроенного ключа, платежи, keep-alive, disconnect во время выдачи и блокировку небезопасной выдачи.
2026-08-21 — Добавлен безопасный контекст и журнал операций
- Каждая cash/card-сессия получает уникальный локальный
OperationId; начало и единственный итог публикуются типизированными снимками. - Добавлены
SessionErrorCode, безопасные пользовательские тексты и рекомендацииReturnHome/TryAnotherPaymentMethod/ContactSupport; сырая ошибка оборудования не попадает в UI. - Отдельный JSONL-журнал
user://logs/operations.jsonlхранит только безопасные поля и при старте закрывает незавершённые записи какUnknownAfterRestart, не повторяя оплату или выдачу. IMachineControllerиMockMachineControllerподдерживают событие потери связи; потеря во время выдачи приводит кDispenseStatusUnknownи запрещает предполагать результат.- Debug-панель карточного сценария позволяет вручную воспроизвести успех, отказ, полную/частичную ошибку выдачи и потерю связи.
- Правила восстановления и ручная приёмка зафиксированы в
docs/operations/RECOVERY_AND_MOCK_QA.md. - Набор расширен до 45 тестов; проверены уникальность идентификаторов, единственный финальный исход, typed errors, очистка подписок и восстановление JSONL.
2026-08-21 — Автоматизировано тестирование mock-среза
- Подключены NUnit 4.6.1, NUnit3TestAdapter 6.2.0 и Microsoft.NET.Test.Sdk 18.9.0 в отдельном
Exchanger.Tests. - Бизнес-логика вынесена из Godot-узла в чистый
SessionFlow;SessionControllerостался тонким адаптером_Processи журналирования. - Добавлен
IMonotonicClock, благодаря которому таймауты 45/120 секунд проверяются мгновенно управляемыми часами. PricingPolicyотделяет проверку суммы и расчёт базовых/бонусных жетонов от UI и Godot.- Набор из 37 тестов покрывает конфигурацию, тарифы, cash/card success, decline, timeout, неподтверждённое состояние запаса, duplicate/late events, частичную выдачу, сброс данных и утечки подписок.
- Автоматически проверяется наличие восьми сцен и четырёх ресурсов тем; семь пользовательских экранов отдельно прошли runtime smoke-загрузку через
godot-ai. - В тот момент mock временно проверял выбранный пакет против числового запаса; позже это поведение удалено после уточнения, что датчик сообщает только «много/мало».
MockMachineControllerполучил настраиваемую задержку и детерминированные сценарии полной/частичной ошибки выдачи; полный отказ runtime-проверен до корректногоErrorScreen.- Итоговые
dotnet test, запуск проекта и Godot editor/game logs проходят без ошибок и предупреждений.
2026-08-21 — Завершён Этап 2
- Добавлена типизированная аппаратная граница
IMachineControllerиMockMachineControllerдля баланса, запаса, карточного результата и подтверждения выдачи без предположений о wire-протоколе. - Реализован
SessionControllerс явными cash/card состояниями, монотонными таймаутами, сбросом временных данных и защитой от повторных команд. - Добавлены
CardCustomAmountScreen,CardTerminalScreen,SuccessScreenиErrorScreen; все экраны подключены черезScreenRegistry. - Наличная ветка получила debug-ввод купюр и явное подтверждение выдачи; карточная ветка — debug-результаты терминала.
- Реализован автономный
AdvertisementPlayer: локальный плейлист, постер/текстовый fallback, беззвучный режим по умолчанию и остановка декодирования внеHomeScreen. - Runtime пройдены cash success, card success, card decline и custom amount; проверены выдача только после подтверждения, отображение запаса и возвраты на Home.
- Визуальная QA 720×1280 при логическом viewport 1080×1920 выявила и устранила неравномерную цифровую клавиатуру; финальная сетка состоит из трёх равных колонок.
- Контрольная C#-сборка и Godot runtime-логи чистые; новые NuGet-зависимости не потребовались.
2026-08-20 — Первый пакет Этапа 2
- Логический viewport переведён на 1080×1920, debug-window — на 720×1280; добавлена миграция пользовательской конфигурации до версии 2.
- Добавлены Input Actions
kiosk_backиdebug_cycle_theme. - Реализованы Autoload
ScreenManager, централизованныйScreenRegistry, общийScreenHostи UI fade-переходы. - После runtime-теста добавлен
TransitionInputBlocker, устраняющий случайный выбор элемента под координатой отпущенного тача на новом экране. - Удалён ландшафтный
StartScreen; созданыHomeScreen,CashPaymentScreenиCardAmountScreen. - Добавлены конфигурируемые тарифы, бонусы, карточные пресеты, брендинг, настройки промо и
TokenStockStatus. - Космическая тема переведена с фиолетового прототипа на тёмно-синюю/салатовую палитру референса.
- Визуально и через runtime UI проверены Home → Cash → Home → CardAmount → Home на 720×1280 при логическом viewport 1080×1920.
- Разрешение на необходимые NuGet-пакеты получено; в текущем пакете новые зависимости не потребовались.
2026-08-20 — Завершён Этап 0
- Инициализирован локальный Git-репозиторий без назначения remote и создания первого коммита.
.agents/AGENTS.mdпризнан проектным файлом и исключён из списка игнорирования.- Создан
docs/architecture/decisions.mdс базовыми архитектурными решениями. - До появления целевого оборудования принята универсальная, конфигурируемая стратегия без привязки к конкретному ПК, GPU, DPI или тач-контроллеру.
- Реализация wire-протокола и COM перенесена в Этапы 3–4; входом станет документация и список команд, которые владелец позднее добавит в
references/. - Зафиксировано, что все аппаратные данные поступают ПК от контроллера и преобразуются внутри приложения в типизированные события.
2026-08-20 — Инициализация дорожной карты
- Изучено исходное ТЗ и текущее состояние проекта.
- Исторически был зафиксирован Compatibility renderer вместо противоречащего ему Forward+; текущий режим — Mobile/Vulkan для Native Video.
- Сформирована архитектура тем, навигации, сессии и аппаратного слоя.
- Определены этапы разработки, критерии приёмки, риски и вопросы к владельцу продукта.
2026-08-20 — Завершён Этап 1
- Исторически были настроены viewport 1920×1080, Compatibility, production fullscreen и debug-window профиль; текущий рендерер — Mobile/Vulkan.
- Созданы
App,StartScreen,TouchInputGuard,AppSettingsи журнал с ротацией. - Реализованы
VendingThemeDefinition, AutoloadThemeManager, базовая и космическая темы. - Добавлен анимированный shader-фон, космические частицы и статический fallback для облегчённого режима.
- Созданы
IHardwarePort, рабочая mock-реализация и безопасные Windows/Android каркасы. - Проверены C#-сборка без предупреждений, main scene, runtime-логи, смена тем, кнопка «Начать», mock PING и создание пользовательской конфигурации.
- Визуально проверены 1280×720, 1024×768 и borderless fullscreen 2560×1440.
- Подтверждено, что для реального Windows SerialPort потребуется предварительно согласованный NuGet-пакет
System.IO.Ports.
2026-08-20 — Исправлена корневая документация
README.mdполностью заменён документацией Exchanger на русском языке.- Добавлены описание продукта, текущее состояние, запуск, конфигурация, журналы, архитектура тем и аппаратного слоя.
- Удалён случайно установленный корневой
LICENSEGodotX Toast. - Лицензии сторонних компонентов в
addons/иgodot-ai-LICENSE.txtсохранены. - Зафиксировано отсутствие объявленной собственной лицензии Exchanger.
2026-08-20 — Учтены визуальные референсы аппарата
references/добавлен в.gitignoreкак локальный источник концептов, не предназначенный для production.- Проанализированы семь макетов UI 720×1280, рендер корпуса и видео 1080×1920/50 FPS длительностью 32,16 секунды.
- Целевая ориентация изменена с ландшафтного технического прототипа на портретную 9:16.
- Зафиксированы домашний экран, наличная ветка, карточные суммы/клавиатура/терминал, отказ оплаты, запас жетонов, бонусы, промо-блок и поддержка.
- План Этапов 2, 3, 5 и 7 переработан с учётом реального корпуса и пользовательского потока.
- Подробный разбор сохранён в
docs/REFERENCE_ANALYSIS.md.
2026-08-20 — Фон приведён к референсам
AnimatedBackgroundзаменён наStaticBackground.- Из активной сцены и
VendingThemeDefinitionудалены фоновые shader-материалы и частицы. - Удалены ставшие ненужными shader/particle-ресурсы обеих тем.
- Сохранена поддержка статической текстуры фона и отдельной
PackedSceneс анимированными спрайтами. - Промо-блок отделён в архитектуре от фонового слоя приложения.
2026-08-21 — Завершена программная часть Этапа 4
- В
IMachineControllerдобавлено безопасное состояние соединенияDisconnected/Authenticating/Ready/Faulted, одинаковое для mock и реального протокольного адаптера. - Потеря связи переводит бинарный запас в
Unknown, блокируя начало новой оплаты без вымышленного остатка. - Добавлен атомарный
ConnectionStatusIndicator: в production он не занимает внимание приReady, но показывает авторизацию, обрыв и ошибку; debug также показывает штатное подключение. - Интеграционный тест выполняет 200 reconnect-циклов с обрывом во время выдачи и подтверждает отсутствие автоматического повтора и позднего завершения операции.
- Полный набор расширен до 100 тестов; сборка без предупреждений, Godot 4.7.1 runtime и журналы чистые, индикатор визуально проверен на 720×1280.
- Физический длительный прогон и отключение USB-кабеля остаются внешней приёмкой до появления контроллера.
2026-08-21 — Подготовлена аппаратная приёмка платы
- Добавлен отдельный проект
Exchanger.HardwareTestsиз 15 NUnit-проверок production-путиSerialPortHardware → ControllerAuthenticator → PeripheryMachineController. - Безопасная группа проверяет COM 115200 8N1, production AES-handshake,
INPUT, status-команды, закрытие и повторную авторизацию. - Ручные группы покрывают SERVICE, монетник, купюроприёмник и оба бинарных состояния датчика; отсутствующую периферию можно пропустить независимо.
- Реальная карточная операция, физическая выдача и отключение USB требуют разных явных подтверждений и не могут стартовать из обычного
dotnet test. - PowerShell-runner создаёт локальный TRX-отчёт в
artifacts/board-tests/; сырые кадры, AES-данные и секреты в отчёт не попадают. - Полная инструкция запуска и порядок приёмки сохранены в
docs/hardware/BOARD_ACCEPTANCE_TESTS.md.
2026-08-21 — Разработка тем полностью вынесена из Exchanger
- Каталог
themes/, встроенные.tres-темы и debug-переключение удалены из основного проекта. - Exchanger содержит только программную fallback-тему и runtime-контракт одного внешнего DLC; списка тем и горячего переключения больше нет.
- Конфигурация версии 7 читает
Themes.ExternalDlcPathиз пользовательскогоappsettings.json; по умолчанию используетсяuser://theme_dlc/active_theme.pck. - Реализован формат
ExchangerThemeDlcv1:.pckдо 512 МиБ, обязательный manifest иTheme, необязательные статическая текстура иPackedSceneанимированных спрайтов. - Пакет монтируется с
replace_files=false; пути ограниченыres://exchanger_theme_dlc/, повреждённый DLC безопасно оставляет fallback. - В соседнем
../ExchangerThemeDlcBuilderсоздан независимый Godot 4.7-проект с manifest, примером темы, статическим фоном и PowerShell-сборщиком/установщиком. - Реальный
.pckуспешно собран и загружен Exchanger через production loader; fallback отдельно визуально проверен в Godot на 720×1280. - Набор расширен до 105 автоматических тестов плюс 15 отключённых по умолчанию аппаратных проверок; solution собирается без предупреждений.
2026-08-21 — Создана первая внешняя тема space_pixel
- В независимом
../ExchangerThemeDlcBuilderобработаны предоставленные 46 PNG, статический фон 1080×1920, кириллический pixel-font и восемь покадровых последовательностей. - Оригиналы сохранены в
themes_src/space_pixel/; runtime-копии получили стабильные ASCII-пути и не зависят от основного проекта. - Реализованы
ui_theme.tres, статический фон и пассивная decoration-сцена мерцающих звёзд и пролетающих НЛО без скриптов, шейдеров, частиц и видео. - В manifest v1 добавлен обратно совместимый флаг
UseNearestTextureFilter;space_pixelвключает nearest, остальные DLC сохраняют стандартную фильтрацию. - Экспорт текстовых
.tres/.tscnв бинарный формат отключён, поэтому переносимый PCK загружается по стабильным путям без cross-project UID-предупреждений. build/active_theme.pckсобран и независимо проверен production-загрузчиком Exchanger: тема активируется, приложение завершает smoke-run без ошибок и предупреждений.- Контекстные анимации оплаты подготовлены в builder, но остаются не подключёнными до появления именованных screen-specific слотов в следующей версии DLC-контракта.
- В локальный игнорируемый каталог
themes_src/space_pixel/references/скопированы восемь JPG и видео интерфейса; reference-медиа не экспортируются в PCK. - После просмотра всех макетов и 64 кадров видео тема получила семантические вариации
ScreenTitle,PanelTitle,PanelText,SupportText,PrimaryButton,CompactButton,BackButtonиWhitePanel. - Preview перестроен по наличному экрану референса в 720×1280; runtime-декорация при этом сохраняет координаты host-приложения 1080×1920 и масштабируется только внутри preview.
- Для полного reference-look основному Exchanger позднее потребуется назначить semantic
theme_type_variation, вынести общий footer и добавить screen-specific слоты анимаций; точный список узлов зафиксирован в builderdocs/SPACE_PIXEL.md. - Builder-preview расширен до переключаемой галереи всех семи пользовательских экранов темы: Home, Cash, CardAmount, CardCustom, CardTerminal, Success и Error.
- В builder-preview добавлен live reload: сохранённые изменения Theme, изображений и preview-сцен автоматически появляются в запущенной галерее без ручного перезапуска и без сброса выбранной вкладки; preview-инструмент не экспортируется в DLC.
- Layout всех семи preview-сцен приведён к общему правилу: после зелёной шапки сохраняется заметный белый отступ, кнопки не прилипают к заголовкам, а изображения и экранные анимации центрируются относительно внутренней области
WhitePanel.
2026-08-24 — Начата реализация сервисных настроек
- Конфигурация повышена до версии 8 и получила
AudioSettings: master volume, master mute и отдельную громкость промо-ролика. - Добавлен чистый C#
SettingsServiceс изолированной рабочей копией и неизменяемым активным снимком, атомарной записью через временный файл,.bakпредыдущей корректной версии и восстановлением после повреждения JSON. Appзагружает настройки через новый сервис и применяет master volume к Godot audio bus;AdvertisementPlayerотдельно применяет громкость промо-ролика, сохраняя существующий ad mute.- Миграция реального пользовательского файла 7 → 8 проверена в runtime: создана резервная версия 7, временный файл удалён, домашний экран и журналы Godot чистые.
- NUnit-набор расширен до 119 тестов: добавлены аудиограницы, working-copy isolation, round-trip сохранения, backup, восстановление из backup/defaults, защита от конфигурации будущей версии, безопасный запуск при невозможности записи и smoke-проверка новой сцены.
- Добавлен атомарный
SettingsScreenдля звука: рабочая копия, live-preview, сохранение черезSettingsService, отмена с восстановлением активного снимка и безопасный синусоидальный тестовый сигнал. - Master и промо разведены по отдельным Godot audio buses; bus промо-ролика отправляется в Master и меняется независимо без двойного пересчёта громкости в проигрывателе.
- Вход по
F10возможен только из Home и только приOS.IsDebugBuild(); production-вход остаётся закрытым до реализации отдельной авторизации сервисного персонала. - Экран и действия сохранения/отмены проверены в runtime на 1080×1920 и 720×1280; повторный тестовый сигнал и оба аудиоканала не оставляют ошибок в Godot game/editor logs.
SettingsScreenрасширен вкладкой «Тарифы и бонусы»: цена жетона, динамические строки порог → бонус, добавление, удаление, сортировка перед сохранением и preview типовых сумм через productionPricingPolicy.- В интерфейсе явно показано правило расчёта: из подходящих строк берётся один наибольший бонус, строки не суммируются.
- Добавлен чистый
PricingSettingsValidator: блокирует нулевую/чрезмерную цену, цену выше максимальной суммы, пороги вне диапазона, отрицательные/чрезмерные бонусы и дубли порогов; ошибки цены и каждой строки показываются рядом с полем. - Сохранённые тарифы безопасно применяются только из Home: заново настраиваются
SessionController, наличный, карточный и ручной экраны, после чего восстанавливаются stock/connection state; активную операцию редактор открыть не может. - NUnit-набор расширен до 126 тестов; тарифный UI проверен в runtime на 720×1280 и 1080×1920, включая add/remove, duplicate validation, disabled Save, preview, Cancel и сохранение без ошибок Godot.
- Конфигурация повышена до версии 9 и получила отдельный блок
Payments; runtime-миграция реального файла 8 → 9 создала корректную резервную версию 8 без оставшегося временного файла. - В
SettingsScreenдобавлена вкладка «Оплата»: независимое включение наличной и карты, максимальная карточная сумма, шаг ручного ввода, динамический редактор пресетов и три пользовательских таймаута с пояснениями безопасных диапазонов. - Карточные пресеты сортируются, проверяются на диапазон, кратность шагу и дубли. Пустой список разрешён, поскольку карточная ветка сохраняет действие «Другая сумма».
PaymentSettingsValidatorзапрещает отключение обоих способов оплаты и проверяет таймауты;PricingSettingsValidatorдополнен проверкой максимума, шага и каждой строки пресета.SessionFlowотклоняет отключённый способ до начала операции и обращения к контроллеру, аHomeScreenсразу блокирует соответствующую кнопку вместе с существующей блокировкой по запасу.- Настройки безопасно применяются только из Home; runtime-проверка временно отключила наличную оплату, подтвердила блокировку кнопки и восстановила исходную конфигурацию.
- NUnit-набор расширен до 137 тестов; 15 тестов физической платы по-прежнему безопасно пропускаются без явного флага.
- Экран «Оплата», add/remove, ошибки способов оплаты, диапазонов и disabled Save проверены в Godot 4.7.1 на 720×1280 и 1080×1920; финальные game/editor logs чистые.
SettingsScreenполучил стартовую вкладку «Общие» с четырёхкнопочной навигацией, однострочными полями названия, подзаголовка и контакта техподдержки, ограничениями длины и отдельным preview домашнего экрана.- Добавлен чистый
BrandingSettingsValidator: обязательность, максимальная длина и запрет управляющих символов проверяются до записи; runtime-нормализация сворачивает пробелы и безопасно ограничивает текст из внешнего JSON. - Сохранение общих данных проверено сквозным runtime-сценарием до
HomeScreen; тестовые значения после проверки заменены исходными, пользовательская конфигурация версии 9 не оставила временного файла. - NUnit-набор расширен до 146 тестов; вкладка «Общие», пустое поле, disabled Save, живой preview и сохранение проверены в Godot 4.7.1 на 720×1280 и 1080×1920, журналы чистые.
SettingsScreenполучил пятую вкладку «Промо»: включение блока, отдельный mute промо-роликов, fallback-текст, необязательный poster, динамический OGV-плейлист до 12 строк и сводный preview состояния.- Новый
AdvertisementSettingsValidatorпринимает толькоres://,user://или абсолютные локальные пути, запрещает traversal/сетевые URL, проверяет форматы PNG/JPG/JPEG/WEBP и OGV, существование файлов, дубли и длины до сохранения. - Отключённое промо намеренно позволяет сохранить временно недоступные пути:
AdvertisementPlayerв этом режиме не загружает poster, не создаёт видеопоток и показывает «ПРОМО ОТКЛЮЧЕНО». AdvertisementPlayerдополнен загрузкой внешнего raster-постера черезImageи локального OGV черезVideoStreamTheora; диагностическое предупреждение больше не раскрывает полный путь файла.- Runtime-проверка покрыла пустой fallback, отсутствующий poster, пустой/отсутствующий промо-ролик, add/remove, disabled Save и безопасное сохранение отключённого блока; после теста исходные настройки промо восстановлены.
- NUnit-набор расширен до 157 тестов; вкладка «Промо» визуально проверена в Godot 4.7.1 на 720×1280 и 1080×1920, game/editor logs чистые.
SettingsScreenполучил шестую вкладку «Тема»: включение единственного внешнего DLC, путь к.pck, статус доступности пакета и облегчённый режим эффектов.- Новый
ThemeSettingsValidatorпринимает толькоuser://либо абсолютный локальный путь к.pck, запрещает traversal и управляющие символы; отсутствие будущего пакета не мешает сохранить корректный путь и безопасно оставить fallback-тему. - В UI и runtime зафиксирована граница применения:
ReducedEffectsпереключается сразу и откатывается кнопкой «Отменить», а включение DLC и путь применяются только при следующем запуске без самопроизвольной перезагрузки темы. - NUnit-набор расширен до 166 тестов; неверный путь, отключённый DLC, live-preview/откат и внешний вид вкладки проверены в Godot 4.7.1 на 720×1280 и 1080×1920, пользовательские настройки восстановлены, game/editor logs чистые.
2026-08-24 — Начат Этап 7 и синхронизирован host-контракт тем
- Все девять runtime-экранов получили семантические
theme_type_variation; встроенная тема регистрирует их как безопасные наследники базовых Godot-классов, поэтому fallback не изменился. - Динамически создаваемые строки настроек также используют
PanelTextиCompactButton, при этомCheckButtonиOptionButtonсохраняют собственные базовые типы. ScreenManagerотключает processing скрытого экрана и включает его только перед показом нового; runtime-переход Home → Settings подтвердил один активный экран и восемь отключённых.- Зафиксирован debug-baseline на 720×1280 и 1080×1920: стабильные 60 FPS, до 37 draw calls и
менее 1,4 мс process time; условия и ограничения записаны в
docs/operations/PERFORMANCE_BASELINE.md. - Визуально проверены fallback Home 720×1280 и Settings 1080×1920 после внедрения семантических типов: элементы читаемы, панели и кнопки не пропали, наложений не обнаружено.
- Solution собирается без предупреждений; 223 unit/integration-теста проходят, 17 физических hardware-тестов остаются безопасно пропущенными без явных разрешающих флагов.
- Decoration внешнего DLC получила жёсткий runtime-бюджет узлов/спрайтов/кадров и частоты; текущая
space_pixelзанимает лишь 5 узлов, 4 CanvasItem, 1 AnimatedSprite2D и 2 кадра при 1 FPS. - Runtime-аудит всех девяти экранов устранил неравные колонки цифровых клавиатур и подтвердил отсутствие мелких пользовательских кнопок и логики, зависящей от hover.
- Соседний Theme Builder синхронизирован с девятью экранами и восемью разделами Settings,
расширенными variations, hot reload и export-аудитом; PCK установлен в стандартный
user://. space_pixelзагружен production loader без UID-предупреждений; визуально проверены Home, ServiceAccess и Settings/Equipment на 720×1280, а full/reduced профиль сохраняет 60 FPS.- После дополнительного host-QA исправлен контраст CheckButton; финальный PCK (167280 байт,
30 entries) установлен в
user://, все 8 Settings-разделов и SERVICE проходят runtime smoke.
2026-08-24 — Начат Этап 9: воспроизводимый Windows export
- Добавлен preset
Windows x64иtools/export-windows.ps1, который собирает release из очищенной staging-копии, не меняя рабочий проект и не включая editor-autoload. - Из PCK исключены
references/, тесты, docs, tools, artifacts, agent-файлы и все addons; проверенный каталог не содержит test DLL или addon-файлов. - Первая self-contained сборка 0.6.0 успешно создана: 189 файлов, 180,8 МиБ, внутри присутствуют
Exchanger.dll,GodotSharp.dllиSystem.IO.Ports.dll. - Экспортированный
Exchanger.exeпрошёл headless smoke-run с exit code 0; порядок повторной сборки и pre-release проверки записан вdocs/operations/WINDOWS_EXPORT.md. - Финальный export после semantic/touch-правок повторно собран в
artifacts/windows/Exchanger-0.6.0-20260824-163811: 189 файлов, 180,8 МиБ, exit code 0.
2026-09-07 — Составные действия интерактивного питомца переданы теме
- Добавлен обратно совместимый optional composite contract: тема владеет последовательностью клипов и визуальных преобразований, а Exchanger передаёт scoped runtime для проверенного движения anchor, политик ввода/границ/опор и посадки на доступную поверхность.
space-pixelреализуетinteract: условный поворот,come_closerс scale ×2, повторaction, вычисляемый проходfallingчерез низ/верх экрана без промежуточных опор,landingна самой высокой опоре и возврат вidle; reduced-effects получает сокращённую ветку.- Runtime автоматически инвалидируется при смене экрана/темы, drag и конфликтующем действии;
темы без нового API сохраняют прежний одиночный
interactfallback. - NUnit и полный
InteractivePetBehaviorSmokeпроверяют выбор верхней опоры, PCK-контракт, scale ×2, вертикальный wrap, точный порядок клипов и сохранение прежних drag/drop, маршрутов, смены экранов и четырёх циклов празднования.
2026-09-07 — Host синхронизирован с актуальными документами и PCK темы
- Подтверждён актуальный контракт: 481 immutable binding + 17 обязательных supplemental ID;
Sync-HostBindingContract.ps1теперь явно исключает supplemental-набор из JSON-генерации, аTest-PackagedBindingContract.ps1защищает все 17 ID от случайного попадания в каталог. - Зафиксирован trusted runtime без устаревшего decoration budget.
space-pixelпубликует 22 анимации/414 кадров и новые имена walking start/stop через semantic mapping; app-код не привязывается к конкретным именам клипов темы. - Свежий
space-pixel.pck1658512 байт, SHA-25676518563591159EC4B8087911D2BB29924BC29C12AAA4FF1544D97ED01648E91, прошёл полныйInteractivePetBehaviorSmokeпо явному пути на mock-оборудовании. PaymentRewardFormattingSmokeбольше не сохраняет пользовательские Settings и сравнивает наличный/карточный формат на фактическом пресете и бонусном правиле вместо жёсткого ожидания нулевого бонуса.
2026-09-08 — Приземление и простой питомца включены в обычное поведение
- После падения при перетаскивании или смене экрана host проигрывает цепочку
falling → landing → idle;landingвыполняется один полный цикл, аidleостаётся состоянием ожидания до следующего автономного действия. - Старые темы без анимации
landingпродолжают сразу переходить вidle. - Запрошенные во время падения четыре цикла
dancingначинаются только после завершения приземления. - Runtime-smoke с актуальным
space-pixel.pckи mock-оборудованием подтвердил touch drag, смену экранов,falling → landing → idle, отложенный танец и composite action. Debug и Release прошли по 488/488 NUnit-тестов; 18 аппаратных тестов в каждой конфигурации пропущены.
2026-09-08 — Вероятностный простой после ходьбы питомца
- После завершения маршрута host с вероятностью 35% выбирает
idleна 3–5 секунд, а в остальных случаях —sittingна 1,5–3,5 секунды. Темы безsittingбезопасно используютidle. InteractivePetBehaviorSmokeдопускает оба корректных результата маршрута и продолжает проверятьfalling → landing → idle. Unit-тесты фиксируют границу вероятности.- Godot 4.7.1 начал штатно добавлять
unique_idв заголовки узлов.tscn; хрупкая проверка фиксированного футера Settings адаптирована к дополнительным атрибутам без изменения сцены. - Debug и Release прошли по 496/496 NUnit-тестов; 18 аппаратных тестов в каждой конфигурации
пропущены. Runtime-smoke с новым
space-pixel.pckна mock-оборудовании завершился успешно.
2026-09-09 — Действие питомца во время подъёма и спуска
- На каждом ненулевом ребре подъёма или спуска host выбирает случайную точку между 20% и 80%
пути, останавливает перемещение и выполняет
climbing_action_start → climbing_action → climbing_action_stop; средний клип проигрывается один полный цикл. - После stop возобновляется исходная анимация направления и продолжается тот же маршрут. Для старых тем возможность включается только при наличии всех трёх действий, поэтому частичная последовательность не возникает.
- Reduced-effects теперь действительно исключает автономный подъём сразу после landing, но не блокирует явно запрошенные маршруты и их climbing-action.
- Debug и Release прошли по 529/529 NUnit-тестов. Полный
InteractivePetBehaviorSmokeс явным актуальнымspace-pixel.pckи mock-оборудованием подтвердил порядок клипов, неподвижность anchor во время sequence, продолжение маршрута, смены экранов и составное взаимодействие.