# Aletheia 2.40 — результат реализации аудита Дата проверки: 6 сентября 2026. Android versionCode: 51. ## Реализовано - Библиотека: фильтры остаются доступны при пустой выдаче; очистка сбрасывает запрос и выбранный фильтр (`BookshelfFragment.kt`). - База версии 9: источник каталога, уникальность пары источник/ID, индексированный поиск; отдельные обновления метаданных, позиции чтения, карты страниц и позиции аудио (`AppDatabaseHelper.kt`, `BookRepository.kt`). Старым записям без известного источника сервер не приписывается. - FB2 передаётся XML-парсеру исходным потоком с учётом декларации кодировки (`BookParserService.kt`). - Общие загрузки на уровне приложения: каталог и карточка получают один результат, прогресс привязан к книге; закрытие экрана не отменяет импорт (`BookDownloads.kt`). - Каталог: избранное с сохранёнными метаданными, настоящая навигация по доступным OPDS-разделам, подборка из каталога, различение источников в карточках. Если сервер не предоставляет раздел, приложение сообщает об этом. Старое избранное с неизвестным источником показано отдельно, без подстановки другой книги (`CatalogFavorites.kt`, `QBooksLibraryFragment.kt`). - Плеер и таймер сна перенесены в MediaSessionService; перемотка использует безопасные вычисления; кнопки имеют смысловые подписи, таймер показывает оставшееся время (`AudioPlaybackService.kt`, `PlaybackMath.kt`, `AudioBookPlayerActivity.kt`). - Готовые M4A сохраняются в постоянном каталоге приложения, существующие файлы переносятся из кэша; добавлен экспорт через системный диалог сохранения (`AudioBookRepository.kt`, `BookshelfFragment.kt`). - HTTP-ошибки разделены на окончательные и временные, число повторов ограничено. Удаление сохраняет идентификатор серверного задания в устойчивую очередь очистки до подтверждения; позднее завершение загрузки не восстанавливает удалённую запись (`AudioRetryPolicy`, `AudioJobCleanup`, `AudioBookGenerationService`). - Из APK удалён общий токен. Добавлены одноразовое подключение устройства, хранение полномочий через Android Keystore, серверная проверка владельца задания и отзыв устройств. Публичный health больше не сообщает ID задания (`AudioDeviceCredentials.kt`, `device_auth.py`, `audiobook_service.py`). - Синтез выполняется отдельным процессом; его завершение не перезапускает HTTP API (`worker_runner.py`). - Из ReaderActivity выделены сохранение состояния и действия с выделенным текстом; сохранены существующие ReaderStateCoordinator и ReaderWebController. Это первый этап постепенного разделения Activity, а не полная переработка всех панелей. - Ключ подписи перенесён в `%USERPROFILE%\.aletheia\signing`, удалён из рабочего дерева Git; сценарий сборки использует внешнее хранилище. История Git не переписана и по-прежнему содержит прежние версии файлов ключа. - Сценарии подготовки и публикации проверяют коды завершения, подпись и SHA-256. Перед публикацией выполняются резервное копирование SQLite и integrity_check. ## Проверки | Проверка | Результат и источник | |---|---| | Kotlin/JVM | 38 тестов, 0 ошибок и падений; `app/build/test-results/testDebugUnitTest/TEST-*.xml`, `artifacts/release-final-2.40.log` | | Android API 35, эмулятор | 8 тестов, PASS; `artifacts/instrumentation-2.40.log` | | Сервер | 6 тестов, PASS; `artifacts/server-tests-2.40.log` | | Android lint | 0 ошибок, 369 предупреждений; `app/build/reports/lint-results-debug.txt` | | Области нажатия | `scripts/test-accessibility-layout.ps1`: PASS | | Release | `assembleRelease`: PASS; `artifacts/release-final-2.40.log` | | Обновление APK | Установка 2.39 → `adb install -r` 2.40 на эмуляторе: Success; запуск MainActivity: Status ok | Восемь Android-тестов проверяют: таймер при выключенном экране; перенос аудиофайла из кэша; миграцию базы 8→9; сохранение позиции аудио при обновлении задания; сохранение позиции чтения при обновлении метаданных; независимость одинаковых ID разных источников; одну загрузку для двух экранов при отмене наблюдателя; восстановление библиотеки после пустого фильтра. Физический телефон и TalkBack не проверялись. Полный сценарий восстановления EPUB/FB2 после поворота и смены шрифта не проверен на устройстве в этом выпуске; имеющиеся JVM-тесты проверяют парсер и координатор состояния, а не весь WebView-сценарий. ## Публикация - Argus: stable/android, версия 2.40, пакет `aletheia-2.40-51.apk`. - [Публичный manifest](https://argus.kusoft.xyz/api/apps/aletheia-kotlin/manifest?platform=android&channel=stable). - [Скачать APK](https://argus.kusoft.xyz/api/apps/aletheia-kotlin/releases/0d2d1c6b-7666-4967-95e2-30876538adf3/download). - SHA-256 локального и повторно скачанного публичного APK: `c3df0b3d0e6afeda5fe22986cbf4165fab394689c382044b927bdd7c33cdec83`. - SHA-256 сертификата обеих версий: `f4a74d73540d3ea7f092012d50e798d0fbb9c61d3f00483163dc22b04acda764`. - Резервная копия БД Аргуса: `/mnt/data/argus/backups/argus-before-aletheia-kotlin-2.40-0D2D1C6B-7666-4967-95E2-30876538ADF3.db`. - Журнал публикации: `artifacts/publication-2.40.log`. ## Незавершённое развёртывание аудиосервиса CMP `192.168.0.112` не отвечает по SSH (тайм-аут); публичный `/aletheia-tts/health` возвращает HTTP 502. Серверные изменения проверены локальными тестами, но **не развёрнуты на CMP**. Синтез на GPU и подключение реального устройства по новому протоколу не подтверждены. Подготовлен архив `artifacts/aletheia-audiobook-service-2.40.tar.gz`. После восстановления доступа нужны резервная копия jobs.db3, обновление службы по `server/audiobook/README.md`, проверка публичного маршрута и подключение устройства одноразовым кодом. Старый общий токен новая версия APK не использует; без обновления CMP создание новых аудиокниг недоступно. Чтение и воспроизведение уже сохранённых файлов работают локально.