Clear every compiler warning in our own sources (Swift 6 groundwork), and fix the blur relay's fake weak capture - #305
Merged
Conversation
…y's fake weak capture
A Debug simulator build was emitting 22 warnings across the app and test targets.
Several were "this is an error in the Swift 6 language mode", so clearing them is
also Swift 6 migration groundwork.
One was a real defect. In OutboundFrameRelay.blur, the inner `queue.async` sat
inside a closure that had already bound `self` strongly via `guard let self`, so
its `[weak self]` Task was decorative: a relay released mid-pipeline was held
alive to finish the composite and publish one more frame. The outer capture is
weak now, which is what the surrounding code always intended.
Main-actor isolation — immutable configuration made genuinely `nonisolated`
rather than hopping, since these are read from CoreBluetooth and capture
callbacks where a hop would change timing:
- EvenBLETransport's characteristic UUIDs and advertised-name prefix. CBUUID
isn't annotated Sendable, so the three UUIDs are `nonisolated(unsafe)` —
immutable value objects created once, stated rather than worked around.
- LocalLLMService.visionModelIds, LLMService.localSafeTools,
VideoRecordingService.frameStallSeconds.
- FingerspellingModelDownloader.liveInstaller moves onto the (nonisolated)
FingerspellingModelBundle, mirroring ASRModelBundle. That also resolves the
redundant `await progress(...)`: the closure is no longer main-actor-inferred,
so the hop is real, and the download's file I/O leaves the main thread.
Sendable:
- The vision turn's UserInput (and the CIImage in it) is built inside the
@sendable closure from Sendable ingredients only, instead of crossing the
boundary.
- MediaTriggerService's notification handler is typed @sendable.
- BroadcastAudioProviding is @mainactor — the adopter and both call sites
already were; only the handlers it registers are @sendable.
iOS 26 deprecations (deployment target is 26.0, so no availability gates):
- The OAuth presentation anchor walks connected scenes — foreground-active key
window, any key window, any window, then a new window on a scene.
init(windowScene:) is the only surviving UIWindow initialiser, so the
scene-less tail traps instead of returning an unpresentable empty window;
signIn() is only reachable from a Settings button tap, which requires a live
scene.
- Walking routes use MKMapItem(location:address:) instead of MKPlacemark.
Also: two discarded capturePhoto() results made explicit (it files every capture
to the "Glasses" album itself), a discarded seekToEnd(), two redundant `try`s on
non-throwing closures passed to a rethrows function, and three redundant `await`s
in the download tests.
Verified: Debug simulator build and the full suite are clean — 2852 tests, 0
failures, 3 skipped, and zero compiler warnings in our own sources. The only
warnings left are two pre-existing xcodebuild group-membership notices about the
generated project.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Clears every compiler warning in our own sources (app + test targets). Several were "this is an error in the Swift 6 language mode", so this is also Swift 6 migration groundwork. Vendored/SPM warnings are out of scope.
One real bug
OutboundFrameRelay.blur— the innerqueue.asyncsat inside a closure that had already boundselfstrongly viaguard let self, so its[weak self]Task was decorative. A relay released mid-pipeline was held alive to finish the composite and publish one more frame. The outer capture is weak now, which is what the surrounding code always intended.Main-actor isolation
Immutable configuration made genuinely
nonisolatedrather than hopping — these are read from CoreBluetooth and capture callbacks where an actor hop would change timing.EvenBLETransport's characteristic UUIDs and advertised-name prefix.CBUUIDisn't annotatedSendable, so the three UUIDs arenonisolated(unsafe)— immutable value objects created once, stated rather than worked around.LocalLLMService.visionModelIds,LLMService.localSafeTools,VideoRecordingService.frameStallSeconds.FingerspellingModelDownloader.liveInstallermoves onto the nonisolatedFingerspellingModelBundle, mirroring the existingASRModelBundleprecedent. That also resolves the redundantawait progress(...): the closure is no longer main-actor-inferred, so the hop is real — and the download's file I/O leaves the main thread.Sendable
UserInput(and theCIImagein it) is built inside the@Sendableclosure from Sendable ingredients only, instead of crossing the boundary.MediaTriggerService's notification handler is typed@Sendable.BroadcastAudioProvidingis@MainActor— the adopter and both call sites already were; only the handlers it registers are@Sendable.iOS 26 deprecations
Deployment target is 26.0, so no availability gates were needed.
init(windowScene:)is the only survivingUIWindowinitialiser, so the scene-less tail traps rather than returning an unpresentable empty window. Worth a reviewer's eye — it's a new trap where there wasn't one, thoughsignIn()is only reachable from a Settings button tap, which requires a live scene, and the empty window it replaced could never have presented anything.MKMapItem(location:address:)instead of the deprecatedMKPlacemark.Also
Two discarded
capturePhoto()results made explicit (it files every capture to the "Glasses" album itself), a discardedseekToEnd(), two redundanttrys on non-throwing closures passed to arethrowsfunction, and three redundantawaits in the download tests.Verification
Every edited file was confirmed present in the build's
SwiftCompilelines — an incremental build can silently skip a file, making a fixed warning and an unrecompiled file look identical. Three fixes initially looked verified and weren't; they were forced to rebuild and re-checked.Build bumped to 351 per the per-merge convention; marketing version unchanged (no new feature).
Not addressed
Two xcodebuild notices remain, both pre-existing and neither a compiler warning:
OpenGlasses/Sources/Modelsand.../Sharedare members of multiple groups in the generated project. That's aproject.base.ymlgroup-layout artifact from the widget target referencing individual files inside a directory the app target includes wholesale — changing shared-file group placement risks the widget's target membership, so it's left alone.Separately, a Release build does not launch on device — see #304. That's a vendored-dependency static-init deadlock, unrelated to this PR (the Release compile here is clean; the hang is pre-
main).🤖 Generated with Claude Code