Add matched training signals, daily recovery and performance analysis
This commit is contained in:
@@ -1,6 +1,24 @@
|
||||
# Dokku deployment
|
||||
|
||||
App: `stride`; database: `stride-db`; domain: `stride.peterstockings.com`.
|
||||
|
||||
Training-signal releases migrate private daily recovery and session preferences
|
||||
automatically. Back up PostgreSQL before release, then recompute older recordings:
|
||||
|
||||
```sh
|
||||
dokku run stride env FLASK_APP=app flask backfill-analysis --batch-size 20
|
||||
dokku run stride env FLASK_APP=app flask install-training-signals --email ACCOUNT
|
||||
dokku run stride env FLASK_APP=app flask backfill-health --email ACCOUNT --days 90
|
||||
```
|
||||
|
||||
The installer validates queries before saving, pins five analyses and preserves
|
||||
existing edits on repeat runs. Pace and long-run thresholds are editable CLI
|
||||
options and account queries. Recovery backfill uses the existing encrypted
|
||||
session and account lock, enables recovery only for that account and leaves
|
||||
missing watch observations missing. Other accounts can opt in through Settings;
|
||||
recovery failures do not stop activity imports. Never run a local copy of the
|
||||
same Garmin session concurrently with production. Analysis version 3 persists
|
||||
continuous windows; no dashboard query loads full recording samples.
|
||||
The Dockerfile installs locked dependencies on Python 3.12. Dokku runs database
|
||||
migrations in the predeploy step, then one web container and one sync worker.
|
||||
|
||||
|
||||
@@ -1,5 +1,117 @@
|
||||
# Run analysis DSL
|
||||
|
||||
## Deep training signals
|
||||
|
||||
`intervals` reads persisted, non-overlapping continuous moving windows of up to
|
||||
30 seconds. Recording breaks over ten seconds, distance resets, stops and
|
||||
implausible movement end a window; windows never join across those breaks.
|
||||
Filter `duration >= 25 s` to remove short fragments. `elapsed` and
|
||||
`moving_offset` are minutes since recording start and usable moving start.
|
||||
Elapsed offsets use relative time even when FIT timestamps are Unix timestamps.
|
||||
|
||||
```text
|
||||
intervals
|
||||
during last 16 weeks
|
||||
reduce by run min 3 min
|
||||
where elapsed >= 10 min
|
||||
and duration >= 25 s
|
||||
and pace between 6:30 and 7:00 /km
|
||||
and grade between -2 and 2 %
|
||||
and grade_variability <= 2 %
|
||||
and pace_variability <= 15 %
|
||||
and sensor_coverage >= 90 %
|
||||
and hr_artifact_percent = 0 %
|
||||
summarize mean(heart_rate) as "Matched HR"
|
||||
by run
|
||||
sort by date asc
|
||||
compare none
|
||||
chart line
|
||||
```
|
||||
|
||||
Filters run **before** `reduce by run`. A session needs the specified total
|
||||
matched moving minutes to contribute one observation. Within-session HR and
|
||||
mechanics are weighted by usable sensor time; `mean` across reduced observations
|
||||
weights each session equally. `count()` then counts independent sessions rather
|
||||
than windows. Matched windows can be separated in time. This is different from
|
||||
requiring one uninterrupted three-minute section. Charts show distinct-session
|
||||
and usable-minute coverage, and run plots preserve calendar spacing.
|
||||
|
||||
`grade` is duration-weighted signed grade using the existing smoothed elevation
|
||||
model; `grade_variability` is its population SD in percentage points. GAP and
|
||||
grade require at least 80% terrain coverage. Window-level cadence, power,
|
||||
stride length, vertical oscillation and ground contact include sensor coverage
|
||||
metrics. HR outside 30–240 bpm or a jump exceeding 20 bpm per second is excluded
|
||||
and counted in `hr_artifact_percent`. These coarse checks do not detect every
|
||||
sensor artifact or cadence lock. Terrain, HR lag, weather and session intent
|
||||
remain confounders; the matcher does not claim to remove them.
|
||||
|
||||
After reduction, `heart_rate_drift` is recomputed over matched moving-time
|
||||
halves, excluding any filtered warm-up. Each half needs at least ten minutes of
|
||||
joint usable HR and terrain, and 80% of the half's time. Halves must differ by
|
||||
at most 10% in speed and one percentage point of mean grade. Otherwise the
|
||||
result is missing. Positive means lower speed/HR efficiency later. This is a
|
||||
descriptive comparison, not an overtraining diagnosis. Recording-level flags
|
||||
require reduction to independent sessions; a baseline still needs ten runs.
|
||||
|
||||
`efforts` expands the persisted best elapsed windows. Use `where distance = 5 km`
|
||||
and `min(effort_time)` for a 5 km progression. Whole runs expose `best_1km`,
|
||||
`best_2km`, `best_5km`, and `best_10km`, which accept second/minute filters and
|
||||
display elapsed min:sec. No attempt at that distance remains missing. These
|
||||
efforts are windows inside runs, not standardized races.
|
||||
|
||||
```text
|
||||
days
|
||||
during last 16 weeks
|
||||
long run distance >= 10 km
|
||||
summarize latest(days_since_long_run), latest(rolling_28d_distance)
|
||||
by day
|
||||
compare none
|
||||
chart line
|
||||
display overlay
|
||||
```
|
||||
|
||||
`days` includes rest days. `sessions`, `days_since_run`, `days_since_long_run`,
|
||||
`run_day_streak`, and `long_run_share` expose continuity and concentration.
|
||||
`long_run_share` is the largest individual run's share of the current seven-day
|
||||
distance. Daily 7/28-day windows include the current local day plus the previous
|
||||
6/27 local days, including history before the query. Whole-run rolling metrics
|
||||
continue to use elapsed 168/672-hour windows. Missing prior long-run history
|
||||
does not become a fabricated gap. `latest(field)` selects the latest input by
|
||||
timestamp regardless of sort order, retaining missing values on that input;
|
||||
it is useful for current dashboard values and cannot define a baseline band.
|
||||
|
||||
`health` reads owner-only Garmin resting HR, overnight HRV, sleep duration and
|
||||
stress observations (`resting_hr`, `hrv`, `sleep_hours`, `stress`). Enable the
|
||||
optional recovery sync in Settings. The worker refreshes today/yesterday and
|
||||
backfills a bounded batch of earlier dates. Provider gaps and unsupported watch
|
||||
observations stay missing; no readiness score is inferred. Daily inputs link
|
||||
to their contributing runs when present; rest/recovery-only days do not invent
|
||||
activity links. Daily sources also support calendar rolling calculations.
|
||||
|
||||
Private activity notes expose `perceived_effort` (1–10) and `fatigue` (0–10).
|
||||
They are never shown on public or friend activity pages. Settings accepts two
|
||||
personal HR boundaries. `lower_hr_minutes`, `middle_hr_minutes`, and
|
||||
`upper_hr_minutes` sum actual usable moving sample time, rather than assigning
|
||||
an entire run/window according to its average HR. Boundary HR belongs to the
|
||||
higher band. Missing thresholds mean missing results; physiological zones are
|
||||
never assumed.
|
||||
|
||||
`route similar to ID` restricts recordings to an approximate full-course match
|
||||
against one of your own runs. The comparison resamples compact geometry along
|
||||
distance, requires endpoints within 100 m, length within 10%, mean course
|
||||
separation ≤100 m and 90th-percentile separation ≤200 m. Different directions
|
||||
and recording breaks are excluded; geometry shorter than 500 m is unavailable.
|
||||
This is an exploratory same-start course matcher, not exact named-segment
|
||||
recognition. Always inspect the contributing courses.
|
||||
|
||||
Operators can run `flask --app app install-training-signals --email ACCOUNT`
|
||||
to save editable examples and pin the first five. `--pace-low`, `--pace-high`
|
||||
and `--long-run` customize matching. Re-running preserves existing library
|
||||
edits. Recompute old recordings with `backfill-analysis` (version 3).
|
||||
`backfill-health --email ACCOUNT --days 90` imports bounded recovery history
|
||||
using the normal account session lock and encrypted token rotation; only this
|
||||
account's recovery sync is enabled.
|
||||
|
||||
## Account library and live dashboard
|
||||
|
||||
Save an analysis with a name, investigation collection and notes. **Save as new**
|
||||
|
||||
Reference in New Issue
Block a user