From 2dfb7791a2ad026eb33f2a6916bf16b66c55bbd7 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Tue, 4 Aug 2026 18:14:24 +0200 Subject: [PATCH] fix(apple): the drift test tripped Swift's static exclusivity check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI caught what my local harness could not: reading `huge.count` inside the closure that already holds `huge` exclusively is an exclusivity violation, so PunktfunkKitTests failed to compile. The blind spot is worth recording. I verified `AudioRing` by compiling it against a standalone harness whose bodies were TOP-LEVEL code, where Swift applies DYNAMIC exclusivity — the same statement in a function body gets the static check and is a hard error. A harness that does not share the shape of the thing it stands in for can be green for a reason the real build does not have. The harness now puts every body in a method and compiles with `-enforce-exclusivity=checked`. Length now comes off the buffer pointer (`$0.count`), which is what the closure already owns. Co-Authored-By: Claude Opus 5 (1M context) --- .../apple/Tests/PunktfunkKitTests/AudioRingDriftTests.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clients/apple/Tests/PunktfunkKitTests/AudioRingDriftTests.swift b/clients/apple/Tests/PunktfunkKitTests/AudioRingDriftTests.swift index 70f3b56f..a86949dd 100644 --- a/clients/apple/Tests/PunktfunkKitTests/AudioRingDriftTests.swift +++ b/clients/apple/Tests/PunktfunkKitTests/AudioRingDriftTests.swift @@ -79,9 +79,11 @@ final class AudioRingDriftTests: XCTestCase { scratch.withUnsafeMutableBufferPointer { ring.read(into: $0.baseAddress!, count: want) } XCTAssertTrue(scratch.contains { $0 != 0 }, "should be playing after priming") - // Drain it dry with one oversized read, then feed a normal quantum again. + // Drain it dry with one oversized read, then feed a normal quantum again. The length comes + // off the buffer pointer, not off `huge`: touching the array inside the closure that is + // already holding it exclusively is an exclusivity violation. var huge = [Float](repeating: 0, count: 200 * perMS) - huge.withUnsafeMutableBufferPointer { ring.read(into: $0.baseAddress!, count: huge.count) } + huge.withUnsafeMutableBufferPointer { ring.read(into: $0.baseAddress!, count: $0.count) } let feed = [Float](repeating: 0.5, count: want) feed.withUnsafeBufferPointer { ring.write($0.baseAddress!, count: want) } scratch.withUnsafeMutableBufferPointer { ring.read(into: $0.baseAddress!, count: want) }