Files
Stride/docs/PERSONAL_RECORDS.md
T

58 lines
3.2 KiB
Markdown

# Running personal records
Activity import calculates and persists estimated best efforts for
1 km, 2 km, 5 km, 10 km, half marathon (21,097.5 m), and marathon (42,195 m).
These are fastest stretches anywhere within a run, rather than lap times or
times projected from average pace. All existing running activities participate.
Following [Strava's elapsed-time convention](https://support.strava.com/en-us/articles/15401661-how-do-best-efforts-work-for-running-on-strava),
stops inside an effort count. The calculation uses full-resolution FIT cumulative
distance and timestamps, with linear interpolation at distance boundaries. Missing
distance/time, backwards distance, and non-increasing timestamps split the data.
Timestamp gaps count as elapsed time; there is no subtraction for auto-pause.
No distance or time is inferred from an activity summary when samples are absent.
The dashboard lists current records. Runs earn historical PR badges if they
established or strictly improved a record on their activity date; equal times
do not earn another badge. Import order does not affect the result. Records and
badges are recalculated from history, so older imports and removals are reflected.
Comparisons currently appear only in the owner's dashboard and activity page.
These are estimates from watch data, not verified race records or an exact clone
of Strava's proprietary calculation. GPS/distance spikes or sparse recording can
affect results. There is currently no manual effort exclusion or correction UI.
Imports (FIT upload, Garmin sync and local cache) persist per-run efforts in the
same transaction as the run. Refreshing recorded data recalculates the efforts.
`efforts_version` identifies the calculation version; version 0 means pending.
A current version with an empty list means calculated with no eligible distances.
Page requests only compare stored efforts; there is no sample-based fallback.
Raw samples and laps are deferred in list queries. Route availability is also
persisted, so the dashboard can choose its map without loading historical samples.
Chronological PR comparisons still happen on page requests, using at most six
stored efforts per run, preserving correct badges after backfills or removals.
After `flask --app app db upgrade`, run:
```sh
flask --app app backfill-efforts --batch-size 25
```
The command commits each bounded batch and skips current-version rows on reruns.
It includes non-running and incomplete activities, storing an empty result when
appropriate. `--owner-id ID` limits the operation to one athlete; `--force`
recalculates current results. It uses row locks on PostgreSQL to coordinate with
concurrent refreshes, and fixes an upper activity ID at the start so new imports
do not extend the backfill indefinitely. New imports calculate their own results.
No FIT files need to be downloaded again. On Dokku:
```sh
dokku run stride flask --app app backfill-efforts --batch-size 25
```
Until backfill finishes, pending activities do not contribute to records or
route selection. Keep backfills separate from schema migrations so a large
history does not delay every deployment.
Further additions could include second/third-best medals, annual records, manual
exclusion of bad recordings, and a selected-effort highlight on the route map.