Skip to content

Migrate project targets to Swift 6 - #82

Merged
Mag1cByt3s merged 2 commits into
Evil-Project:mainfrom
Mag1cByt3s:swift-6-migration
Jul 30, 2026
Merged

Migrate project targets to Swift 6#82
Mag1cByt3s merged 2 commits into
Evil-Project:mainfrom
Mag1cByt3s:swift-6-migration

Conversation

@Mag1cByt3s

@Mag1cByt3s Mag1cByt3s commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • migrate all repository-owned app and test targets to Swift 6 language mode
  • update actor isolation and sendability across Shimeji resource handling, audio managers, WatchConnectivity, caching, and UI tests
  • replace the scroll-state DispatchWorkItem debounce with a cancellable Swift concurrency task
  • update the WebKit navigation delegate callback to its current concurrency-aware signature

Why

The project used the Swift 6 compiler and approachable concurrency settings, but every target still explicitly compiled in Swift 5 language mode. Enabling Swift 6 exposed compile-time isolation issues and two runtime executor violations that could crash test hosts.

Third-party Swift packages keep the language modes declared by their own package manifests.

Validation

  • clean Debug simulator build for the iOS scheme, including watch and widget dependencies
  • Release simulator build for the iOS scheme
  • Debug and Release simulator builds for tvOS
  • iOS unit tests pass
  • watchOS unit tests pass
  • tested successfully on a physical iPhone

Summary by Sourcery

Migrate app, watch, tv, and test targets to Swift 6 and update concurrency usage to comply with Swift 6 isolation and sendability rules.

New Features:

  • Adopt Swift concurrency tasks for scroll state debounce instead of Dispatch work items.
  • Make WebKit navigation delegate policy decision handler use the modern concurrency-aware signature.

Bug Fixes:

  • Fix potential executor and isolation violations in Shimeji resource handling, watch connectivity session publishing, audio polling, and cache access.
  • Ensure UI test cases and watch session publisher run consistently on the main actor to avoid concurrency-related crashes.
  • Prevent Shimeji overlay bounds tracking from retaining scenes and align bounds reads with effective scene geometry.

Enhancements:

  • Mark Shimeji, lyrics, cache, and zip model types and enums as nonisolated and Sendable where appropriate to better express concurrency contracts.
  • Wrap cache access side effects on CacheManager in main-actor tasks while keeping I/O synchronous and serialized with locking.
  • Annotate deinitializers in audio and auth managers with actor isolation to make teardown consistent under Swift 6.

Build:

  • Update Xcode project target settings to compile repository-owned targets in Swift 6 language mode.

Tests:

  • Mark iOS and watchOS UI test classes as @mainactor to align with Swift 6 XCTest expectations.

Summary by CodeRabbit

  • Improvements
    • Updated the app and companion experiences to use Swift 6, improving compatibility with modern concurrency requirements.
    • Improved reliability of CAPTCHA handling, lyric caching, resource downloads, watch communication, and scrolling state updates.
    • Refined Shimeji overlay positioning to better account for current screen geometry.
    • Preserved existing authentication, audio, and polling behavior while strengthening cleanup and lifecycle handling.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Mag1cByt3s, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 45 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e43f47f3-c34c-4c45-9ebe-df09fe71ad9a

📥 Commits

Reviewing files that changed from the base of the PR and between 45cfd84 and 0d95173.

📒 Files selected for processing (2)
  • Twinskaraoke/Services/Shimeji/ShimejiResourceManager.swift
  • TwinskaraokeWatchApp/Services/RadioController.swift
📝 Walkthrough

Walkthrough

Swift 6 is enabled across application and test targets. Shared models gain Sendable and nonisolated annotations, while asynchronous downloads, timers, cache bookkeeping, watch-session publishing, lifecycle cleanup, and UI tests are updated for Swift concurrency.

Changes

Swift 6 concurrency migration

Layer / File(s) Summary
Swift 6 settings and data contracts
Twinskaraoke.xcodeproj/project.pbxproj, TwinskaraokeShared/Models/LyricsModels.swift, Twinskaraoke/Services/Shimeji/ShimejiModels.swift, Twinskaraoke/Services/Shimeji/ShimejiZipReader.swift, TwinskaraokeUITests/..., TwinskaraokeWatchAppUITests/...
All listed targets use Swift 6, and shared Shimeji, lyric, parser, and UI test types receive concurrency annotations.
Shimeji resource concurrency
Twinskaraoke/Services/Shimeji/ShimejiResourceManager.swift
Download completion and progress updates use main-actor delivery helpers; ZIP extraction runs through detached-task processing.
Timer and callback isolation
Twinskaraoke/Components/Shimeji/ShimejiOverlayWindow.swift, Twinskaraoke/Services/Debug/ScrollPerformanceState.swift, Twinskaraoke/Components/Shared/CaptchaWebView.swift
Overlay tracking uses selector-based timers and effective geometry, scroll completion uses cancellable Tasks, and web view handlers use main-actor sendable callbacks.
Service actor boundaries and teardown
Twinskaraoke/Services/Storage/LyricsCacheStore.swift, Twinskaraoke/Services/User/..., TwinskaraokeTVApp/Services/AudioManager.swift, TwinskaraokeWatchApp/Services/...
Cache operations, watch-session callbacks, deinitializers, and radio polling are updated for explicit actor isolation.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested reviewers: xiaoyuan151, cosmii02

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 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 change: migrating repository targets to Swift 6.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

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

@sourcery-ai

sourcery-ai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Migrates all first-party app and test targets to Swift 6 by tightening actor isolation, marking core models/utilities as nonisolated and Sendable, updating async patterns to use Swift concurrency tasks, and aligning delegate APIs and deinitializers with Swift 6 concurrency rules.

Sequence diagram for Shimeji resource download and manifest loading under Swift concurrency

sequenceDiagram
    participant URLSession
    participant ShimejiResourceManager
    participant MainActor
    participant TaskDetached

    ShimejiResourceManager->>URLSession: downloadTask(with: packURL)
    URLSession-->>ShimejiResourceManager: completion(tempURL,error)
    ShimejiResourceManager->>MainActor: deliverDownloadCompletion(to:tempURL:error)
    MainActor->>ShimejiResourceManager: handleDownloadCompletion(tempURL:error)
    ShimejiResourceManager->>TaskDetached: Task.detached(extractAndLoad(zipURL:))
    TaskDetached-->>ShimejiResourceManager: ShimejiManifest
    ShimejiResourceManager->>ShimejiResourceManager: manifest,state = ready

    URLSession-->>ShimejiResourceManager: progress.fractionCompleted
    ShimejiResourceManager->>MainActor: deliverProgress(progress,to:manager)
    MainActor->>ShimejiResourceManager: state = .downloading(progress)
Loading

Sequence diagram for WatchSessionPublisher handling WCSession callbacks on MainActor

sequenceDiagram
    participant WCSession
    participant WatchSessionPublisher
    participant MainActor

    WCSession-->>WatchSessionPublisher: session(activationDidCompleteWith:error:)
    WatchSessionPublisher->>MainActor: publish(bumpingGeneration:false)

    WCSession-->>WatchSessionPublisher: sessionWatchStateDidChange
    WatchSessionPublisher->>MainActor: publish(bumpingGeneration:false)

    WCSession-->>WatchSessionPublisher: session(didReceiveMessage:replyHandler:)
    WatchSessionPublisher->>MainActor: publish(bumpingGeneration:true)
Loading

File-Level Changes

Change Details Files
Refactor Shimeji resource loading and overlay bounds tracking to be Swift 6–safe and better aligned with actor isolation.
  • Replace inline MainActor Task usage in URLSession callbacks with nonisolated static helpers that hop to the main actor
  • Change extract-and-load workflow to use a detached Task for heavy I/O and a main-actor Task for state updates, with nonisolated static extraction
  • Introduce a scene-backed bounds tracking mechanism in ShimejiOverlayWindow using a Timer target/selector pattern and UIWindowScene.effectiveGeometry
Twinskaraoke/Services/Shimeji/ShimejiResourceManager.swift
Twinskaraoke/Components/Shimeji/ShimejiOverlayWindow.swift
Harden lyrics caching APIs for cross-actor use and main-actor cache bookkeeping under Swift 6.
  • Mark LyricsCacheVariant, LyricsCacheStore, and related properties as nonisolated and Sendable
  • Move FileManager access into local variables to avoid shared mutable state issues
  • Ensure CacheManager interactions (recordAccess and enforceLyricsCacheLimits) run on the main actor via Tasks
Twinskaraoke/Services/Storage/LyricsCacheStore.swift
TwinskaraokeShared/Models/LyricsModels.swift
Align WatchConnectivity session publishing and radio polling logic with Swift 6 concurrency semantics.
  • Annotate WatchSessionPublisher as @mainactor and make WCSessionDelegate methods nonisolated, hopping back to MainActor with Tasks
  • Adjust RadioController polling loop to avoid awaiting on actor-isolated properties and perform cleanup without unnecessary actor hops
Twinskaraoke/Services/User/WatchSessionPublisher.swift
TwinskaraokeWatchApp/Services/RadioController.swift
Replace DispatchWorkItem-based scroll debounce with a cancellable Swift concurrency Task.
  • Swap the DispatchWorkItem debounce for a Task that sleeps for the debounce interval and checks a generation counter
  • Update cancellation logic to cancel the Task and bump the generation to ignore stale completions
Twinskaraoke/Services/Debug/ScrollPerformanceState.swift
Mark core Shimeji and lyrics models/utilities as nonisolated and Sendable to enable safe cross-actor usage.
  • Declare Shimeji manifest, character, anchor, action definition, and action kind types as nonisolated and Sendable
  • Make ShimejiZipReader and its nested types nonisolated, including ZipError and Entry
  • Mark LyricLine and RawLyricLine as Sendable for safe sharing across tasks
Twinskaraoke/Services/Shimeji/ShimejiModels.swift
Twinskaraoke/Services/Shimeji/ShimejiZipReader.swift
TwinskaraokeShared/Models/LyricsModels.swift
Update auth and audio manager lifecycle to satisfy Swift 6 isolation rules.
  • Mark AuthManager.K constant keys as nonisolated to avoid actor isolation violations
  • Convert AuthManager and AudioManager deinitializers to isolated deinit to safely interact with instance state during teardown
Twinskaraoke/Services/User/AuthManager.swift
TwinskaraokeTVApp/Services/AudioManager.swift
TwinskaraokeWatchApp/Services/AudioManager.swift
Modernize WebKit delegate APIs and UI test isolation for Swift 6.
  • Update WKNavigationDelegate decisionHandler signature to be @mainactor @sendable
  • Remove unnecessary DispatchQueue.main hop in webViewDidClose, calling onClose() directly under main-actor context
  • Annotate UITest case classes with @mainactor to keep XCTest interactions on the main actor
Twinskaraoke/Components/Shared/CaptchaWebView.swift
TwinskaraokeUITests/TwinskaraokeUITests.swift
TwinskaraokeWatchAppUITests/TwinskaraokeWatchAppUITests.swift
Configure Xcode project to compile first-party targets in Swift 6 language mode while leaving external packages unchanged.
  • Update Swift language version for app, watch, tvOS, shared, and test targets to Swift 6 in the project file
  • Ensure third-party Swift packages retain their own declared language modes
Twinskaraoke.xcodeproj/project.pbxproj

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@Mag1cByt3s
Mag1cByt3s marked this pull request as ready for review July 30, 2026 10:12

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • In ShimejiResourceManager, the Task that wraps the detached extract/load work now mutates manifest and state directly; consider enforcing main-actor updates (e.g. via @MainActor on the type or MainActor.run) to keep ObservableObject state changes on the UI thread.
  • The RadioController polling loop now reads shouldKeepPolling and calls clearPollTask() without await; verify these are either nonisolated or explicitly main-actor-safe, or adjust their actor isolation to match the background polling context.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In ShimejiResourceManager, the Task that wraps the detached extract/load work now mutates `manifest` and `state` directly; consider enforcing main-actor updates (e.g. via `@MainActor` on the type or `MainActor.run`) to keep ObservableObject state changes on the UI thread.
- The RadioController polling loop now reads `shouldKeepPolling` and calls `clearPollTask()` without `await`; verify these are either nonisolated or explicitly main-actor-safe, or adjust their actor isolation to match the background polling context.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 `@Twinskaraoke/Services/Shimeji/ShimejiResourceManager.swift`:
- Around line 108-141: Update the installation flow around the detached
extraction Task and the `deleteDownloadedPack()`/`retry()` methods to track an
installation generation or cancellable task, incrementing or invalidating it in
both delete and retry paths. Before swapping the extracted directory and before
publishing `.ready` or `.failed` state and the manifest, verify the work still
matches the current installation generation; otherwise discard the stale result
and clean up temporary files.
🪄 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 Plus

Run ID: c8aec85b-3029-4162-8c4d-0d826ca83082

📥 Commits

Reviewing files that changed from the base of the PR and between 08513fc and 45cfd84.

📒 Files selected for processing (16)
  • Twinskaraoke.xcodeproj/project.pbxproj
  • Twinskaraoke/Components/Shared/CaptchaWebView.swift
  • Twinskaraoke/Components/Shimeji/ShimejiOverlayWindow.swift
  • Twinskaraoke/Services/Debug/ScrollPerformanceState.swift
  • Twinskaraoke/Services/Shimeji/ShimejiModels.swift
  • Twinskaraoke/Services/Shimeji/ShimejiResourceManager.swift
  • Twinskaraoke/Services/Shimeji/ShimejiZipReader.swift
  • Twinskaraoke/Services/Storage/LyricsCacheStore.swift
  • Twinskaraoke/Services/User/AuthManager.swift
  • Twinskaraoke/Services/User/WatchSessionPublisher.swift
  • TwinskaraokeShared/Models/LyricsModels.swift
  • TwinskaraokeTVApp/Services/AudioManager.swift
  • TwinskaraokeUITests/TwinskaraokeUITests.swift
  • TwinskaraokeWatchApp/Services/AudioManager.swift
  • TwinskaraokeWatchApp/Services/RadioController.swift
  • TwinskaraokeWatchAppUITests/TwinskaraokeWatchAppUITests.swift

Comment thread Twinskaraoke/Services/Shimeji/ShimejiResourceManager.swift Outdated
@Mag1cByt3s
Mag1cByt3s merged commit f45451c into Evil-Project:main Jul 30, 2026
4 checks passed
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