# Guided calibration recovery and attempt logs — build 5

2026-10-01. Baseline f042db6, clean tree. James reached the final step and heard failure but could not recall its reason. No attempt log existed for that physical failure, so its exact cause remains unknown. James authorized adding logging.

## Behavior

At most two automatic guided retries per calibration attempt. Similar LEFT/FORWARD axes retain neutral and LEFT, return to center, and repeat FORWARD. Weak/short final gesture evidence retains neutral and repeats both leans after recentering. A gesture or return timeout repeats that step. Retry instructions explain what happened and what is retained. The existing four-second waiting feedback continues. Once the retry budget is exhausted, the specific reason precedes the instruction to retry manually. Original neutral is never replaced by a return check. Invalid input, unverified sensor direction, standard-mount mismatch and transport/speech watchdog failures remain explicit stops.

RIGHT is not added in this build: it repeats the lateral axis; FORWARD supplies the independent axis required by the fit. A future right-side validation is distinct from recovering a rejected forward capture.

Each attempt writes a separate JSON diagnostic log under Sessions/CalibrationLogs, excluded from .rideform master/session listing. Entries contain build, wall/uptime, stage, exact error code, retry count, neutral/left/forward/hold counts, latest measured center offset/angular speed, spoken instructions, final convention verification, and cancellation. Writes are atomic; write failures are visible. These are diagnostic snapshots, not a full raw-motion recording or acoustic evidence. Latest log survives relaunch and can be shared from ready/uncalibrated/terminal-retry screens. Log sharing is absent during active calibration and recording.

## Verification

- RED: a final collinear-gesture rejection stops the old controller, preventing a corrected forward retry (`/tmp/rideform-retry-red.log`).
- Regression now preserves earlier center/left timestamps and succeeds with a corrected forward lean. Existing timeout tests were extended to assert the two-retry bound before terminal failure.
- Actual RecordingController/fixture test forces three final-fit rejections; requires two recovery cycles, continued capture, three logged fits and eventual explicit stop.
- Logging test reads persisted JSON, checks rejection/cancel reason, reopens latest log and confirms no session is manufactured.
- Independent Swift source review identified a pending-snapshot lifecycle edge. Fixed by clearing snapshotPending on watchdog generation invalidation and disallowing automatic gesture recovery for transport/speech watchdog errors. Final review has no findings. Reviewer ran no tests/builds.
- Scoped simplification kept existing stage buffers and speaker. One separate log writer owns attempt files; no changes to core solver thresholds or recorded-session schemas.

All 38 app integration tests passed (`/tmp/rideform-retry-final-app.log`, TEST SUCCEEDED), including actual capture across three fit attempts and persisted log reopening. Signed device build succeeded (`/tmp/rideform-retry-device.log`). The full UI workflow, including opening and dismissing the calibration-log share popover, passed (`/tmp/rideform-retry-ui-final.log`). The first share test incorrectly expected a Close button; observed UI exposed PopoverDismissRegion, now used by the test. Latest-log discovery uses modification time, not random filename ordering. The final log-persistence/latest-selection test passed (`/tmp/rideform-retry-log-final.log`), and the final signed build and codesign verification passed (`/tmp/rideform-retry-device-final.log`). Physical reproduction of James’s original rejection still requires another attempt; the new log is the evidence source if it recurs.

After James reconnected the iPhone, build 5 installed successfully (`/tmp/rideform-retry-install.json`), inventory confirmed bundleVersion 5 (`/tmp/rideform-build5-inventory.json`), and launch succeeded (`/tmp/rideform-retry-launch.log`). Physical calibration and spoken retry behavior still require James’s trial.
