Files
ios/PLAN.md
T

41 KiB
Raw Blame History

MusicBridge iOS — план

Обновлено: 2026-09-14. Пользователь разрешил начать нативное iOS-приложение. Репозиторий: C:/Users/areso/iOS MusicBridge; origin — dev.yukinoki.ru/musicbridge/ios. Windows-агент — соседний проект C:/Users/areso/MusicBridge/MusicBridge.Agent.

Системный пульт 0.7.0 (8) — текущий этап

  • Реализация NowPlaying RemoteMediaSession и отдельного ExtensionKit target для iOS 27.
  • Кнопка включения/выключения в приложении; музыка продолжает играть на ПК.
  • Метаданные, обложка, play/pause, предыдущий/следующий трек, перемотка, громкость ПК.
  • Перед командой проверяются свежие capabilities и действующее сопряжение; команды не повторяются автоматически.
  • Токен хранится в общем Keychain, не передаётся в атрибутах системной сессии.
  • Перемотка переводится из позиции относительно трека в диапазон Windows API.
  • Выключение и удаление сопряжения удаляют доступ расширения; возврат запоздавшего restore не восстанавливает сессию.
  • Итоговый 91e305a: Actions 34785082289, Xcode 27, 36 XCTest без отказов, успешный Release archive. Первая попытка 34783380221 выявила Double/Float и исправлена.
  • Установка с подписью обоих расширений и общим Keychain; проверка на физическом iPhone.
  • Пункт управления: кнопки, перемотка, громкость; блокировка телефона, сон ПК, отзыв токена, повторная подпись.

IPA скачана в build/iPhone-0.7.0/MusicBridge-iPhone.ipa (без подписи). Локально проверены ZIP, ARM64 iPhoneOS всех трёх исполняемых файлов, совпадение версий, ExtensionKit extension point и общий Keychain suffix. SHA-256: a84e146a5259c0c7250dab829f2eb07093f33d5e212ff1e1880f6c3fd29d65ee. Логи тестов находятся в build/iPhone-0.7.0/tests, снимки — в preview. Просмотрены светлый плеер и дополнительный iPhone: кнопка пульта видна снизу, пояснения доступны прокруткой. Системная карточка NowPlaying на этих снимках не проверялась: для запуска нужен подписанный общий Keychain.

Ограничение iloader: проверен официальный исходник nab138/isideload, ветка apple-codesign-quick, commit f6a4d5dba717d72fc2af63eaba26b27ba44116be, который использует текущий iloader. isideload/src/sideload/bundle.rs обнаруживает расширения только в PlugIns, а NowPlaying размещается в Extensions. sign.rs берёт entitlements из profile, добавление shared Keychain реализовано для отдельных SpecialApp, не для MusicBridge. Поэтому обычную установку 0.7.0 через iloader нельзя считать поддержанной. Не переносить ExtensionKit в PlugIns наугад и не передавать токен через публичные атрибуты. Следующий этап установки: совместимый подписыватель или доработка iloader для ExtensionKit и общего Keychain с реальными provisioning profiles. Xcode signing всех трёх targets — вариант при наличии совместимого Mac и профилей; разрешение нового extension point бесплатной командой ещё не подтверждено на устройстве.

2026-09-14 пользователь попробовал установку 0.7.0: IXErrorDomain 2/8, родитель стал ru.yukinoki.musicbridge.<TeamID>, а remote остался ru.yukinoki.musicbridge.remote. Это подтверждает пропуск Extensions при переименовании. Дополнительно библиотека apple-codesign-quick также обходила только Frameworks/PlugIns. В tools/iloader добавлены патчи обоих уровней и воспроизводимая подготовка закреплённых upstream revisions. Отдельный ручной workflow iloader-compat.yml собирает portable Windows GUI; исходное приложение iloader на ПК не заменяется. Патч сохраняет публичные Bundle ID приложения до подписи, затем iloader сам применяет TeamID ко всем расширениям и получает для них настоящие Apple profiles. Shared Keychain для MusicBridge добавляется только при разрешении в profile.

  • Проверено чистое применение патчей к закреплённым исходникам.
  • Rust-тесты на переименование/обнаружение ExtensionKit, вложенную подпись и Keychain.
  • Готовый portable EXE и повторная установка исходной IPA 0.7.0 через него.
  • Подтвердить регистрацию NowPlaying и общий Keychain на iPhone.

Без APNs расширение читает ПК при команде; открытое приложение обновляет сессию при смене трека/статуса и периодически. Смена трека на самом ПК при приостановленном приложении не гарантирует автоматического обновления карточки. Фиктивное аудио не используется.

Инфраструктура — текущее состояние

  • SSH к macOS проверен: aresov@10.67.67.28, macOS 26.6.2, x86_64, около 459 ГБ свободно. Xcode не установлен. Локальный отдельный ключ: C:/Users/areso/.ssh/musicbridge_macos_ed25519 (закрытый ключ не включать в репо). Использовать C:/Windows/System32/OpenSSH/ssh.exe с -F NUL, -o ProxyCommand=none -o ProxyJump=none -o IdentitiesOnly=yes и этим ключом; другая установленная версия ssh не подключалась. Host key сохранён в known_hosts.
  • Xcode 27 требует Apple Silicon; эта Intel-виртуалка не подходит для SDK 27. CI переведён на GitHub-hosted xcode-27: Xcode 27.0 (27A5252f), Swift 6.4, SDK iOS 27.0. Actions 34764552877 для 1e14bf7: 32 XCTest, 0 отказов, успешный Release archive. IPA: build/iPhone-0.6.0-xcode27/MusicBridge-iPhone.ipa; проверены SDK 27, ARM64 приложения/расширения и структура пакета. Предпросмотр карточки просмотрен. Версия осталась 0.6.0 (7); новые функции в пересборке не добавлены. Просроченный тестовый сертификат создаётся с явными датами через cryptography==46.0.3 в отдельном venv, поскольку новый OpenSSL отвергает -days -1.
  • Пользователь подтвердил бесплатный Apple Account через iloader. Фоновая доставка APNs заблокирована отсутствием Push Notifications capability и соответствующей подписи. Платная Developer Program, App ID, ключ APNs и provisioning profile пока отсутствуют; не обещать работу push после простой смены Xcode. После появления доступа нужны регистрация токенов, отправитель обновлений с Windows/сервера и тестирование доставки на физическом iPhone.

Правила реализации

  • SwiftUI, без веб-клиента. Музыка играет на Windows.
  • Сверять контракт с Windows PROTOCOL.md; не менять серверный протокол молча.
  • Токены только в Keychain, проверка сертификата до сопряжения, запрет redirect.
  • Не повторять команды автоматически после потери ответа.
  • Не называть проверки Python сборкой Swift или запуском XCTest.
  • После этапа обновлять этот файл: реализация, проверки, ограничения, следующий шаг.

Реализовано в исходниках

  • Проект Xcode, shared scheme, iOS 17+, SwiftUI, без внешних зависимостей.
  • Модели состояния и команд v1; валидация HTTPS IPv4 домашней сети и QR-строки.
  • Ручное сопряжение, импорт приглашения, проверка SHA-256 DER-сертификата.
  • Keychain: адрес, отпечаток и bearer-токен; удаление локального сопряжения.
  • HTTPS-команды, обложка до 2 МиБ, поток WSS с ограничением размера сообщения.
  • Экран трека, возможности кнопок, прогресс, перемотка, громкость, mute.
  • Переподключение 1…16 секунд, watchdog потока, отключение в фоне, возврат.
  • XCTest исходники: диапазоны адресов, отказ опасным URL, отпечатки, QR/срок/коды, JSON Windows, расчёт позиции, формат команд.
  • GitHub Actions: сборка/тесты симулятора, логи, xcresult и артефакт приложения.

Проверки и следующие шаги

  • Первый успешный xcodebuild + XCTest на macOS: 7 тестов, 0 отказов.
  • Подключён GitHub remote polskikh13/musicbridgeios; Actions и чтение логов через gh работают.
  • Интеграционные тесты TLS: верный/чужой/истёкший сертификат, HTTPS и WSS.
  • Пройдены интеграционные проверки redirect, 401, возврата из фона и загрузки обложки.
  • Проверить реальный Keychain после переустановки/блокировки и отзыв устройства на физическом iPhone.
  • Установить на физический iPhone: пользователь подтвердил установку через iloader 2026-09-12.
  • Первое подключение к настоящему Windows-агенту: пользователь подтвердил рабочий пилот на iPhone 2026-09-12.
  • Полная ручная проверка каждого действия, обложки и устойчивости в Яндекс Музыке и SoundCloud.
  • Камера для QR, запрос доступа, сообщение при отказе, остановка камеры при закрытии/уходе в фон.
  • Bonjour-поиск _musicbridge._tcp, список адресов ПК и восстановление адреса с сохранённым сертификатом.
  • QR через камеру работает на физическом iPhone — подтверждено пользователем после установки 0.2.0.
  • Отдельно проверить оба входа (встроенный сканер и стандартная камера), отказ в доступе к камере, Bonjour и смену IP на физическом iPhone.
  • Реализованы понятные ошибки сопряжения по кодам сервера, повтор загрузки обложки после 404 и ручной повтор.
  • Иконка приложения и обновлённый интерфейс подключения/плеера.
  • Просмотрены снимки 0.4.0: подключение, светлая/тёмная темы, iPhone SE и крупный текст.
  • Пользователь подтвердил работу 0.4.0 на iPhone: «всё вроде работает».
  • Локальная Live Activity и Dynamic Island: реализация отображения трека в 0.5.0.
  • Проверить Live Activity на экране блокировки и Dynamic Island после подписи через iloader.
  • LiveActivityIntent: предыдущий/следующий трек, play/pause и обновление — 0.6.0.
  • Проверить команды из Live Activity/Island при блокировке на физическом iPhone.
  • Команды Siri.
  • NowPlaying RemoteMediaSession (iOS 27+): SDK 27 и remote-media extension реализованы в 0.7.0; установка и физическая проверка — в текущем этапе выше.
  • APNs: отдельный проект обновлений при приостановленном приложении, если нужен постоянный актуальный трек в фоне.

Ограничения: хранится один доверенный ПК; адрес при смене IP восстанавливается через Bonjour, если доступны объявления того же агента. Новый адрес сохраняется только после успешного HTTPS-запроса с прежним отпечатком и токеном. Нет фонового воспроизведения, App Store/TestFlight и подписанной IPA. Потеря ответа на успешное сопряжение может оставить устройство на ПК: удалить его в окне агента перед повтором. Облачный runner не имеет доступа к домашней LAN.

Проверка на iPhone 2026-09-12

  • Windows GUI запущен с --tray --lan, порт TCP 8765 слушает.
  • На iPhone первая попытка сопряжения завершилась ошибкой недействительного сертификата сервера. Установка приложения уже работает; это отдельная TLS-проблема.
  • Ошибка воспроизведена настоящим HTTPS-запросом в iOS Simulator: старый код возвращает NSURLErrorDomain -1202 даже с верным отпечатком. Одни ATS-исключения её не устранили. Исправление: обрабатывать server trust также в URLSessionTaskDelegate.didReceive, направляя его в общую проверку отпечатка и срока сертификата. После этого HTTPS и WSS проходят.
  • Подготовлены ATS-исключения только для RFC1918 CIDR: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16. Начиная с iOS 17, для IP нужны явные исключения. Клиент продолжает требовать HTTPS, точный SHA-256 отпечаток, действующий сертификат и запрещает redirect. Глобального отключения ATS нет.
  • Добавлены настоящие HTTPS/WSS проверки в симуляторе с сертификатом того же типа, что у агента: RSA 2048, самоподписанный, CA:FALSE, SAN localhost/127.0.0.1, срок пять лет. Отдельно проверяются чужой отпечаток и истёкший сертификат. tools/tls_fixture.py запускается в CI перед сборкой тестов; закрытые ключи создаются временно на runner и не включаются в приложение или артефакты.
  • Сообщение «непригодные данные» при импорте приглашения пока не разобрано: пользователь попросил отложить его. Следующий этап — исправить импорт и добавить сканер QR, затем поиск ПК и проверки устойчивости.
  • 93f7c9c: Actions 34694138394 — 10 XCTest, 0 отказов, успешный Release archive. Версия 0.1.1 (build 2), IPA скачана в build/iPhone-0.1.1/MusicBridge-iPhone.ipa; локально проверены ZIP, iPhoneOS ARM64, версия и ATS-настройки внутри готовой IPA. После обновления пользователь подтвердил: «всё работает в пилотном режиме». Это подтверждает первую рабочую связку iPhone ↔ Windows; полная матрица ручных проверок и длительная работа пока не подтверждены.

Карта

  • MusicBridge/Models.swift: контракт и проверка входных данных.
  • BridgeClient.swift: сертификат, HTTPS, WSS, ограничения ответов.
  • KeychainStore.swift: хранение сопряжения.
  • PlayerStore.swift: состояние, команды, жизненный цикл и восстановление.
  • ContentView.swift: подключение и плеер.
  • QRScanner.swift: камера AVFoundation, доступ, сканирование и жизненный цикл.
  • DiscoveryStore.swift: Bonjour, разрешение адресов, TXT и безопасный выбор адреса.
  • ConnectionStorage.swift: доступ к Keychain и подмена хранилища для изолированных тестов жизненного цикла.
  • LiveActivityManager.swift: запуск, обновление, устаревание и завершение одной локальной Live Activity.
  • Shared/: ограниченный публичный снимок трека и общие SwiftUI-компоненты карточки.
  • MusicBridgeWidgets/: расширение WidgetKit, экран блокировки и все представления Dynamic Island.
  • MusicBridgeTests/: XCTest и пример Windows JSON.
  • tools/: генератор проекта, структурные проверки, выбор симулятора для CI.
  • .github/workflows/ios.yml: CI на macOS.
  • tools/package_ipa.sh: Release archive для настоящего iPhone и упаковка Payload.
  • tools/verify_ipa.py: проверка ZIP, Info.plist, ARM64 и платформы Mach-O (iOS, не Simulator).

QR и поиск ПК — 0.2.0 (build 3)

  • Добавлен сканер внутри приложения; после сканирования заполняются адрес, отпечаток и код, подключение запускает пользователь. Также зарегистрирована схема musicbridge://, приглашения принимаются через onOpenURL. Посторонний QR, повреждённый JSON и истёкший код дают понятную ошибку.
  • Регистрация URL-схемы устраняет отсутствие обработчика ссылки при чтении QR стандартной камерой. Исходное сообщение «непригодные данные» ещё нужно перепроверить на телефоне, точный источник той ошибки не был установлен.
  • Поиск использует NSBonjourServices и NetServiceBrowser. Объявления версии 1 принимаются только с допустимым SHA-256 и частным IPv4. При первом выборе найденного ПК пользователь сверяет полный отпечаток с его экраном.
  • При восстановлении адреса TXT служит только подсказкой: сертификат из сети не заменяет сохранённый. Чужой fingerprint не используется; токен отправляется только через соединение с прежним TLS pin. После успеха адрес обновляется в Keychain.
  • Поиск приостанавливается в фоне; адреса повторно разрешаются раз в 15 секунд, список ограничен 64 сервисами и 16 адресами на сервис. Есть повторный поиск и переход в настройки разрешений.
  • 397caf2: Actions 34694893204 — 14 XCTest, 0 отказов, Release archive успешен. Проверены формат объявления Windows, разбор sockaddr, отказы чужим данным, сохранение pin/token при смене адреса и .NET timestamp с семью дробными цифрами. Камера и реальный multicast iPhone ↔ Windows не эмулируются этими тестами.
  • Итоговый e384e9a: Actions 34695228108 — 14 XCTest без отказов и успешный Release archive. Экран подключения просмотрен на снимке симулятора; исправлен статус при возвращении без сохранённого ПК. IPA скачана в build/iPhone-0.2.0/MusicBridge-iPhone.ipa; проверены ZIP, ARM64 iPhoneOS, версия 0.2.0 (3), разрешение камеры, Bonjour и обработчик URL в готовом пакете. Пользователь подтвердил работу QR через камеру на iPhone. Следующий шаг: проверить Bonjour/смену IP и устойчивость, улучшить ошибки и восстановление обложки.

Следующие этапы — выполнять последовательно

  1. Устойчивость и ошибки — версия 0.3.0 (build 4). Исправления и автоматические проверки завершены. Следующий ручной шаг — проверка на iPhone.
  2. Интерфейс — версия 0.4.0 (build 5). Добавлены иконка, компактный экран QR, раскрываемые ручные поля, крупная play/pause, процент громкости и меню ПК. Сборка и 23 XCTest прошли; просмотрены темы, компактный экран и крупный текст. Пользователь подтвердил работу обновления на телефоне перед началом этапа 3.
  3. Системные интеграции — 0.6.0 (build 7). Добавлены прямые действия LiveActivityIntent. Убрана ошибка устаревания при обычном сворачивании; каждое нажатие перечитывает ПК. 32 XCTest и Release archive прошли. APNs и встроенный системный музыкальный пульт ещё не реализованы. Не имитировать фоновое аудио. Не обещать постоянный WSS при блокировке.
  4. Несколько сохранённых ПК — последующее расширение, сейчас сохраняется один.

Продолжение третьего этапа — 0.6.0:

  • Итоговый 43c78b2: Actions 34748340408 — 32 XCTest без отказов, успешный Release archive. IPA 0.6.0 (7) скачана в build/iPhone-0.6.0/MusicBridge-iPhone.ipa; проверены ARM64 iPhoneOS приложения и расширения, версии, метаданные интентов. Просмотрены светлая и тёмная карточки. Работа системного запуска LiveActivityIntent и Keychain после блокировки требует проверки на телефоне: обновить IPA, выключить/включить карточку, заблокировать, проверить next/previous/toggle/refresh; затем повторить после перезагрузки и первого unlock.
  • Пользователь сообщил, что карточка постоянно пишет об устаревших данных. Причина: PlayerStore.stop() вызывал unavailable() при каждом уходе в фон. Удалён этот вызов; реальные сетевые отказы продолжают отмечаться отдельно. Карточка показывает время последнего снимка и отдельные ошибки запросов.
  • Shared MusicControlIntent соответствует LiveActivityIntent. WidgetKit содержит определение интента, выполнение сети компилируется только в основной app target; iOS запускает процесс приложения без открытия UI. На компактном/минимальном Island кнопок нет: нужно раскрыть долгим нажатием. Кнопки не отключаются из-за старого снимка.
  • LiveActivityCommands: одно действие одновременно, проверка живой Activity и связи её ID с fingerprint текущего сопряжения. После чтения состояния повторно проверяется актуальность карточки, затем проверяются capabilities и отправляется максимум одна команда. Refresh вообще не отправляет команду. Повторов команд нет.
  • После успеха перечитывается трек и обновляется Activity. 401 завершает её; неизвестный результат и неудача чтения после успеха имеют разные сообщения. Нет бесконечного WSS/Bonjour в фоне; после смены IP сначала открыть приложение.
  • Keychain: AfterFirstUnlockThisDeviceOnly вместо WhenUnlockedThisDeviceOnly, чтобы команды работали при заблокированном iPhone. Существующий токен мигрирует при повторном включении карточки. Он не покидает Keychain и не попадает в payload. В UserDefaults сохраняется только соответствие ID активности и публичного pin. После обновления с 0.5.0 карточку выключить и включить заново в приложении.
  • HTTPS-тесты проверяют одну отправку next и новый трек, refresh без команды, закрытую карточку, неподдерживаемую команду, отсутствие повторов отказавшей команды, ошибку чтения после успешной команды. Физический запуск интента проверяется отдельно.
  • Ответ на вопрос пользователя о встроенном музыкальном центре: официальный NowPlaying RemoteMediaSession предназначен для внешнего воспроизведения. Metadata Apple указывает iOS 27.0. Текущий runner собирает Xcode 16.4: следующий этап — SDK/Xcode 27 и отдельное com.apple.nowplaying.remote-media расширение. Интеграция ещё не реализована.

История третьего этапа — Live Activities 0.5.0 (поведение фона изменено в 0.6.0):

  • Итоговый ddd44e8: Actions 34747772034 — 26 XCTest без отказов, сборка приложения и WidgetKit-расширения, успешный Release archive. IPA скачана в build/iPhone-0.5.0/MusicBridge-iPhone.ipa; проверены оба ARM64 iPhoneOS исполняемых файла, структура .appex, версии и NSSupportsLiveActivities. Светлый/тёмный предпросмотр карточки просмотрен: текст и отметка устаревания читаемы. Установка/регистрация Live Activity на физическом iPhone остаются ручной проверкой.
  • ActivityKit без push: старт только кнопкой пользователя при активном приложении и медиасессии. Восстанавливается существующая активность, дубли завершаются; после удаления пользователем автоматического пересоздания нет.
  • WidgetKit-расширение встроено в приложение. В attributes/content нет адреса ПК, токена, fingerprint или обложки; только публичные данные трека, ограниченные по UTF-8 (по 256 байт для названия и исполнителя).
  • Обычные позиции объединяются до одного обновления в пять секунд; смена трека, длительности или состояния воспроизведения отправляется сразу. Прогресс статический, соответствует последнему снимку. В фоне/без сети помечается устаревшим; staleDate через 15 секунд страхует внезапную остановку приложения.
  • Нет медиасессии, отзыв доступа, «Забыть компьютер» или ручное выключение — завершение. Нажатие карточки открывает musicbridge://player, не попадает в импорт QR.
  • Новые XCTest: позиция относительно startSeconds, нулевая длительность/пауза, чрезмерные Unicode-метаданные и размер Codable payload. Проверка IPA требует встроенную ARM64 iPhoneOS .appex, совпадающие версии и поддержку Live Activities.
  • CI-предпросмотр общей разметки карточки проверяет светлую/тёмную темы и устаревшие данные. Это не проверка системной регистрации ActivityKit/Island. На физическом iPhone проверить старт, блокировку, раскрытие Island, переход в плеер, возврат, удаление карточки, отсутствие автопересоздания, окончание сессии и отзыв доступа.
  • Следующие отдельные задачи: LiveActivityIntent с безопасным выполнением команды (проверить доступность Keychain/локальной сети при блокировке); Siri; APNs, если требуются актуальные данные после приостановки приложения. Постоянный WSS в фоне не реализован и не обещается. Windows-протокол не менялся.
  • Основание: Apple ActivityKit и WidgetKit extension.

Изменения второго этапа:

  • Итоговый aa0b0f0: Actions 34746477145 — 23 XCTest без отказов и успешный Release archive. Итоговая IPA скачана в build/iPhone-0.4.0/MusicBridge-iPhone.ipa; проверены ZIP, iPhoneOS ARM64, версия 0.4.0 (5), AppIcon в Info.plist и скомпилированный каталог Assets.car. Снимки находятся в build/iPhone-0.4.0/final-preview. На маленьком экране основные кнопки видны сразу; для нижней части громкости может требоваться прокрутка.
  • cbd3c0f: добавлены оригинальная иконка 1024×1024 и каталог AppIcon, карточка QR, раскрываемые ручные поля, меню ПК, крупная play/pause и процент громкости.
  • aa0b0f0: после просмотра iPhone SE уменьшена обложка по доступной высоте окна; размеры заданы явно, чтобы заглушка оставалась квадратной. Исполнитель выровнен по центру.
  • В Debug есть изолированный предпросмотр с примером трека и памятью вместо Keychain; в Release этот режим недоступен. CI сохраняет светлый/тёмный плеер, крупный текст, компактный экран и подключение. Ошибка Keychain -34018 на снимке подключения относится к неподписанному запуску в CI; доступ к Keychain на телефоне требует подписи.
  • Ручная проверка обновления: установить IPA через iloader, проверить иконку, сохранённое сопряжение, QR, меню ПК, перемотку и громкость; повторить с крупным системным шрифтом и тёмной темой. Реальную камеру и домашнюю сеть CI не проверяет.

Изменения первого этапа:

  • Итоговый bde6f7a: Actions 34712051233 — 23 XCTest без отказов, Release archive успешен. IPA 0.3.0 (build 4) скачана в build/iPhone-0.3.0/MusicBridge-iPhone.ipa; проверены ZIP, платформа iPhoneOS, ARM64 и версия. Экран подключения просмотрен на снимке симулятора.

  • Четыре попытки загрузить обложку, паузы 2/4/8 секунд, отдельное сообщение и кнопка ручного повтора. После 404 перечитывается состояние, чтобы заметить смену трека. Старая обложка не должна подменять новую после запоздавшего ответа.

  • При уходе в фон закрываются текущие соединения и незавершённое сопряжение; его поздний ответ не сохраняется. Если сервер уже создал запись устройства, пользователь получает указание удалить её перед повторным сопряжением.

  • Ответ 401 переводит приложение в состояние повторного сопряжения, останавливает автоматические повторы и сохраняет этот статус при возвращении из фона.

  • Понятные сообщения для invalid_code, pairing_closed, device_limit, storage_failed, HTTP-ошибок, сетевых сбоев и TLS. Текст отказа команды не стирается обновлением прогресса; сообщение можно скрыть. Команды не повторяются автоматически.

  • Успех команды и неудача последующего чтения состояния различаются в интерфейсе. После недоступности Keychain при запуске чтение повторяется при активации приложения.

  • Реальные HTTPS/WSS тесты используют временный сервер CI с задержками, 404/401/503, redirect, ошибками сопряжения и сменой обложки. Реальный пользовательский Keychain в этих тестах не изменяется. Сон ПК, Wi-Fi и системную блокировку надо проверить отдельно на физических устройствах.

Результаты 2026-09-10

  • 07322c2: успешный Actions run 34445566212. Добавлен Release archive и неподписанный IPA для Sideloadly. Скачан в build/Sideloadly/MusicBridge-iPhone.ipa (112334 байта). Локальная проверка ZIP, Info.plist и Mach-O подтвердила iPhoneOS ARM64, минимум iOS 17.0. Подпись и установка выполняются пользователем в Sideloadly; на физическом iPhone ещё не проверено. Инструкция добавлена в README.md.
  • a761431: успешный Actions run 34444563869, macos-15, Xcode 16.4, Swift 6.1.2, симулятор iOS 18.5; 7 XCTest прошли. Артефакты: MusicBridge-simulator и ios-test-results (лог и xcresult), хранение 7 дней.
  • Первый CI-прогон не дошёл до компиляции: исправлены регистр UDID и выбор runtime по версии активного SDK. Две регрессионные Python-проверки прошли локально.
  • Структурная проверка Python прошла: генератор детерминирован, ссылки проекта, состав исходников, Info.plist, схема и JSON согласованы.
  • В CI есть предупреждения инструментов о подписанных библиотеках XCTest, отсутствии AppIntents и Node 20 в checkout/upload-artifact v4; тесты прошли. Миграция Actions на актуальные версии — отдельное небольшое обновление.
  • Следующий шаг: интеграционные проверки TLS/WSS и UI, затем сканер QR/Bonjour. Физический iPhone, Apple-подпись и управление настоящим ПК ещё не проверены.