EPIC: Activity tracker — ghost racing, audio pacing, route analysis #983

Closed
opened 2026-08-06 19:59:50 +00:00 by spikerj · 1 comment
Owner

Make the activity tracker derive real value from recorded activities:

  1. Ghost race mode — race yourself against a previously recorded activity (Mario Kart ghost style). Gap metric: time gap at my position (when did the ghost pass the point I'm at now).
  2. Eyes-free audio feedback — press a side button mid-activity → rising/falling chime + spoken delta ("ahead by 12 seconds"). iOS: volume-button capture while recording + Action Button App Intent + optional periodic auto-announce. Works with screen locked.
  3. Route analysis report (mobile + web) — where was I slowest/fastest, where did I rest, walk vs run classification, per-km splits, elevation gain/loss. Computed server-side so all clients share one implementation.

Verified starting state: tracker exists only on iOS (v1 record→upload); Android has no tracker; the web map-tracker is local-only; backend stores routes but computes only distance/duration/avg speed.

Workstream tickets (child issues):

  • Backend analysis engine + GET /api/recorded-routes/{id}/analysis + additive segment wire field
  • iOS ghost race + audio + report
  • Angular web report (first consumer of api/recorded-routes on web)
  • Android BASE tracker (parity port of iOS v1; ghost mode there is a later follow-up)

Cross-repo contract: backend RouteAnalysisDto is canonical; index ranges are inclusive indices into the upload-order points array; RouteStatsCalculator formulas untouched (3-repo fixture parity); never log coordinates.


Child issues (per-repo, auto-close on merge)

No open child issues were produced by the migration — either this epic's
work was already complete, or its scope needs to be broken down into
per-repo issues before it can progress.

Checklist generated by the umbrella-tracker migration, 2026-08-07 — Opus 5 Agent

Make the activity tracker derive real value from recorded activities: 1. **Ghost race mode** — race yourself against a previously recorded activity (Mario Kart ghost style). Gap metric: time gap at my position (when did the ghost pass the point I'm at now). 2. **Eyes-free audio feedback** — press a side button mid-activity → rising/falling chime + spoken delta ("ahead by 12 seconds"). iOS: volume-button capture while recording + Action Button App Intent + optional periodic auto-announce. Works with screen locked. 3. **Route analysis report** (mobile + web) — where was I slowest/fastest, where did I rest, walk vs run classification, per-km splits, elevation gain/loss. Computed server-side so all clients share one implementation. Verified starting state: tracker exists only on iOS (v1 record→upload); Android has no tracker; the web map-tracker is local-only; backend stores routes but computes only distance/duration/avg speed. Workstream tickets (child issues): - Backend analysis engine + `GET /api/recorded-routes/{id}/analysis` + additive `segment` wire field - iOS ghost race + audio + report - Angular web report (first consumer of `api/recorded-routes` on web) - Android BASE tracker (parity port of iOS v1; ghost mode there is a later follow-up) Cross-repo contract: backend `RouteAnalysisDto` is canonical; index ranges are inclusive indices into the upload-order points array; `RouteStatsCalculator` formulas untouched (3-repo fixture parity); never log coordinates. <!-- BEGIN MIGRATED-CHILDREN --> --- ## Child issues (per-repo, auto-close on merge) _No open child issues were produced by the migration — either this epic's work was already complete, or its scope needs to be broken down into per-repo issues before it can progress._ <sub>Checklist generated by the umbrella-tracker migration, 2026-08-07 — Opus 5 Agent</sub> <!-- END MIGRATED-CHILDREN -->
spikerj added the epic label 2026-08-07 13:43:04 +00:00
Author
Owner

Dissolved into per-repo issues as part of the umbrella-tracker breakup. This epic held implementation work that could never auto-close from a merge; it now lives where the code is:

Already shipped, no issue filed — verified 2026-08-07 against synced master and live prod:

  • Backend analysis engine (was spikerj/spikersoft-issues#984): spikersoft-backend@98102023 — SpikerSoft.Business/Domain/Map/RecordedRoutes/Services/RouteAnalyzer.cs, canonical wire shapes in SpikerSoft.Data/DTOs/RouteAnalysisDtos.cs (totals, walk/run/rest segments, per-km splits, rests, fastest/slowest sections, RouteGhostTrackDto), endpoint RecordedRoutesController.cs:150, cached in RecordedRouteAnalysisEF and correctly invalidated by the trim handler. Live: GET https://api.spikersoft.com/api/recorded-routes/<id>/analysis → 401 (auth) while a bogus sibling path → 404, so the route is registered and deployed; /healthz → Healthy.
  • iOS ghost race + audio + report (#985): spikersoft-ios@69265254 — Core/Tracking/GhostRaceEngine.swift, Core/Tracking/GhostComparator.swift (time-gap-at-my-position, 75 m corridor, pause-aware), Core/Audio/AudioCueService.swift + VolumeButtonTrigger.swift + GapAnnouncement.swift, Core/Intents/AnnounceGhostGapIntent.swift, auto-announce cadence in GhostRaceSettingsSheet.swift, and Features/Tracker/RouteAnalysisView.swift reachable from RouteDetailView.swift:58.
  • Angular web report (#986): spikersoft-angular@8e5a4048 — projects/spikersoft/src/app/_components/activity-report/ (classified path, fastest/slowest underlays, rest markers, splits table). Live: learn.spikersoft.com main bundle main-KZKZUOSX.js contains tracker/activities.
  • Android base tracker (#987): spikersoft-android@fbe33d30 — recording service, route DB, sync worker, trim screen, and the additive segment wire field in core/network/TrackerDtos.kt.

What is left is exactly what this epic deferred: "Android BASE tracker (parity port of iOS v1; ghost mode there is a later follow-up)". grep -ri "ghost|analysis|TextToSpeech|SoundPool" over spikersoft-android/app/src/ returns 0 hits, and core/network/SpikerSoftApi.kt has no {id}/analysis call — hence the four Android issues above.

Not duplicated here (already tracked): spikerj/spikersoft-ios#16 (iOS route trim UI), spikerj/spikersoft-ios#17 (return-to-start prompt), spikerj/spikersoft-infrastructure#166 (terrain tile health canary).

The unit is tracked by the shared [Tracker v2] title prefix and by sibling cross-links in each issue. Closing here — the umbrella tracker is being emptied.

— Opus 5 Agent

Dissolved into per-repo issues as part of the umbrella-tracker breakup. This epic held implementation work that could never auto-close from a merge; it now lives where the code is: - Android: spikerj/spikersoft-android#15 — route analysis report screen, consuming `GET /api/recorded-routes/{id}/analysis` - Android: spikerj/spikersoft-android#16 — ghost race mode (port of iOS `GhostComparator`/`GhostRaceEngine`) - Android: spikerj/spikersoft-android#17 — audio pacing cues (rising/falling chime + spoken gap delta + auto-announce cadence) - Android: spikerj/spikersoft-android#18 — **decision issue**: which eyes-free manual trigger Android uses (iOS's volume-button capture + Action Button have no Android equivalent) **Already shipped, no issue filed** — verified 2026-08-07 against synced master and live prod: - **Backend analysis engine** (was spikerj/spikersoft-issues#984): `spikersoft-backend@98102023` — `SpikerSoft.Business/Domain/Map/RecordedRoutes/Services/RouteAnalyzer.cs`, canonical wire shapes in `SpikerSoft.Data/DTOs/RouteAnalysisDtos.cs` (totals, walk/run/rest segments, per-km splits, rests, fastest/slowest sections, `RouteGhostTrackDto`), endpoint `RecordedRoutesController.cs:150`, cached in `RecordedRouteAnalysisEF` and correctly invalidated by the trim handler. **Live:** `GET https://api.spikersoft.com/api/recorded-routes/<id>/analysis` → 401 (auth) while a bogus sibling path → 404, so the route is registered and deployed; `/healthz` → `Healthy`. - **iOS ghost race + audio + report** (#985): `spikersoft-ios@69265254` — `Core/Tracking/GhostRaceEngine.swift`, `Core/Tracking/GhostComparator.swift` (time-gap-at-my-position, 75 m corridor, pause-aware), `Core/Audio/AudioCueService.swift` + `VolumeButtonTrigger.swift` + `GapAnnouncement.swift`, `Core/Intents/AnnounceGhostGapIntent.swift`, auto-announce cadence in `GhostRaceSettingsSheet.swift`, and `Features/Tracker/RouteAnalysisView.swift` reachable from `RouteDetailView.swift:58`. - **Angular web report** (#986): `spikersoft-angular@8e5a4048` — `projects/spikersoft/src/app/_components/activity-report/` (classified path, fastest/slowest underlays, rest markers, splits table). **Live:** `learn.spikersoft.com` main bundle `main-KZKZUOSX.js` contains `tracker/activities`. - **Android base tracker** (#987): `spikersoft-android@fbe33d30` — recording service, route DB, sync worker, trim screen, and the additive `segment` wire field in `core/network/TrackerDtos.kt`. What is left is exactly what this epic deferred: "Android BASE tracker (parity port of iOS v1; **ghost mode there is a later follow-up**)". `grep -ri "ghost|analysis|TextToSpeech|SoundPool"` over `spikersoft-android/app/src/` returns **0 hits**, and `core/network/SpikerSoftApi.kt` has no `{id}/analysis` call — hence the four Android issues above. Not duplicated here (already tracked): spikerj/spikersoft-ios#16 (iOS route trim UI), spikerj/spikersoft-ios#17 (return-to-start prompt), spikerj/spikersoft-infrastructure#166 (terrain tile health canary). The unit is tracked by the shared `[Tracker v2]` title prefix and by sibling cross-links in each issue. Closing here — the umbrella tracker is being emptied. — Opus 5 Agent
Sign in to join this conversation.