[codex] prepare 1.14.4 canonical proxy release#38
Conversation
|
🔖 On merge this PR will release v1.14.4 ( |
|
Warning Review limit reached
More reviews will be available in 28 minutes and 19 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (14)
📝 WalkthroughWalkthroughThis PR implements synchronous sleep handling (RLR-M2) for meeting recordings plus a configurable hold-start delay for push-to-talk dictation. The recording recovery system includes per-recording in-progress directories, time-rotated chunk files with manifest tracking, and chunk stitching on stop. Sleep handlers flush and close active chunks before system sleep completes. Hold-start delay allows users to configure a threshold before recording begins when holding a modifier key. ChangesRecording Recovery & Sleep Handling
Configurable Hold-Start Delay for Push-To-Talk
Test Coverage & Build Configuration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Diduny/Core/Services/PushToTalkService.swift (1)
113-120:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winCaps Lock still bypasses the hold-delay path.
handleFlagsChanged(_:)returns tohandleCapsLockEvent(...)beforeprocessModifierKeyEvent(...), so.capsLockkeeps the old immediate start/stop behavior. MeanwhileShortcutsSettingsViewnow exposes the delay slider for everyPushToTalkKey, which makes this setting look supported for Caps Lock even though it has no effect.Either route Caps Lock through the delayed path too, or disable/hide the hold-delay UI when
.capsLockis selected.🤖 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 `@Diduny/Core/Services/PushToTalkService.swift` around lines 113 - 120, The caps-lock branch currently short-circuits to handleCapsLockEvent(...) and returns, bypassing the hold-delay logic in processModifierKeyEvent(...); change this so Caps Lock is handled via the same delayed path by either removing the early return and calling processModifierKeyEvent(isPressed:eventTime:) for selectedKey == .capsLock, or have handleCapsLockEvent(...) delegate into processModifierKeyEvent(...) so Caps Lock respects the configured hold-delay; update handleFlagsChanged(_:) to route Caps Lock through processModifierKeyEvent(...) (or delegate from handleCapsLockEvent(...) to it) so the delay slider actually takes effect.
🧹 Nitpick comments (7)
DidunyTests/MeetingChunkStitcherTests.swift (1)
128-155: ⚡ Quick winAdd a test for a single unreadable/empty chunk.
The suite covers all-empty (multi) and leading-empty cases but not a single empty/corrupt chunk. That path currently behaves differently (see
stitchSingleChunk), so a dedicated test would pin down the intended contract.💚 Suggested test
func test_stitch_singleEmptyChunk_throwsAllUnreadable() throws { let bad = try writeEmptyFile(name: "chunk_001.wav") let target = tmpDir.appendingPathComponent("out.wav") XCTAssertThrowsError(try MeetingChunkStitcher.stitch(chunkURLs: [bad], outputURL: target)) { error in guard case MeetingChunkStitcher.StitchError.allChunksUnreadable = error else { XCTFail("Expected .allChunksUnreadable, got \(error)") 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 `@DidunyTests/MeetingChunkStitcherTests.swift` around lines 128 - 155, Add a unit test that asserts a single unreadable/empty chunk causes MeetingChunkStitcher.stitch to throw .allChunksUnreadable; create a single empty file via writeEmptyFile (e.g., name "chunk_001.wav"), call MeetingChunkStitcher.stitch(chunkURLs: [bad], outputURL: target) and use XCTAssertThrowsError to verify the error matches MeetingChunkStitcher.StitchError.allChunksUnreadable—this will exercise the stitchSingleChunk path and lock down the intended contract.Diduny/Core/Services/MeetingRecorderService.swift (2)
121-130: ⚡ Quick winConsider grouping chunk rotation callback parameters.
The
onChunkRotatedcallback has 6 parameters (flagged by SwiftLint). While functional, bundling related metadata into a struct improves clarity and makes future additions easier.♻️ Proposed refactor
Define a parameter struct in
SystemAudioCaptureService:struct ChunkRotationInfo { let closedIndex: Int let closedURL: URL let closedAt: Date let byteCount: Int64 let durationSeconds: Double }Update the callback signature:
-service.onChunkRotated = { [weak self] closedIndex, closedURL, closedAt, byteCount, durationSeconds in +service.onChunkRotated = { [weak self] info in self?.handleChunkRotated( - closedIndex: closedIndex, - closedURL: closedURL, - closedAt: closedAt, - byteCount: byteCount, - durationSeconds: durationSeconds, + info: info, directoryURL: directoryURL ) }Update
handleChunkRotatedsignature similarly.🤖 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 `@Diduny/Core/Services/MeetingRecorderService.swift` around lines 121 - 130, The onChunkRotated callback currently passes six separate parameters; define a compact struct (e.g., ChunkRotationInfo) in SystemAudioCaptureService containing closedIndex, closedURL, closedAt, byteCount, and durationSeconds, change the onChunkRotated signature to accept a single ChunkRotationInfo parameter, and update all call sites and the MeetingRecorderService handleChunkRotated method to accept that struct (rename parameter to rotationInfo) and unpack fields as needed; ensure SystemAudioCaptureService and MeetingRecorderService method signatures and any related closures are updated consistently to avoid SwiftLint warnings and simplify future additions.
266-274: ⚡ Quick winConsider extracting last-chunk duration calculation.
The duration calculation logic (lines 266–274) is sound but dense: it subtracts prior chunk durations from the stitch total or falls back to the overall recording duration. Extracting this into a helper method would improve readability and testability.
♻️ Proposed refactor
private func computeLastChunkDuration( stitchResult: MeetingChunkStitcher.Result?, manifest: InProgressRecordingManifest, overallDuration: TimeInterval ) -> Double { if let stitch = stitchResult { let priorDurations = manifest.chunks.prefix(manifest.chunks.count - 1) .reduce(0.0) { $0 + $1.durationSeconds } return max(0, stitch.totalDurationSeconds - priorDurations) } else { return overallDuration } }Then replace lines 265–274:
- let lastDuration: Double - if let stitch = stitchResult { - // Subtract durations of preceding (closed) chunks from total. - let priorDurations = manifest.chunks.prefix(manifest.chunks.count - 1) - .reduce(0.0) { $0 + $1.durationSeconds } - lastDuration = max(0, stitch.totalDurationSeconds - priorDurations) - } else { - // Stitch unavailable (no rotation happened): the whole recording is in chunk_001. - lastDuration = duration - } + let lastDuration = computeLastChunkDuration( + stitchResult: stitchResult, + manifest: manifest, + overallDuration: duration + )🤖 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 `@Diduny/Core/Services/MeetingRecorderService.swift` around lines 266 - 274, Extract the last-chunk duration calculation into a private helper to improve readability and testability: create a method like computeLastChunkDuration(stitchResult: MeetingChunkStitcher.Result?, manifest: InProgressRecordingManifest, overallDuration: TimeInterval) -> Double that encapsulates the current logic (if stitchResult non-nil, compute priorDurations by summing manifest.chunks.prefix(manifest.chunks.count - 1).reduce(0.0) { $0 + $1.durationSeconds } and return max(0, stitch.totalDurationSeconds - priorDurations); otherwise return overallDuration), then replace the inline block that sets lastDuration (which currently references stitchResult, manifest and duration) with a call to this new helper inside MeetingRecorderService.Diduny/App/AppDelegate+MeetingTranslationRecording.swift (1)
278-278: ⚡ Quick winUse NSLog with [Transcription] prefix for cloud API logging.
Lines 278, 307–310, and 312 use
Log.transcription.*for real-time translation connection logs in an AppDelegate extension file. Based on learnings, these should useNSLog("[Transcription] ...")formatting for consistency with the expected log output format in AppDelegate extension files.♻️ Proposed fix
rtService.onError = { error in - Log.transcription.error("Realtime meeting translation error: \(error.localizedDescription)") + NSLog("[Transcription] Realtime meeting translation error: %@", error.localizedDescription) // Don't stop recording — file recording continues independently } // ... await MainActor.run { store.isActive = true } - Log.transcription - .info( - "Meeting real-time translation connected successfully (\(sourceLanguage.uppercased()) -> \(targetLanguage.uppercased()))" - ) + NSLog("[Transcription] Meeting real-time translation connected successfully (%@ -> %@)", + sourceLanguage.uppercased(), targetLanguage.uppercased()) } catch { - Log.transcription.error("Meeting real-time translation FAILED to connect: \(error.localizedDescription)") + NSLog("[Transcription] Meeting real-time translation FAILED to connect: %@", error.localizedDescription) await MainActor.run {Based on learnings: prefer NSLog("[Transcription] ...") for cloud API/WebSocket connection logs in AppDelegate extension files rather than Log.transcription.* to maintain consistent log output format.
Also applies to: 307-310, 312-312
🤖 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 `@Diduny/App/AppDelegate`+MeetingTranslationRecording.swift at line 278, Replace the uses of Log.transcription.* in the AppDelegate+MeetingTranslationRecording extension (e.g., the call Log.transcription.error("Realtime meeting translation error: \(error.localizedDescription)") and the other occurrences around the realtime translation WebSocket/connection handling at the same scope) with NSLog("[Transcription] ...") calls that preserve the original message text and interpolated values (for example include error.localizedDescription), so all cloud API/WS transcription logs use the NSLog("[Transcription] ...") format for consistent output.Diduny/App/AppDelegate+MeetingRecording.swift (1)
287-287: ⚡ Quick winUse NSLog with [Transcription] prefix for cloud API logging.
Lines 287, 302, and 304 use
Log.transcription.*for real-time transcription connection logs in an AppDelegate extension file. Based on learnings, these should useNSLog("[Transcription] ...")formatting for consistency with the expected log output format in AppDelegate extension files.♻️ Proposed fix
rtService.onError = { error in - Log.transcription.error("Realtime transcription error: \(error.localizedDescription)") + NSLog("[Transcription] Realtime transcription error: %@", error.localizedDescription) // Don't stop recording — file recording continues independently } // ... await MainActor.run { store.isActive = true } - Log.transcription.info("Meeting real-time transcription connected successfully") + NSLog("[Transcription] Meeting real-time transcription connected successfully") } catch { - Log.transcription.error("Meeting real-time transcription FAILED to connect: \(error.localizedDescription)") + NSLog("[Transcription] Meeting real-time transcription FAILED to connect: %@", error.localizedDescription) await MainActor.run {Based on learnings: prefer NSLog("[Transcription] ...") for cloud API/WebSocket connection logs in AppDelegate extension files rather than Log.transcription.* to maintain consistent log output format.
Also applies to: 302-302, 304-304
🤖 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 `@Diduny/App/AppDelegate`+MeetingRecording.swift at line 287, Replace the Log.transcription.* calls in the AppDelegate+MeetingRecording.swift extension with NSLog using a "[Transcription]" prefix so cloud API/WebSocket logs match the expected format; specifically, change instances like Log.transcription.error("Realtime transcription error: \(error.localizedDescription)") to NSLog("[Transcription] Realtime transcription error: %@", error.localizedDescription) and similarly convert the other Log.transcription.* invocations to NSLog("[Transcription] ...") preserving the original message text and any interpolated values.Diduny/Core/Services/PushToTalkService.swift (1)
175-177: ⚡ Quick winUse
NSLogfor these new state-transition logs.These messages are tracking push-to-talk state changes, so they should follow the repo's
NSLog("[AppState] ...")convention instead ofLog.app.info(...). As per coding guidelines "Use NSLog() for logging with prefixes: [Diduny] for AppDelegate flow, [Transcription] for cloud API calls, [AppState] for state changes".Also applies to: 181-183, 187-206
🤖 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 `@Diduny/Core/Services/PushToTalkService.swift` around lines 175 - 177, Replace Log.app.info(...) calls used for push-to-talk state-transition messages in PushToTalkService (the guard using hasStartedAfterHold and the subsequent similar logs at the same block and lines 181-183, 187-206) with NSLog() using the [AppState] prefix; e.g., change any Log.app.info("\(self.selectedKey.displayName) ...") to NSLog("[AppState] \(self.selectedKey.displayName) ...") so all state-change logs follow the repo convention for AppState messages.Diduny/App/AppDelegate+Hotkeys.swift (1)
96-100: ⚡ Quick winSwitch these new AppDelegate state logs to
NSLog.These are AppDelegate state-change logs, so they should use the repo's
NSLog("[AppState] ...")format instead ofLog.app.info(...). As per coding guidelines "Use NSLog() for logging with prefixes: [Diduny] for AppDelegate flow, [Transcription] for cloud API calls, [AppState] for state changes".Also applies to: 160-164
🤖 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 `@Diduny/App/AppDelegate`+Hotkeys.swift around lines 96 - 100, Replace the Log.app.info calls in the AppDelegate state-change handlers (e.g., pushToTalkHoldStartDelayChanged(_:), and the similar handler around lines 160-164) with NSLog using the "[AppState]" prefix; specifically, keep the same message text/formatting (e.g., the formatted delay string) but call NSLog("[AppState] Dictation modifier hold delay changed to: ...") instead of Log.app.info so AppDelegate state transitions follow the repo logging convention.
🤖 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 `@Diduny/App/AppDelegate.swift`:
- Around line 219-305: The willSleep/didWake closures run on a background thread
but currently call AppDelegate's main-isolated methods
(flushActiveRecordingForSleep and handleWakeAfterRecordingInterrupt) and mutate
main-actor state (recordingWasInterruptedBySleep, meetingActivityToken,
meetingTranslationActivityToken), which can deadlock or defer activity token
release; make the sleep/wake bookkeeping actor-independent by extracting
non-main-isolated helpers: add a nonisolated method (or standalone helper) to
perform the synchronous flush logic that returns flushedURL/ok and the
recordingId without touching main-actor properties, and add a nonisolated
function to synchronously end activity tokens (or move token storage into a
thread-safe, non-@MainActor container) so
ProcessInfo.processInfo.endActivity(...) can be called before the willSleep
handler returns; update setupSleepHandling to call
SleepFlushCoordinator.flushCurrentChunk -> the new nonisolated flush helper, and
keep only UI/state updates (e.g., handleWakeAfterRecordingInterrupt and any
mutation of recordingWasInterruptedBySleep) dispatched to the MainActor
asynchronously after the background work completes.
In `@Diduny/Core/Services/MeetingChunkStitcher.swift`:
- Around line 72-91: stitchSingleChunk currently copies the file even when
AVAudioFile reading fails (duration == 0), causing corrupt/empty chunks to be
persisted; fix this by checking computed duration before copying in
stitchSingleChunk and throw StitchError.allChunksUnreadable if duration == 0 (so
no copy occurs), and additionally update MeetingRecorderService.stopRecording()
to gate persistence/transcription on stitchResult?.appendedChunkCount > 0 (or
explicitly handle StitchError.allChunksUnreadable in the fallback that uses
capturedChunkURLs.last) to ensure unreadable chunks are not saved or
transcribed.
In `@Diduny/Core/Services/PushToTalkService.swift`:
- Around line 93-95: resetHandsFreeMode() currently clears active hold state by
setting hasStartedAfterHold = false which breaks hold-to-record flows because
AppDelegate+Hotkeys calls this on tap-count/hold-delay changes and the
subsequent key-up will early-return in onKeyUp; remove the hasStartedAfterHold
reset from resetHandsFreeMode() and instead introduce a new method (e.g.,
clearFullHandsFreeState() or resetAllHandsFreeState()) that cancels pending
timers and also clears hasStartedAfterHold for callers that truly need a full
reset; update callers that only change configuration (like AppDelegate+Hotkeys)
to call the lighter resetHandsFreeMode() while callers that need a full wipe
call the new helper.
In `@Diduny/Core/Services/SystemAudioCaptureService.swift`:
- Around line 440-448: The race occurs because isCapturing is only cleared after
synchronizedTeardown(), allowing in-flight SCStream callbacks on
streamOutputQueue to enqueue onto mixerQueue (and the microphone tap path) after
teardown; to fix, set isCapturing = false before calling synchronizedTeardown()
in synchronousFlushForSleep(), and add a guard at the start of the
microphone/tap callback (the mic path that enqueues to mixerQueue) to drop any
buffers when isCapturing is false so late callbacks are gated and cannot enqueue
work after teardown.
In `@Diduny/Core/Storage/InProgressRecordingStore.swift`:
- Around line 20-28: The initializer for InProgressRecordingStore should
validate the applicationSupportDirectory lookup and surface directory-creation
errors instead of force-unwrapping and silencing failures: change
init(baseDirectory:fileManager:) to a throwing initializer (init(...) throws),
replace the force-unwrap of fileManager.urls(for: .applicationSupportDirectory,
in: .userDomainMask).first! with a guard-let that throws a descriptive error
(e.g., ApplicationSupportDirectoryUnavailable), compute self.baseDirectory from
the provided baseDirectory or the validated appSupport path, and replace try?
fileManager.createDirectory(...) with try fileManager.createDirectory(...) so
directory creation failures propagate; update any call sites (notably the static
let shared = InProgressRecordingStore() singleton) to handle or propagate the
thrown error per the review note.
In `@DidunyTests/RecordingModelMigrationTests.swift`:
- Around line 17-27: Rename the single-letter local variables to meet
SwiftLint's identifier_name rule: in the iso8601 JSONDecoder closure rename the
variable `d` to a descriptive ≥3-char name (e.g., `decoder`) and update its
return reference; in the iso8601Encoder JSONEncoder closure rename `e` to a
descriptive ≥3-char name (e.g., `encoder`) and update its return reference; and
rename the other single-letter `r` (used elsewhere around the
RecordingModelMigrationTests file) to a ≥3-char name (e.g., `result` or
`reader`) and update all subsequent `r.` references accordingly so all usages
compile and lint cleanly.
---
Outside diff comments:
In `@Diduny/Core/Services/PushToTalkService.swift`:
- Around line 113-120: The caps-lock branch currently short-circuits to
handleCapsLockEvent(...) and returns, bypassing the hold-delay logic in
processModifierKeyEvent(...); change this so Caps Lock is handled via the same
delayed path by either removing the early return and calling
processModifierKeyEvent(isPressed:eventTime:) for selectedKey == .capsLock, or
have handleCapsLockEvent(...) delegate into processModifierKeyEvent(...) so Caps
Lock respects the configured hold-delay; update handleFlagsChanged(_:) to route
Caps Lock through processModifierKeyEvent(...) (or delegate from
handleCapsLockEvent(...) to it) so the delay slider actually takes effect.
---
Nitpick comments:
In `@Diduny/App/AppDelegate`+Hotkeys.swift:
- Around line 96-100: Replace the Log.app.info calls in the AppDelegate
state-change handlers (e.g., pushToTalkHoldStartDelayChanged(_:), and the
similar handler around lines 160-164) with NSLog using the "[AppState]" prefix;
specifically, keep the same message text/formatting (e.g., the formatted delay
string) but call NSLog("[AppState] Dictation modifier hold delay changed to:
...") instead of Log.app.info so AppDelegate state transitions follow the repo
logging convention.
In `@Diduny/App/AppDelegate`+MeetingRecording.swift:
- Line 287: Replace the Log.transcription.* calls in the
AppDelegate+MeetingRecording.swift extension with NSLog using a
"[Transcription]" prefix so cloud API/WebSocket logs match the expected format;
specifically, change instances like Log.transcription.error("Realtime
transcription error: \(error.localizedDescription)") to NSLog("[Transcription]
Realtime transcription error: %@", error.localizedDescription) and similarly
convert the other Log.transcription.* invocations to NSLog("[Transcription]
...") preserving the original message text and any interpolated values.
In `@Diduny/App/AppDelegate`+MeetingTranslationRecording.swift:
- Line 278: Replace the uses of Log.transcription.* in the
AppDelegate+MeetingTranslationRecording extension (e.g., the call
Log.transcription.error("Realtime meeting translation error:
\(error.localizedDescription)") and the other occurrences around the realtime
translation WebSocket/connection handling at the same scope) with
NSLog("[Transcription] ...") calls that preserve the original message text and
interpolated values (for example include error.localizedDescription), so all
cloud API/WS transcription logs use the NSLog("[Transcription] ...") format for
consistent output.
In `@Diduny/Core/Services/MeetingRecorderService.swift`:
- Around line 121-130: The onChunkRotated callback currently passes six separate
parameters; define a compact struct (e.g., ChunkRotationInfo) in
SystemAudioCaptureService containing closedIndex, closedURL, closedAt,
byteCount, and durationSeconds, change the onChunkRotated signature to accept a
single ChunkRotationInfo parameter, and update all call sites and the
MeetingRecorderService handleChunkRotated method to accept that struct (rename
parameter to rotationInfo) and unpack fields as needed; ensure
SystemAudioCaptureService and MeetingRecorderService method signatures and any
related closures are updated consistently to avoid SwiftLint warnings and
simplify future additions.
- Around line 266-274: Extract the last-chunk duration calculation into a
private helper to improve readability and testability: create a method like
computeLastChunkDuration(stitchResult: MeetingChunkStitcher.Result?, manifest:
InProgressRecordingManifest, overallDuration: TimeInterval) -> Double that
encapsulates the current logic (if stitchResult non-nil, compute priorDurations
by summing manifest.chunks.prefix(manifest.chunks.count - 1).reduce(0.0) { $0 +
$1.durationSeconds } and return max(0, stitch.totalDurationSeconds -
priorDurations); otherwise return overallDuration), then replace the inline
block that sets lastDuration (which currently references stitchResult, manifest
and duration) with a call to this new helper inside MeetingRecorderService.
In `@Diduny/Core/Services/PushToTalkService.swift`:
- Around line 175-177: Replace Log.app.info(...) calls used for push-to-talk
state-transition messages in PushToTalkService (the guard using
hasStartedAfterHold and the subsequent similar logs at the same block and lines
181-183, 187-206) with NSLog() using the [AppState] prefix; e.g., change any
Log.app.info("\(self.selectedKey.displayName) ...") to NSLog("[AppState]
\(self.selectedKey.displayName) ...") so all state-change logs follow the repo
convention for AppState messages.
In `@DidunyTests/MeetingChunkStitcherTests.swift`:
- Around line 128-155: Add a unit test that asserts a single unreadable/empty
chunk causes MeetingChunkStitcher.stitch to throw .allChunksUnreadable; create a
single empty file via writeEmptyFile (e.g., name "chunk_001.wav"), call
MeetingChunkStitcher.stitch(chunkURLs: [bad], outputURL: target) and use
XCTAssertThrowsError to verify the error matches
MeetingChunkStitcher.StitchError.allChunksUnreadable—this will exercise the
stitchSingleChunk path and lock down the intended contract.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: ae6bdda5-44c0-4a88-bcd6-7262f7c5de4d
📒 Files selected for processing (25)
Diduny.xcodeproj/project.pbxprojDiduny.xcodeproj/xcshareddata/xcschemes/Diduny TEST.xcschemeDiduny/App/AppDelegate+Hotkeys.swiftDiduny/App/AppDelegate+MeetingRecording.swiftDiduny/App/AppDelegate+MeetingTranslationRecording.swiftDiduny/App/AppDelegate.swiftDiduny/Core/Models/Recording.swiftDiduny/Core/Protocols/ServiceProtocols.swiftDiduny/Core/Services/AuthService.swiftDiduny/Core/Services/MeetingChunkStitcher.swiftDiduny/Core/Services/MeetingRecorderService.swiftDiduny/Core/Services/PushToTalkService.swiftDiduny/Core/Services/SleepFlushCoordinator.swiftDiduny/Core/Services/SystemAudioCaptureService.swiftDiduny/Core/Storage/InProgressRecordingManifest.swiftDiduny/Core/Storage/InProgressRecordingStore.swiftDiduny/Core/Storage/RecordingsLibraryStorage.swiftDiduny/Core/Storage/SettingsStorage.swiftDiduny/Features/Settings/ShortcutsSettingsView.swiftDidunyTests/InProgressRecordingStoreTests.swiftDidunyTests/MeetingChunkStitcherTests.swiftDidunyTests/PushToTalkServiceTests.swiftDidunyTests/RecordingModelMigrationTests.swiftDidunyTests/SleepFlushCoordinatorTests.swiftproject.yml
Що змінилось
https://diduny-ears-proxy.fly.dev.diduny-ears-proxy-v2.fly.dev.1.14.4/ build4; фактична release version береться з GitHub tag.Чому
Клієнти мають повернутися з тимчасового v2 endpoint на canonical backend, щоб backend реліз міг відновити стандартний
diduny-ears-proxyбез ламання existing installs.Validation
xcodebuild -project Diduny.xcodeproj -scheme Diduny -configuration Debug -destination platform=macOS buildRelease
release:patchv1.14.3; this PR will releasev1.14.4.