# U5 independent frozen-source review

Reviewed `/tmp/rideform-u5-preview3-snapshot` against `CLAUDE.md`, the original iOS brief, U5/R8–R11 and KTD4/KTD5/KTD7/KTD12 in the unified plan, and `docs/validation/u5-evidence.md`. This review describes the frozen preview, before subsequent coordinator/U7 changes.

## Findings

1. **P1 — Synchronize clock mapping before Start copies it.** Frozen `App/RecordingController.swift:114` reads `capture.clock.mapping` on the main actor while `App/SessionClock.swift:39–40` mutates its `validated` and `[String] checks` fields on the capture control queue for every accepted motion callback. Copying a Swift array concurrently with replacing it is a data race, with possible retained-storage corruption. Obtain the mapping through the ordered capture snapshot, or protect all mapping reads/writes with the same lock; `now()` only reads immutable scale and does not require this fix.

   Independent reproducer: `/tmp/rideform-u5-clock-race.swift` contains the frozen `SessionClock` verbatim, the actual core `ClockMapping` definition, and two queues repeatedly updating/copying mapping. Compile with `DEVELOPER_DIR=/Applications/Xcode-beta.app/Contents/Developer xcrun swiftc -module-cache-path /tmp/rideform-u5-review-module-cache -sanitize=thread /tmp/rideform-u5-clock-race.swift -o /tmp/rideform-u5-clock-race`, then run. `/tmp/rideform-u5-clock-race.log` reports a Thread Sanitizer data race in `SessionClock.validateMapping`, followed by `_ContiguousArrayStorage` deallocation with a nonzero retain count; exit 134. This is an isolated high-contention reproduction of the real unsynchronized access, not an observed app crash.

2. **P2 — Declare the timestamp export purpose in the privacy manifest.** Frozen `App/PrivacyInfo.xcprivacy` declares only system-boot-time reason `35F9.1`, but ZIP/CSV exports retain Mach event/receipt/anchor timestamps, rather than only elapsed durations. Apple's current [required-reason documentation](https://developer.apple.com/documentation/bundleresources/app-privacy-configuration/nsprivacyaccessedapitypes/nsprivacyaccessedapitypereasons) permits elapsed-event durations to leave the device under `35F9.1`; `8FFB.1` covers calculating/exporting absolute timestamps for in-app events. Add the applicable timestamp reason and document the event timestamp purpose. Confirm that exported Mach timestamps qualify as in-app absolute event timestamps; this reason still excludes boot-time information and other derived information. Preserve the experiment's raw records. Official documentation payload retained at `/tmp/rideform-u5-privacy-reasons.json`. This is a distribution/privacy declaration issue, not a blocker to local hardware sign/sampling experiments.

## Other reviewed behavior

- Recording sink installation/detachment is locked; accepted capture callbacks enqueue directly to the serial writer. Capture's stop barrier precedes sink detachment/finalization, suppresses later-generation callbacks, and reconciles recording-local sequences/counts.
- Calibration and recording share the same capture reference. Stop, capture-mode change, and scene interruption invalidate recording authorization; prior calibration evidence remains retained. Saved review and saveError guard against starting over an unsaved master.
- Cue dispatch uses the shared immutable Mach clock accessor, saves scheduled and actual dispatch timestamps, and suppresses pending jobs through a generation token. Acoustic onset is explicitly unmeasured. Stop/interruption restores the prior idle timer setting.
- Saved-list reload and export preserve immutable masters. Session loading/export work runs off-main; synthetic generation is simulator-compiled, explicitly enabled, and labeled. The app includes motion usage text and declares no tracking/collected-data purpose.

## Evidence and remaining tests

The coordinator's `/tmp/rideform-u5-preview3-tests.log` reports 16 passing app tests plus the passing full UI workflow (41.428 seconds); result bundle `/tmp/rideform-u5-preview3-derived/Logs/Test/Test-RideForm-2026.10.01_11-34-10--0500.xcresult`. I inspected the log/test assertions but did not rerun shared Xcode/simulator sessions. The independent clock reproducer above is the additional executed evidence.

Controller-level fault tests do not yet exercise checkpoint failure → interrupted finalization, finalization failure → retained writer → successful retry, or later convention invalidation → interruption. Core writer/recovery coverage and source guards help, but do not establish those complete UI lifecycle paths. Interrupted/incomplete files are discoverable on relaunch; physical suspension during saving remains a device check.

Physical mounting/sign checks, real authorization/rates, matched raw/fused trials, acoustic onset, background-save timing on hardware, Dynamic Type/VoiceOver checks, and approximately 50 garage transitions remain pending human/device gates. No simulator or standalone concurrency result is hardware motion evidence.
