Skip to content

Swift best-practices: close the review backlog (F, G, docstrings, A)#21

Open
samkeen wants to merge 1 commit into
mainfrom
swift-best-practices-round-4
Open

Swift best-practices: close the review backlog (F, G, docstrings, A)#21
samkeen wants to merge 1 commit into
mainfrom
swift-best-practices-round-4

Conversation

@samkeen

@samkeen samkeen commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Completes planning/swift-best-practices-review.md — every actionable item is now applied. Only the cosmetic H (error-type naming) / I (formatter) and the declined preset → switch are intentionally skipped.

Changes

  • G — ModelStores six inits → one. Collapsed the six init overloads into a single nil-defaulted init(whisper:parakeet:cleanup:), each slot falling back to its real store via ??. The nil defaults sidestep the original blocker (a non-nil default arg can't call the @MainActor store init); every call site is unchanged.
  • F — stopAndTranscribe() teardown dedup. The two identical light teardowns (guard-else + success) collapse into one up-front block: capture a local session, nil the stored property, then finish()/cancel() on the local. Catch paths await session.cancel() on the local — the only cleanupAfterFailure() work not already done up-front — so behavior is preserved.
  • Docstrings (CodeRabbit gate). First pass over the transcriber entry-point spine + recording view model: ModelStores, RecorderViewModel, Transcriber/TranscriptionSession, TranscriberFactory, AppleSpeechTranscriber (was 0%). Targeted at the non-obvious — not metric-chased filler.
  • A — ParakeetDecoder per-step fatalError. Removed the per-decode-step joint_net[2] as? Linear cast + fatalError by retyping joint_net [Module][UnaryLayer], so the joint applies joint_net[2](activated) directly (no cast, no new stored property — which would have aliased a duplicate parameter key). Safe because MLXNN keys array children by runtime value (build(value:) inspects each element as Module), so joint.joint_net.2.* is keyed identically regardless of static element type.

Validation

  • xcodebuild build + 61-test suite green on the iPhone 17 Pro simulator.
  • A device-validated on the iPhone 15 Pro Max via ParakeetSmoke.run(): full model loaded under verify: .noUnusedKeys (throws if joint_net.2 goes unconsumed — it didn't), T2.1d decode substring check = PASS ✅, T2.1e chunking check = PASS ✅, peak 1345.5 MB (unchanged). Output is numerically identical to the pre-change path (same Linear, same weights).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved error handling during recording teardown and session failures with clearer error messages
    • Enhanced handling of edge cases in transcription
  • Refactor

    • Simplified initialization patterns for improved code reliability
    • Removed unsafe casting in decoder processing to enhance stability

Completes planning/swift-best-practices-review.md — every actionable item is
now applied; only cosmetic H/I and the declined preset→switch are skipped.

- G: ModelStores' six init overloads → one nil-defaulted init. The nil
  defaults sidestep the @mainactor default-arg blocker (the ?? fallbacks run
  in the init body); all call sites unchanged.
- F: RecorderViewModel.stopAndTranscribe() teardown dedup — the two identical
  light teardowns collapse into one up-front block (capture a local session,
  nil the stored one, finish/cancel on the local). Catch paths cancel the
  local, preserving behavior without the heavier cleanupAfterFailure().
- Docstrings: first CodeRabbit-gate pass over the transcriber entry-point
  spine + recording view model (ModelStores, RecorderViewModel, Transcriber/
  TranscriptionSession, TranscriberFactory, AppleSpeechTranscriber). Targeted,
  not metric-chased.
- A: ParakeetDecoder per-step `joint_net[2] as? Linear` cast + fatalError
  removed by retyping joint_net [Module] → [UnaryLayer], so the joint applies
  joint_net[2](activated) directly. MLXNN keys array children by runtime value,
  so the joint_net.2 safetensors key is unchanged. Device-validated on the
  iPhone 15 Pro Max (ParakeetSmoke: decode + chunking gates PASS).

Build + 61-test suite green (iPhone 17 Pro simulator); A also device-green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR applies a "Swift best-practices round 4" pass: ParakeetJointNetwork.joint_net is retyped from [Module] to [UnaryLayer] to eliminate a runtime cast and fatalError; ModelStores replaces multiple init overloads with a single optional-parameter initializer; RecorderViewModel.stopAndTranscribe() teardown is restructured into an early light teardown and a direct cancel-plus-file-delete error path; and docstrings are added across Transcriber, TranscriberFactory, AppleSpeechTranscriber, and RecorderViewModel. Planning docs and the changelog are updated accordingly.

Changes

Swift Best-Practices Round 4

Layer / File(s) Summary
ParakeetDecoder: retype joint_net to remove fatalError
Relay Notes/Transcription/Parakeet/ParakeetDecoder.swift
joint_net changes from [Module] to [UnaryLayer]; callAsFunction calls joint_net[2](activated) directly, removing the guarded downcast-to-Linear and fatalError.
ModelStores: consolidate init overloads
Relay Notes/Transcription/ModelStores.swift
Three stored properties gain updated docs; five prior init overloads are replaced by a single @MainActor init(whisper:parakeet:cleanup:) with optional parameters that nil-coalesce to default store constructors.
stopAndTranscribe() teardown refactor
Relay Notes/Recording/RecorderViewModel.swift
Early light teardown cancels and clears updatesTask, captures then clears session/currentAudioURL before guard checks. On session.finish() failure, directly cancel()s the captured session and deletes the orphaned audio file instead of calling cleanupAfterFailure(). Docstrings added to class, properties, and affected methods.
Transcription protocol and factory docstrings
Relay Notes/Transcription/Transcriber.swift, Relay Notes/Transcription/TranscriberFactory.swift, Relay Notes/Transcription/AppleSpeechTranscriber.swift
Doc comments added to TranscriptionOptions, TranscriptionSession members (audioFormat, feed, finish, cancel), Transcriber, TranscriberFactory MLX-cache eviction behavior, and all AppleSpeechTranscriber/AppleSpeechSession methods. No signatures or runtime behavior changed.
Planning doc and changelog
CHANGE_LOG.md, planning/swift-best-practices-review.md
CHANGE_LOG.md records round-4 and item-A completions. Planning doc marks backlog empty, all applied fixes documented, lower-priority polish and docstring sections updated.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 Hop-hop, the fatalError's gone,
No unsafe cast to stumble on!
One init rules where five once stood,
Teardown is tidy, crisp, and good.
Docstrings bloom like spring-time clover—
The backlog's clear, the polish over! 🌸

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: completing the swift-best-practices review backlog by applying four major improvements (F, G, docstrings, A).
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch swift-best-practices-round-4

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Relay` Notes/Recording/RecorderViewModel.swift:
- Around line 175-181: The combined guard statement on line 179 checking `guard
let session, let url` returns immediately without properly cleaning up resources
when either value is missing. If session exists but url is nil, or url exists
but session is nil, the resources remain orphaned. Instead of a single combined
guard check, validate session and url separately - if session is present, cancel
it; if url is present, delete the audio file - and only then set state to
.failed. This ensures complete resource cleanup regardless of which value is
missing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e17ef875-1a45-4a4b-bcca-4793f8d093e3

📥 Commits

Reviewing files that changed from the base of the PR and between ded597b and 13588e3.

📒 Files selected for processing (8)
  • CHANGE_LOG.md
  • Relay Notes/Recording/RecorderViewModel.swift
  • Relay Notes/Transcription/AppleSpeechTranscriber.swift
  • Relay Notes/Transcription/ModelStores.swift
  • Relay Notes/Transcription/Parakeet/ParakeetDecoder.swift
  • Relay Notes/Transcription/Transcriber.swift
  • Relay Notes/Transcription/TranscriberFactory.swift
  • planning/swift-best-practices-review.md

Comment on lines +175 to 181
let session = self.session
self.session = nil
currentAudioURL = nil

guard let session, let url else {
updatesTask?.cancel()
updatesTask = nil
self.session = nil
currentAudioURL = nil
state = .failed(message: "Recording could not be saved. Please try again.")
return

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle partial guard failure without leaking session/audio cleanup.

Line 179’s combined guard let session, let url drops into .failed without canceling an existing session or deleting an existing audio file when only one of the two is missing. This leaves a resource-leak/orphan-file gap exactly in the path this refactor centralized.

Suggested fix
-        let session = self.session
-        self.session = nil
-        currentAudioURL = nil
-
-        guard let session, let url else {
+        let session = self.session
+        self.session = nil
+        let fallbackURL = currentAudioURL
+        currentAudioURL = nil
+
+        guard let session else {
+            if let orphanURL = url ?? fallbackURL {
+                try? FileManager.default.removeItem(at: orphanURL)
+            }
+            state = .failed(message: "Recording could not be saved. Please try again.")
+            return
+        }
+        guard let url = url ?? fallbackURL else {
+            await session.cancel()
             state = .failed(message: "Recording could not be saved. Please try again.")
             return
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let session = self.session
self.session = nil
currentAudioURL = nil
guard let session, let url else {
updatesTask?.cancel()
updatesTask = nil
self.session = nil
currentAudioURL = nil
state = .failed(message: "Recording could not be saved. Please try again.")
return
let session = self.session
self.session = nil
let fallbackURL = currentAudioURL
currentAudioURL = nil
guard let session else {
if let orphanURL = url ?? fallbackURL {
try? FileManager.default.removeItem(at: orphanURL)
}
state = .failed(message: "Recording could not be saved. Please try again.")
return
}
guard let url = url ?? fallbackURL else {
await session.cancel()
state = .failed(message: "Recording could not be saved. Please try again.")
return
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Relay` Notes/Recording/RecorderViewModel.swift around lines 175 - 181, The
combined guard statement on line 179 checking `guard let session, let url`
returns immediately without properly cleaning up resources when either value is
missing. If session exists but url is nil, or url exists but session is nil, the
resources remain orphaned. Instead of a single combined guard check, validate
session and url separately - if session is present, cancel it; if url is
present, delete the audio file - and only then set state to .failed. This
ensures complete resource cleanup regardless of which value is missing.

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