Archived
Redesign Hope iOS UI, harden playback, and document project handoff
This commit is contained in:
1 parent
40aaf4fea7
commit
24f95639dc
24 files changed
+1470
-594
No files matched your search
@@ -0,0 +1,38 @@
|
||||
# NAS deployment — 2026-09-08
|
||||
|
||||
The `voice` container on `192.168.86.2` hosts LiveKit, the voice agent,
|
||||
token service, music API and nginx. The app connects to
|
||||
`https://192.168.86.2:9178`. Docker uses host networking and an
|
||||
`unless-stopped` restart policy.
|
||||
|
||||
- Image: `hope-voice-api-voice:68f4c46-ios-audio`.
|
||||
- LLM: **qwen2.5-vl-3b**, through OpenWebUI at `http://192.168.86.2:3005/api`.
|
||||
- Speech: existing Azure configuration, unchanged.
|
||||
- Persistent certs, skills and music: `/mnt/user/dev/hope-voice-api` mounts.
|
||||
- Build source: `/mnt/user/dev/hope-voice-deploy-68f4c46`, a separate clean
|
||||
archive plus the iOS audio compatibility patch. The pre-existing dirty
|
||||
backend checkout was not overwritten.
|
||||
- Local compatibility source: sibling `hope-voice-api/web/media_server.py`;
|
||||
regression test: `hope-voice-api/tests/test_ios_audio.py`.
|
||||
|
||||
The music service retains original WebM files. An explicit `?format=m4a`
|
||||
request generates and caches AAC audio under `media/files/ios`, serving
|
||||
byte ranges for iOS playback and seeking. Browser requests remain unchanged.
|
||||
|
||||
## Health and rollback
|
||||
|
||||
```sh
|
||||
ssh [email protected] 'docker inspect --format "{{.State.Status}} {{.State.Health.Status}}" voice'
|
||||
```
|
||||
|
||||
The stopped container `voice-before-ios-audio` retains the baseline deployment.
|
||||
If rollback is needed, first inspect both containers, then stop the current
|
||||
`voice`, rename it to a unique recovery name, rename `voice-before-ios-audio`
|
||||
to `voice`, and start it. This restores the baseline without deleting images,
|
||||
containers or the music library; it does not include iOS AAC conversion.
|
||||
|
||||
`scripts/deploy-backend.sh` records the launch configuration and refuses to
|
||||
replace an existing `voice` container. Run it on the NAS only after building
|
||||
the named image and explicitly handling the existing container. It reads
|
||||
credentials on the NAS and never prints them. No source changes were pushed;
|
||||
future CI deployments must include the compatibility patch to preserve it.
|
||||
@@ -33,8 +33,8 @@ ensure the server cert pin is current (see README — re-export after any server
|
||||
|
||||
## 4. Audible media playback
|
||||
|
||||
- [ ] Requires a track in an iOS-decodable format (m4a/aac/mp3) — current library tracks
|
||||
are webm and will fail with `-11828` until the server serves a supported format.
|
||||
- [ ] The deployed server now serves cached AAC for library tracks requested with
|
||||
`?format=m4a`; verify actual speaker/headphone output on hardware.
|
||||
- [ ] Play a library track: audio is audible, now-playing card shows art/title/status.
|
||||
- [ ] Pause / ±10 s / stop / seek all work; agent mics off while playing
|
||||
(`media_state` published), mics back on when stopped.
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
# Project status and handoff
|
||||
|
||||
Last updated: 2026-09-09.
|
||||
|
||||
## Current direction
|
||||
|
||||
Keep **Qwen 2.5**. The user explicitly canceled the earlier request to switch to
|
||||
a ChatGPT subscription/device-token login. Do not revive that migration because
|
||||
an old saved goal mentions it. Current work is the native iOS UI/UX redesign,
|
||||
restoring the music/AI server, and end-to-end qualification.
|
||||
|
||||
The UI and playback changes are implemented, and the NAS deployment was verified
|
||||
on September 8. Full app qualification is **not complete**: physical-device tests
|
||||
and some broader live scenarios remain. This report summarizes prior evidence;
|
||||
server health and device availability must be rechecked when resuming.
|
||||
|
||||
## Completed work
|
||||
|
||||
### Native interface and usability
|
||||
|
||||
- Reorganized the app into native **Talk, Music, Activity** tabs, sharing one session.
|
||||
- Replaced the large animated orb with a compact waveform/status presentation;
|
||||
added a clearer welcome screen, Voice/Type selection before connecting, explicit
|
||||
start/end controls, microphone meter, and recoverable connection errors.
|
||||
- Improved transcript readability, timestamps, live updates, copy/selection,
|
||||
follow-latest scrolling, and explicit Cancel/Clear confirmation.
|
||||
- Reworked Settings around voice, input mode, model, and connection; server changes
|
||||
require an explicit validated save. Voice selection persists.
|
||||
- Improved Music library/search navigation, now-playing controls, seek/volume,
|
||||
empty/loading/error states, and validated station-entry sheet.
|
||||
- Improved Activity hierarchy and task detail presentation with an active-task badge.
|
||||
- Removed forced dark appearance; adopted adaptive system styling, Dynamic Type,
|
||||
and larger interaction targets, informed by the Impeccable native-iOS guidance.
|
||||
|
||||
### Functional fixes
|
||||
|
||||
- Observed nested transcript/state/task objects so asynchronous updates render.
|
||||
- Preserved latest-wins server replacement; clear old media when switching servers.
|
||||
- Sent standalone media controls and reports to the default server room.
|
||||
- Refreshed track metadata as downloads become ready; exposed request/decoder errors.
|
||||
- Loaded artwork through pinned TLS for the NAS self-signed certificate.
|
||||
- Requested cached AAC (`?format=m4a`) for YouTube library tracks on iOS.
|
||||
- Corrected AVFoundation's content type to a UTI rather than an HTTP MIME string.
|
||||
- Changed the pinned media loader to deliver 256 KB byte ranges instead of buffering
|
||||
an entire song before delivering usable audio, addressing a reproduced timeout.
|
||||
|
||||
### Tests and tooling
|
||||
|
||||
- Installed XcodeBuildMCP and its skills; used it for simulator build/run/test work.
|
||||
- Added the `VoiceUITests` target in `project.yml` and regenerated the Xcode project.
|
||||
- Added isolated DEBUG UI-test preferences and optional fixtures; normal application
|
||||
preferences are not reset by those UI-test launch arguments.
|
||||
- Added media-control/error/metadata tests and opt-in real-NAS UI tests.
|
||||
- Live tests retain failure screenshots/UI hierarchy and attempt to stop music
|
||||
they initiated even when an assertion fails.
|
||||
|
||||
## Backend deployment and cross-repository dependency
|
||||
|
||||
SSH host: `[email protected]` (Unraid). App URL: `https://192.168.86.2:9178`.
|
||||
|
||||
- `voice` image: `hope-voice-api-voice:68f4c46-ios-audio`, host networking,
|
||||
restart policy `unless-stopped`. Includes LiveKit, voice agent, token service,
|
||||
media API, and nginx.
|
||||
- LLM: `qwen2.5-vl-3b` through existing OpenWebUI at
|
||||
`http://192.168.86.2:3005/api`. Existing Azure speech configuration retained.
|
||||
- `voice`, `open-webui`, and `local-vl-models` were present and healthy when the
|
||||
user suspected deletion. Do not recreate healthy services unnecessarily.
|
||||
- Original library, certificates, and skills were retained under
|
||||
`/mnt/user/dev/hope-voice-api`; the dirty remote checkout was not overwritten.
|
||||
- Separate deployment source: `/mnt/user/dev/hope-voice-deploy-68f4c46`.
|
||||
- Stopped rollback container: `voice-before-ios-audio`.
|
||||
- Backend AAC conversion preserves original WebM files and serves cached AAC with
|
||||
byte-range support. Browser/raw requests retain their original behavior.
|
||||
|
||||
**Important:** the backend patch and its test are in a different local repository:
|
||||
`/Users/shane/dev/hope-voice-api/web/media_server.py` and
|
||||
`/Users/shane/dev/hope-voice-api/tests/test_ios_audio.py`. They were still uncommitted
|
||||
at this handoff. Committing/pushing `voice-ios` does **not** publish those files.
|
||||
The deployed image contains the patch, but a future backend CI rebuild can lose it
|
||||
unless it is committed and deployed through that repository's workflow. Inspect
|
||||
that workflow before pushing: it may replace the live container.
|
||||
|
||||
Launch configuration and rollback details: [DEPLOYMENT.md](DEPLOYMENT.md).
|
||||
Do not copy credentials or `.env` contents into documentation or commits.
|
||||
|
||||
## Verification performed
|
||||
|
||||
Project `Voice.xcodeproj`, scheme `Voice_iOS`, iPhone 17 Pro simulator.
|
||||
|
||||
- 68 unit tests passed; five offline UI tests passed (navigation/error recovery,
|
||||
settings persistence/validation, music validation, transcript/task UI, large text).
|
||||
- Real NAS tests verified Qwen replies, background task completion, reconnect,
|
||||
library loading, advancing playback time, pause, forward-seek control and stop.
|
||||
- Qwen/task/reconnect passed three consecutive iterations.
|
||||
- Music initially failed intermittently. Logs captured an AVPlayer timeout while
|
||||
buffering a whole 6 MB response. After bounded-range delivery, three consecutive
|
||||
live playback iterations passed. The earlier isolated agent-join failure remains
|
||||
unexplained; do not claim all intermittent connection issues are resolved.
|
||||
- Backend integration: 16 passed, 7 skipped, 2 deselected.
|
||||
- Backend AAC regression: one passed (conversion, cache reuse, original preservation,
|
||||
and byte ranges); deployed range request returned HTTP 206.
|
||||
- The final bounded-range change was verified by focused playback repetitions,
|
||||
not a new full combined regression run.
|
||||
|
||||
Exact result-bundle names and qualifications: [VERIFICATION.md](VERIFICATION.md).
|
||||
Artifacts live on this Mac under the XcodeBuildMCP workspace, not in Git.
|
||||
|
||||
## What remains, in order
|
||||
|
||||
1. **Pair the physical iPhone.** Latest check detected it on USB and reported iOS
|
||||
26.6.1, device ID `BF93D35E-0853-5470-A125-6EB0DB3F17AB`, state `unpaired`.
|
||||
The user had unlocked it but could not see it in Finder. Last guidance was to
|
||||
enable iOS devices in Finder's Sidebar settings and accept any accessory/Trust
|
||||
prompts. Recheck current state rather than repeating old cable assumptions.
|
||||
2. **Build, sign, install and run on that iPhone.** No successful device install is
|
||||
recorded. Check Developer Mode, trust, signing team/profile, and LAN access.
|
||||
3. **Qualify real audio:** microphone capture, TTS audibility, speaker/headphones,
|
||||
barge-in, media/voice handoff, Siri/phone interruptions, lock/background behavior,
|
||||
microphone-permission-denied fallback, and network-loss recovery. Some checks
|
||||
require the user's speech/listening or a real interruption; simulator state tests
|
||||
do not prove them. Follow [DEVICE_TESTING.md](DEVICE_TESTING.md).
|
||||
4. **Broader regression:** rerun the full suite after the range-loader change; test
|
||||
longer playback, seek near EOF, slow network/cancellation and server replacement.
|
||||
Exercise new downloads, test-owned station add/play/remove, and voice/model
|
||||
selection against the live agent. Do not delete the user's existing library song.
|
||||
5. **Final visual/accessibility pass:** inspect all populated/error screens in light
|
||||
and dark mode, large text and small-device layouts; test VoiceOver and focus.
|
||||
The existing large-text navigation test is not a full accessibility audit.
|
||||
6. **Publish the backend compatibility source safely** in the sibling repository
|
||||
and ensure its normal deployment preserves mounts, certificates and Qwen settings.
|
||||
7. Update this report with results and remaining limitations. Do not mark the whole
|
||||
app qualified until the outstanding end-to-end gates have evidence.
|
||||
|
||||
## Repository handoff
|
||||
|
||||
The iOS work and this report belong to branch `feat/ios-app`, remote `origin`
|
||||
(`https://git.srmr.xyz/snowspeeder/voice-ios.git`). The requested handoff commit
|
||||
includes the implementation, tests, deployment notes and startup instructions.
|
||||
Check Git history/remote status for the final commit and push result.
|
||||
@@ -0,0 +1,77 @@
|
||||
# Verification — 2026-09-08
|
||||
|
||||
## Scope and implementation
|
||||
|
||||
The requested model migration was canceled: Qwen 2.5 remains configured.
|
||||
The native redesign separates Talk, Music and Activity; simplifies the welcome
|
||||
and connection controls; supports light/dark appearance and Dynamic Type;
|
||||
adds recoverable error states; and gives transcript clearing explicit confirmation.
|
||||
The Impeccable native-iOS guidance informed system controls, hierarchy, readable
|
||||
spacing and touch targets. Settings, transcripts and task updates are observed
|
||||
directly so asynchronous changes render promptly.
|
||||
|
||||
Music fixes include standalone control requests, current download metadata,
|
||||
visible failures, pinned artwork, server-change cleanup, cached AAC delivery,
|
||||
and correct AVFoundation content-type identifiers in the pinned resource loader.
|
||||
|
||||
## Evidence
|
||||
|
||||
Project: `Voice.xcodeproj`; scheme: `Voice_iOS`; simulator: iPhone 17 Pro.
|
||||
|
||||
- 68 unit tests passed, including standalone media controls, retry error clearing,
|
||||
download metadata, transcript persistence/deduplication, session replacement,
|
||||
and interruption state handling.
|
||||
- Five offline UI tests passed: navigation/offline recovery, voice persistence and
|
||||
URL validation, music search failure/station validation, transcript confirmation
|
||||
and task details, and accessibility-size navigation.
|
||||
- Two live UI tests passed together against the NAS at 17:56 UTC: real Qwen
|
||||
response, background task completion, disconnect/reconnect, library playback
|
||||
with advancing media time, pause, forward seek and stop.
|
||||
- Backend integration run: 16 passed, 7 skipped, 2 deselected. This is not a claim
|
||||
that the skipped or slow integration cases were verified.
|
||||
- AAC conversion regression: one passed, checking original-file preservation,
|
||||
AAC output, cache reuse and HTTP byte ranges. Deployed range request returned 206.
|
||||
|
||||
XcodeBuildMCP result bundles are under
|
||||
`~/Library/Developer/XcodeBuildMCP/workspaces/voice-ios-9eb036fdea81/result-bundles/`:
|
||||
|
||||
- Unit/offline UI: `test_sim_2026-09-08T11-48-52-164Z_pid87175_79b1a610.xcresult`.
|
||||
This combined run's two live cases failed after long stalls; its unit/offline
|
||||
results above passed.
|
||||
- Latest live pair: `test_sim_2026-09-08T17-56-51-984Z_pid30949_ec504db2.xcresult`.
|
||||
- Earlier live rerun: `test_sim_2026-09-08T17-46-07-841Z_pid30949_bd804a04.xcresult`
|
||||
failed agent join and advancing playback. Their intermittent cause has not
|
||||
been established. The subsequent passing pair did not require a server restart.
|
||||
|
||||
## Not yet qualified
|
||||
|
||||
Passing simulator tests do not prove audible speaker/headphone output, microphone
|
||||
capture, barge-in, phone/Siri interruption recovery, background audio, or network
|
||||
loss recovery on hardware. Follow `DEVICE_TESTING.md` with a physical iPhone on
|
||||
the LAN. Navigation at large text sizes is tested, not a complete VoiceOver audit.
|
||||
Live tests use an existing library track; they do not prove new YouTube downloads
|
||||
or every radio stream format.
|
||||
|
||||
## Repeatability follow-up — 18:04 UTC
|
||||
|
||||
Three consecutive Qwen/task/reconnect iterations passed. Music passed twice and
|
||||
failed on the third iteration; runtime logs captured AVPlayer's request timeout
|
||||
while the TLS loader buffered a whole 6 MB response. The loader now delivers
|
||||
bounded 256 KB ranges to AVPlayer, retaining cancellation and EOF handling.
|
||||
After that change, **all three consecutive live playback iterations passed**
|
||||
in about 13 seconds each. This addresses the observed music buffering failure;
|
||||
the earlier isolated agent-join failure has not been reproduced or explained.
|
||||
|
||||
- Reproduction bundle: `test_sim_2026-09-08T18-00-03-993Z_pid30949_49da9d2c.xcresult`.
|
||||
- Post-fix playback bundle: `test_sim_2026-09-08T18-04-30-014Z_pid30949_df323119.xcresult`.
|
||||
- Live tests now attach failure screenshots and UI hierarchy, and attempt to stop
|
||||
test-initiated music during teardown even after an assertion failure.
|
||||
|
||||
The initial hardware check found an unavailable iPhone. A later USB check detected
|
||||
the phone running iOS 26.6.1, explicitly marked **unpaired** by XcodeBuildMCP.
|
||||
No successful device install or hardware qualification is recorded. See
|
||||
`PROJECT_STATUS.md` for the current pairing blocker and next steps.
|
||||
|
||||
Deployment and rollback are recorded in `DEPLOYMENT.md`. The NAS image includes
|
||||
the compatibility patch; the sibling backend source still requires its own commit
|
||||
and safe deployment workflow. See `PROJECT_STATUS.md` for repository handoff scope.
|
||||
Reference in new issue
Block a user