feat: hardening, error states, interruption handling, a11y (Phase 8)
This commit is contained in:
1 parent
9f1f26ba54
commit
12ded179eb
6 files changed
+233
-38
No files matched your search
@@ -27,7 +27,7 @@ Goal: full-parity native iOS app per UPDATE_PATH.md, verified in simulator via X
|
||||
- [x] Phase 5: media player — commit 0af944e (webm playback blocked by iOS AVPlayer; see status below)
|
||||
- [x] Phase 6: media search, choices, library panel (commit cbf1830)
|
||||
- [x] Phase 7: background tasks panel (commit af296da)
|
||||
- [ ] Phase 8: polish/hardening/parity pass
|
||||
- [x] Phase 8: polish/hardening/parity pass (commit pending)
|
||||
- [ ] Phase 9: docs & handoff
|
||||
|
||||
## Phase 2 status
|
||||
@@ -151,6 +151,37 @@ Notes:
|
||||
- Screenshot captured at /tmp/taskpanel.png (model can't view images; verified via UI snapshot text + logs instead).
|
||||
- No server/agent changes needed — the task dispatch pipeline already worked; only the iOS client was missing.
|
||||
|
||||
## Phase 8 status (2026-08-30 ~13:40)
|
||||
Done:
|
||||
- **Stale-room guards**: `sessionGeneration` in VoiceSession, `pollGeneration` in MediaPlayerController. All async callbacks check generation before mutating state. RoomDelegate methods check `self.room === room`. Prevents post-disconnect mutations.
|
||||
- **Audio interruption**: `handleAudioInterruption` in VoiceSession (mute mic on begin, resume on end if shouldResume). MediaPlayerController pauses/resumes AVPlayer on interruption.
|
||||
- **Error states**: `isReconnecting` published property + reconnect banner in ConversationView. `stateError` published property + error banner in MediaPanelView.
|
||||
- **Accessibility**: OrbView accessibilityLabel/Value (maps state to "Listening", "Thinking", etc.). ConversationView: Send, End, Tasks, Media, Settings labels. MediaPanelView: transport controls + refresh library labels.
|
||||
- **Server URL change fix**: Changed `session` from `@ObservedObject` to `@State` in ConversationView so it can be reassigned inside async closures. Added `.onReceive(session.objectWillChange)` for observation. `.onChange(of: settings.serverURL)` disconnects old session and creates a new one when idle.
|
||||
|
||||
Verified in simulator:
|
||||
- Build: zero errors, zero warnings.
|
||||
- App launches cleanly.
|
||||
- Server URL change (invalid → valid) triggers session recreation without crash.
|
||||
- Connect/Disconnect/Reconnect matrix: Start → Ready → Hang up → Start again (3x). No crashes, state resets cleanly.
|
||||
- Logs confirm no post-disconnect mutations (stale callbacks guarded).
|
||||
|
||||
Web parity checklist (vs /Users/shane/dev/hope-voice-api/web/app.js):
|
||||
- [x] Token auth + LiveKit connect
|
||||
- [x] Agent wait + agent_ready
|
||||
- [x] Voice/model pickers + sync-on-join
|
||||
- [x] Text mode toggle + barge-in hint
|
||||
- [x] Transcript list + history
|
||||
- [x] Media player (poll, reconcile, transport, seek)
|
||||
- [x] Media search + choices + library
|
||||
- [x] Background tasks panel
|
||||
- [x] Stale-room guards (=== room checks)
|
||||
- [x] Audio interruption handling
|
||||
- [x] Error states (reconnect, mic error, media error)
|
||||
- [x] Accessibility labels
|
||||
- [ ] Web-only: drag-to-seek on waveform (iOS uses slider — acceptable)
|
||||
- [ ] Web-only: keyboard shortcuts (N/A on iOS)
|
||||
|
||||
## Subagent notes
|
||||
- Small context model: keep prompts self-contained, point at this file + UPDATE_PATH.md
|
||||
- Watch for loops (repeated identical commands) — kill and redirect if seen
|
||||
|
||||
Reference in new issue
Block a user