iOS: return-to-start stop prompt (epic #997) #998

Closed
opened 2026-08-07 03:51:20 +00:00 by spikerj · 1 comment
Owner

Part of epic #997.

  • Core/Tracking/ReturnToStartDetector.swift — pure struct per epic spec (Config/Event, process/reset), TrackStats.haversineKm, start passed per call from points.first.
  • ActivityRecorder.swift — the one recorder change: var onRawFix: (@MainActor (CLLocation) -> Void)? invoked in ingest after the accuracy sanity line, before the 2 s/5 m gates.
  • Core/Notifications/LocalNotificationService.swift (greenfield UserNotifications): auth at recording start (.alert/.sound), category RETURN_TO_START with background actions STOP_AND_SAVE + KEEP_RECORDING, post/clear prompt (no notification sound — chime is the sound), delegate willPresent → banner, didReceive routes stop action. Delegate wired in AppDependencies.
  • Core/Tracking/ReturnToStartMonitor.swift — GhostRaceEngine-shaped consumer + raw-fix hook; on fire: AudioCueService.play(GapAnnouncement(chime: .ahead, phrase: "You're back at your start. Stop recording?")) + notification + promptActive. stopAndSave() = recorder.stop → auto-save "Untitled activity" → routeSync.syncNow().
  • TrackerView — notification auth after start/resumeRecovered; in-app banner (Stop & save / Keep recording, proximity-capsule pattern); toolbar gear → new TrackerSettingsSheet (tracker.returnPrompt.enabled, default true).
  • SpikerSoftTests/ReturnToStartDetectorTests.swift — full epic test matrix. xcodegen generate.
Part of epic #997. - `Core/Tracking/ReturnToStartDetector.swift` — pure struct per epic spec (Config/Event, process/reset), `TrackStats.haversineKm`, start passed per call from `points.first`. - `ActivityRecorder.swift` — the one recorder change: `var onRawFix: (@MainActor (CLLocation) -> Void)?` invoked in `ingest` after the accuracy sanity line, before the 2 s/5 m gates. - `Core/Notifications/LocalNotificationService.swift` (greenfield UserNotifications): auth at recording start (.alert/.sound), category `RETURN_TO_START` with background actions `STOP_AND_SAVE` + `KEEP_RECORDING`, post/clear prompt (no notification sound — chime is the sound), delegate willPresent → banner, didReceive routes stop action. Delegate wired in `AppDependencies`. - `Core/Tracking/ReturnToStartMonitor.swift` — GhostRaceEngine-shaped consumer + raw-fix hook; on fire: `AudioCueService.play(GapAnnouncement(chime: .ahead, phrase: "You're back at your start. Stop recording?"))` + notification + `promptActive`. `stopAndSave()` = recorder.stop → auto-save "Untitled activity" → `routeSync.syncNow()`. - `TrackerView` — notification auth after start/resumeRecovered; in-app banner (Stop & save / Keep recording, proximity-capsule pattern); toolbar gear → new `TrackerSettingsSheet` (`tracker.returnPrompt.enabled`, default true). - `SpikerSoftTests/ReturnToStartDetectorTests.swift` — full epic test matrix. `xcodegen generate`.
Author
Owner

Migrated to spikerj/spikersoft-ios#17 as part of the umbrella-tracker breakup.

Verified 2026-08-07 against spikersoft-ios@6926525 (main). Status: not started. No Core/Tracking/ReturnToStartDetector.swift, no ReturnToStartMonitor.swift, no Core/Notifications/LocalNotificationService.swift (SpikerSoft/Features/Notifications/ is still just a .gitkeep), no TrackerSettingsSheet, no onRawFix hook in ActivityRecorder.swift, and no ReturnToStartDetectorTests.swift.

The Android twin (#999) shipped at spikersoft-android@04d9c7b and is the reference for the detector semantics and the shared test matrix. AudioCueService is now safe to touch from the unit-test host — its AVSpeechSynthesizer became lazy in #1001 (AudioCueService.swift:27).

Closing here. Work now lives in the repo that holds the fix, so fixes #17 in a PR will auto-close it on merge. The umbrella tracker keeps cross-repo epics only.

— Opus 5 Agent

Migrated to **spikerj/spikersoft-ios#17** as part of the umbrella-tracker breakup. Verified 2026-08-07 against `spikersoft-ios@6926525` (main). Status: **not started.** No `Core/Tracking/ReturnToStartDetector.swift`, no `ReturnToStartMonitor.swift`, no `Core/Notifications/LocalNotificationService.swift` (`SpikerSoft/Features/Notifications/` is still just a `.gitkeep`), no `TrackerSettingsSheet`, no `onRawFix` hook in `ActivityRecorder.swift`, and no `ReturnToStartDetectorTests.swift`. The Android twin (#999) shipped at `spikersoft-android@04d9c7b` and is the reference for the detector semantics and the shared test matrix. `AudioCueService` is now safe to touch from the unit-test host — its `AVSpeechSynthesizer` became lazy in #1001 (`AudioCueService.swift:27`). Closing here. Work now lives in the repo that holds the fix, so `fixes #17` in a PR will auto-close it on merge. The umbrella tracker keeps cross-repo epics only. — Opus 5 Agent
Sign in to join this conversation.