Goal
Final polish pass after the architectural refactor: tighten residual Sendable conformances in the logging layer, enable swift-version 6 + -strict-concurrency=complete everywhere, update the DocC catalog to match the new public surface.
Context
See the investigation report at docs/investigations/swift6-concurrency-audit-2026-05-13.md, sections Recommendations §C, Migration order Step 5, and Preventive Measures.
The Willow 7.0 upgrade (commit 3657f45) resolved the bulk of the logging-layer concurrency issues. Only small polish remains.
Deliverable (Step 5 of 5 in the migration plan)
ReliaBLEConfig explicit Sendable. Change public struct ReliaBLEConfig { … } to public struct ReliaBLEConfig: Sendable { … }. Compiler-synthesized today, but explicit is better as a public API surface.
- Verify
OSLogWriter synthesizes Sendable under -strict-concurrency=complete. If it doesn't (e.g., on a future SDK where OSLog's Sendable status changes), add @unchecked Sendable (matches upstream Willow.OSLogWriter):
public final class OSLogWriter: LogModifierWriter, @unchecked Sendable { … }
- Enable Swift 6 mode + complete strict concurrency in
Package.swift for both ReliaBLE and ReliaBLEMock targets:
.target(
name: "ReliaBLE",
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency"),
.swiftLanguageMode(.v6),
]
)
- DocC catalog update. Add a new
Concurrency.md page documenting:
ReliaBLEManager is Sendable and callable from any actor (MainActor SwiftUI and background actors).
- All actions are
async.
- All event surfaces return fresh per-subscriber
AsyncStreams.
- SwiftUI consumers should use
.task { for await … } patterns.
BluetoothActor is internal; consumers should not reference it directly.
- Architecture diagram (optional) in DocC showing the isolation graph (
ReliaBLEManager → BluetoothActor → delegate shim → CB).
- Smoke test: construct a
ReliaBLEManager inside Task.detached and exercise every public method. See Tests/ReliaBLETests.
Peripheral Sendable test: capture a Peripheral in a detached task; failure to compile catches accidental non-Sendable field regressions.
Decision: do NOT document the LoggingService.enabled race in DocC
The race is benign last-write-wins, inherited verbatim from Willow 7.0's deliberate upstream choice. A separate issue (itsniper/Willow#3) tracks the upstream fix; ReliaBLE will inherit it transparently when it lands. No ReliaBLE-side workaround or DocC note needed.
Acceptance criteria
swift build -strict-concurrency=complete clean on both targets.
swift test passes including the new smoke + Peripheral Sendable tests.
- DocC builds clean (
swift package generate-documentation). New Concurrency.md page renders.
ReliaBLEConfig: Sendable explicit.
Not in scope
- SwiftLint rules / CI wiring — that's NFR 11 (separate parent issue).
References
Goal
Final polish pass after the architectural refactor: tighten residual Sendable conformances in the logging layer, enable
swift-version 6+-strict-concurrency=completeeverywhere, update the DocC catalog to match the new public surface.Context
See the investigation report at
docs/investigations/swift6-concurrency-audit-2026-05-13.md, sections Recommendations §C, Migration order Step 5, and Preventive Measures.The Willow 7.0 upgrade (commit
3657f45) resolved the bulk of the logging-layer concurrency issues. Only small polish remains.Deliverable (Step 5 of 5 in the migration plan)
ReliaBLEConfigexplicit Sendable. Changepublic struct ReliaBLEConfig { … }topublic struct ReliaBLEConfig: Sendable { … }. Compiler-synthesized today, but explicit is better as a public API surface.OSLogWritersynthesizesSendableunder-strict-concurrency=complete. If it doesn't (e.g., on a future SDK whereOSLog's Sendable status changes), add@unchecked Sendable(matches upstreamWillow.OSLogWriter):Package.swiftfor bothReliaBLEandReliaBLEMocktargets:Concurrency.mdpage documenting:ReliaBLEManagerisSendableand callable from any actor (MainActor SwiftUI and background actors).async.AsyncStreams..task { for await … }patterns.BluetoothActoris internal; consumers should not reference it directly.ReliaBLEManager→BluetoothActor→ delegate shim → CB).ReliaBLEManagerinsideTask.detachedand exercise every public method. SeeTests/ReliaBLETests.PeripheralSendable test: capture aPeripheralin a detached task; failure to compile catches accidental non-Sendable field regressions.Decision: do NOT document the
LoggingService.enabledrace in DocCThe race is benign last-write-wins, inherited verbatim from Willow 7.0's deliberate upstream choice. A separate issue (itsniper/Willow#3) tracks the upstream fix; ReliaBLE will inherit it transparently when it lands. No ReliaBLE-side workaround or DocC note needed.
Acceptance criteria
swift build -strict-concurrency=completeclean on both targets.swift testpasses including the new smoke +PeripheralSendable tests.swift package generate-documentation). NewConcurrency.mdpage renders.ReliaBLEConfig: Sendableexplicit.Not in scope
References
docs/investigations/swift6-concurrency-audit-2026-05-13.mdLogger.enableddata race (deferred from 7.0 Sendable migration) itsniper/Willow#3BluetoothManagerSwift 6 safe #13, Step 2 issue, Remove Combine #12, Step 4 issue