Skip to content

fix(ios-voice): fold the #199 post-merge review notes - #202

Merged
kpmmmurphy merged 1 commit into
masterfrom
fix/ios-voice-review-folds
Sep 4, 2026
Merged

fix(ios-voice): fold the #199 post-merge review notes#202
kpmmmurphy merged 1 commit into
masterfrom
fix/ios-voice-review-folds

Conversation

@kpmmmurphy

Copy link
Copy Markdown
Contributor

The second claude-review round on #199 landed after the merge with two cosmetic notes; this folds both.

  • Generation-stamped progress tick — a cancelled download's last queued didWriteData could paint one frame of stale percentage over a fresh re-pick. The closure now guards on voicePrepareGeneration == generation, like the rest of the file.
  • Built-in pick clears a stale .failed bannervoiceLoad is reset unconditionally on an explicit Built-in pick (was: only while active). The Mac's selectVoiceTier shares the rough edge; tracked under Mac: picking Built-in mid-download lets the finished M1K3 Voice download swap in anyway #200.

Verify-by-launch (app glue, no pure seam). iOS simulator shell builds.

🤖 Generated with Claude Code

https://claude.ai/code/session_01K2kJAPEHTFU34uKiGArFSP

…amped progress tick, Built-in pick clears a stale failure

Two cosmetic notes from the second claude-review round on #199 (landed after
the merge):
- The download progress closure guarded on `.downloading` but not on the
  generation, so a cancelled download's last queued tick could paint one
  frame of stale percentage over a fresh re-pick. Now guarded on
  `voicePrepareGeneration == generation` like everything else in the file.
- An explicit Built-in pick reset `voiceLoad` only while active, so a
  `.failed` banner from an earlier attempt stayed under a row that now reads
  Built-in. Reset unconditionally. (The Mac's selectVoiceTier shares the
  rough edge — #200.)

Verify-by-launch (app glue, no pure seam). iOS simulator shell builds.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K2kJAPEHTFU34uKiGArFSP

# ── MurphySig ──────────────────────────────────────────────────────
# Significant decision in this commit? Sign it. https://murphysig.dev/spec
# ───────────────────────────────────────────────────────────────────
@netlify

netlify Bot commented Sep 3, 2026

Copy link
Copy Markdown

Deploy Preview for m1k3 canceled.

Name Link
🔨 Latest commit f37b5ac
🔍 Latest deploy log https://app.netlify.com/projects/m1k3/deploys/6a99e986218b290008a34a5a

@claude

claude Bot commented Sep 3, 2026

Copy link
Copy Markdown

Review — PR #202

Small, tightly-scoped fix folding two cosmetic notes from the #199 post-merge review. Both changes check out — verified against the surrounding state machine, not just the diff.

1. Generation-stamped progress tick (AppCore+VoiceOutput.swift:83-87)

guard let self, voicePrepareGeneration == generation, case .downloading = voiceLoad else { return }

Confirmed real: prepareM1K3Voice() only bumps voicePrepareGeneration when voicePrepareTask == nil, and the only way to get a new task while an old one exists is via selectVoiceTier(.builtin) cancelling it first. A cancelled task's kokoro.prepare progress closure can still have a Task { @MainActor ... } already queued on the main actor before the cancellation is observed downstream — without the generation check, that stale tick would land after the next generation has already re-set voiceLoad = .progress(0) and painted a wrong percentage over the fresh download. This mirrors the exact pattern already established for warmGeneration in warmSelectedBrain() (AppCore.swift:445-465), so it's consistent with precedent elsewhere in this file rather than a new idiom. Good catch, correct fix.

2. Built-in pick clears a stale failure unconditionally (AppCore+VoiceOutput.swift:54-56)

voiceLoad = .idle (was: if voiceLoad.isActive { voiceLoad = .idle })

.failed is not .isActive (see ModelLoadState.isActive, Sources/M1K3Inference/ModelLoadState.swift:47-52), so a prior download failure left the banner up under a row that now correctly reads Built-in. Checked VoiceOutputSection.swiftvoiceLoad is read-only for rendering there, so the unconditional reset is safe; no other state depends on the transition being conditional. Also confirmed the PR description's claim: the Mac's selectVoiceTier (AppEnvironment.swift:2353) still has the old if voiceLoad.isActive guard, so the "shared rough edge, tracked under #200" note is accurate, not just asserted.

Other checks — Concurrency: both closures are already @MainActor-isolated with the standard guard let self weak-capture; the new generation check adds no new isolation surface, no bare locks. Provenance: the added Review: header line is additive to the existing Signed: block, doesn't rewrite prior entries — correct MurphySig discipline. Tests: none added, and per CLAUDE.md this is app-glue (M1K3iOSApp/, not Sources/*) — verify-by-launch is the right bar, MLX/Kokoro can't run under swift test anyway. Architecture: no logic leaked anywhere it shouldn't be, no new deps.

Nothing to flag — clean, well-verified fix, nice tie-back to the warmGeneration precedent.

@kpmmmurphy
kpmmmurphy merged commit a1ded45 into master Sep 4, 2026
20 checks passed
@kpmmmurphy
kpmmmurphy deleted the fix/ios-voice-review-folds branch September 4, 2026 17:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant