Problem
Calories is distance times a constant.
// app/Actions/Activity/ActivityIndexAction.ts:210
calories: Math.round((a.distance ?? 0) * 95),Checked against live production activities, and it is exact:
| distance | shown | distance x 95 |
|---|---|---|
| 41.7 mi | 3,962 | 3,962 |
| 18.6 mi | 1,767 | 1,767 |
| 7.8 mi | 741 | 741 |
| 7.1 mi | 675 | 675 |
It ignores the athlete, the pace, the terrain and the activity type. The same 10 miles burns the same 950 calories whether it was a flat walk or a 3,000 ft climb, and whoever did it.
Why it matters more than the number being rough
It sits in the secondary stats row beside Elev ft, in the same type, with the same visual weight — and elevation is now genuinely measured from the recorded track (859325b, 38c96b1). One of those two is a measurement and the other is distance x 95, and the page gives the reader no way to tell.
That is the same defect 50f4c2e just removed one instance of: a number that looks measured and is not. It also travels — it is in the feed card, the activity page, and the share image people post.
95 kcal/mile is a reasonable rule of thumb for running for an average-sized adult. It is well wrong for a walk, for a heavy pack, and for anyone far from average.
Options
1. Label it an estimate. Cheapest and honest: "~675 cal" or a footnote. Costs nothing, fixes the misleading part, keeps the number.
2. Make it better with what is already known. Activity type, elevation gain and moving time are all on the activity. A MET-based estimate using type and pace, adjusted for ascent, is a real improvement over a flat multiplier and needs no new input. Still an estimate, but one that tells a hike from a run.
3. Take the athlete into account. Needs weight, which means a profile field and a decision about asking for it. Best accuracy, most product surface.
4. Drop the tile. Nobody asked for it, it is derived from a number already on the page, and removing it costs no real information.
(1) is a one-line change and should probably happen regardless of which of the others is chosen.
Note
Only the index endpoint computes it — ActivityShowAction does not return calories at all, so the detail page renders whatever the feed put in the store. Whatever is decided, the two should agree.