fix: personal records only count watch-recorded FIT activities; exclude phone/Strava GPX/TCX imports (bad GPS teleporting in old activities)
This commit is contained in:
@@ -530,6 +530,13 @@ def detect_route(activity_id: int, user_id: int):
|
||||
return {"status": "no_match"}
|
||||
|
||||
|
||||
# Personal records are only computed from device-recorded FIT files (Garmin and
|
||||
# other GPS watches/head units). Phone- and Strava-sourced GPX/TCX imports —
|
||||
# especially older ones — suffer GPS "teleporting" that fabricates impossibly
|
||||
# fast splits, so they're excluded from PRs entirely.
|
||||
PR_ELIGIBLE_SOURCE_TYPES = {"fit"}
|
||||
|
||||
|
||||
@celery_app.task(name="compute_personal_records")
|
||||
def compute_personal_records(activity_id: int, user_id: int, parsed: dict):
|
||||
"""Calculate personal records for standard distances from this activity."""
|
||||
@@ -539,6 +546,10 @@ def compute_personal_records(activity_id: int, user_id: int, parsed: dict):
|
||||
from sqlalchemy import select
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Only FIT (watch-recorded) activities are trusted for PRs — see note above.
|
||||
if parsed.get("source_type") not in PR_ELIGIBLE_SOURCE_TYPES:
|
||||
return {"status": "skipped_non_watch", "activity_id": activity_id}
|
||||
|
||||
data_points = parsed.get("data_points", [])
|
||||
total_dist = parsed.get("distance_m", 0) or 0
|
||||
sport = parsed.get("sport_type", "running")
|
||||
@@ -1188,8 +1199,9 @@ def backfill_indoor_distances(user_id: int):
|
||||
@celery_app.task(name="recompute_personal_records_all")
|
||||
def recompute_personal_records_all(user_id: int):
|
||||
"""Wipe and rebuild all personal records from stored activity data, excluding
|
||||
indoor (no-GPS) runs whose distance is unreliable. Fixes records polluted by
|
||||
treadmill over-measurement and any duplicate current-record rows."""
|
||||
indoor (no-GPS) runs and non-watch (GPX/TCX) imports whose distance is
|
||||
unreliable. Fixes records polluted by treadmill over-measurement, GPS
|
||||
teleporting in old phone/Strava imports, and any duplicate current-record rows."""
|
||||
from app.services.route_matcher import compute_best_splits, STANDARD_DISTANCES
|
||||
from app.core.database import SyncSessionLocal
|
||||
from app.models.user import Activity, ActivityDataPoint, PersonalRecord
|
||||
@@ -1209,6 +1221,8 @@ def recompute_personal_records_all(user_id: int):
|
||||
|
||||
best = {} # (sport, dist_m) -> {dur, aid, at, label}
|
||||
for a in acts:
|
||||
if a.source_type not in PR_ELIGIBLE_SOURCE_TYPES:
|
||||
continue # only watch-recorded FIT files count toward PRs
|
||||
if a.sport_type == "running" and a.polyline is None:
|
||||
continue # indoor/treadmill — unreliable distance
|
||||
rows = db.execute(
|
||||
|
||||
Reference in New Issue
Block a user