feat: avg pace over moving time (fixes elapsed-based pace on paused activities); show mid-activity pauses on Body Battery band via active_spans
Build and push images / validate (push) Successful in 3s
Build and push images / build-backend (push) Successful in 7s
Build and push images / build-worker (push) Successful in 5s
Build and push images / build-frontend (push) Successful in 10s

This commit is contained in:
2026-06-20 20:04:53 +01:00
parent 0e1d35364f
commit e33946e270
6 changed files with 111 additions and 14 deletions
+9 -3
View File
@@ -72,9 +72,14 @@ def _apply_garmin_summary(parsed: dict, summary: dict):
parsed["moving_time_s"] = summary["moving"]
if summary.get("elapsed") is not None:
parsed["duration_s"] = summary["elapsed"]
dur = parsed.get("duration_s")
if parsed.get("distance_m") and dur:
parsed["avg_speed_ms"] = parsed["distance_m"] / dur
# Recompute average speed over moving (timer) time, not elapsed wall-clock —
# otherwise a long mid-activity pause (e.g. a meal stop on a ride) drags the
# displayed pace down across the whole break. Falls back to elapsed only when
# moving time is unavailable.
moving = parsed.get("moving_time_s")
denom = moving if (moving and moving > 0) else parsed.get("duration_s")
if parsed.get("distance_m") and denom:
parsed["avg_speed_ms"] = parsed["distance_m"] / denom
@celery_app.task(bind=True, name="process_activity_file")
@@ -174,6 +179,7 @@ def process_activity_file(self, file_path: str, user_id: int, source_type: str,
normalized_power=parsed.get("normalized_power"),
avg_speed_ms=parsed.get("avg_speed_ms"),
max_speed_ms=parsed.get("max_speed_ms"),
active_spans=parsed.get("active_spans"),
avg_temperature_c=parsed.get("avg_temperature_c"),
calories=parsed.get("calories"),
training_stress_score=parsed.get("training_stress_score"),