Files
hope-voice-api/.artifacts/20260831-105824-plan-code-ui-audit/iterations/05-request.md
T
2026-08-31 19:50:46 -04:00

25 lines
4.5 KiB
Markdown

# Iteration 05 Request
- Task: 20260831-105824-plan-code-ui-audit
- Requested by: build from `iterations/04-review.md`
- Owner: coder
- Status: changes-requested
## Required Corrections
1. Regenerate `Voice.xcodeproj` after all test files are present. Fix the stream URL expectation to `/media/api/stream/{id}` and make the conversation-state EMA test cross the threshold deterministically. The final log must list all five test files/suites and the mathematically expected test count; do not infer coverage from file contents.
2. Replace the two-store transcript rendering with one canonical visible collection. Recommended minimal shape: initialize `TranscriptHandler.events` from the persisted history snapshot, append/update live events there, trim finals to 50, render only `events`, do not clear restored events on Start, and provide one `clearAll()` that clears visible rows, dedupe state, and persistence. Remove `TranscriptHistory.add`'s permanent adjacent-text dedupe.
3. Make cross-source dedupe source-aware and clock-testable. Record `(role, normalized text, source, timestamp)` and suppress only the opposite-source copy within the window; same-source repeated utterances must remain valid even inside the window. Inject a `now` closure for deterministic before/after-window tests. Cover both source orders, interleaving, same-source immediate repeats, post-window opposite-source text, restoration, max-50, live append, and clear.
4. Implement real server URL Apply semantics. `SettingsView` must keep a local draft, validate only on explicit Apply/submit, show an inline error, and persist only accepted values. `SettingsStore` must sanitize legacy invalid persisted values once at initialization. Conversation must track the URL used by the current session, serialize replacement, and apply one pending accepted URL after an active session reaches idle. Move `VoiceSession.state = .idle` to the end of explicit disconnect cleanup so idle means teardown is complete. Media must consume the last accepted valid setting and never silently derive a fallback from an invalid draft.
5. Make room teardown intentional, idempotent, and complete. Set an intentional/teardown flag and externally visible failure/transitional state before awaiting `room.disconnect()`. Ignore the resulting `.disconnected` callback. Use fresh-room cleanup for the first agent-timeout retry and every final token/connect failure (not only timeout). Retry from `.failed` must always start with a fresh room. Avoid recursive teardown and preserve wake-lock/media cleanup.
6. Make no-resume media interruption safe against polling and request failure. Track whether playback was active before interruption and a separate resume-suppression flag. Suppress reconcile-driven play while interruption/suppression is active. For should-resume, synchronize server resume then clear suppression/play only if scope/generation still match. For no-resume, keep suppression even if pause control fails; clear it only on a later explicit user play/resume action or confirmed coherent paused state. Add deterministic state tests through a small internal seam if practical.
7. Complete resource-loader lifecycle: key tasks by `ObjectIdentifier(loadingRequest)` directly; serialize request/task/loader maps on one queue (a main URLSession delegate queue is acceptable); call `removeLoader` whenever MediaPlayerController replaces or clears the prior AVURLAsset; for 206 set full content length only when Content-Range provides a known total, never fall back to range `expectedContentLength`; for 200 use expectedContentLength. Ensure cleanup occurs on success, error, cancellation, and item replacement. Add discovered focused tests.
8. Serialize microphone interruption operations. Keep a task/token/sequence for the interruption-owned mute; on end wait for or supersede the begin operation so mute/unmute cannot complete out of order. Resume only when the begin sequence started from an active mic, the mute actually succeeded, generation still matches, text mode is off, and `.shouldResume` is present. Cancel/invalidate on disconnect/failure/new begin. Document device-only residual qualification.
## Verification And Deliverables
- Run `xcodegen generate`, complete XcodeBuildMCP tests, separate build, and `git diff --check`.
- Inspect the test log and report exact suites and total, not arithmetic claims unsupported by discovery.
- Write `iterations/05-implementation.md`; update `implementation.md` and manifest without deleting history.
- Return to independent reviewer; do not claim approval yourself.