Replace fixed DSL fields with parameterized metric expressions

This commit is contained in:
Peter Stockings
2026-10-04 10:24:12 +11:00
parent 418e03583a
commit d660b86bb0
18 changed files with 402 additions and 137 deletions
+26 -14
View File
@@ -54,28 +54,31 @@ 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
and `min(effort_time)` for a 5 km progression. Whole runs expose
`best_time(1 km)`, `best_time(2 km)`, `best_time(5 km)`, and `best_time(10 km)`,
which accept second/minute filters and display elapsed min:sec. Unsupported
distances produce a validation error; supported distances without an attempt remain 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)
summarize latest(days_since_run(distance >= 10 km)), latest(rolling_sum(distance, 28 days))
by day
compare none
chart line
display overlay
```
`days` includes rest days. `sessions`, `days_since_run`, `days_since_long_run`,
`days` includes rest days. `sessions`, `days_since_run()`, `days_since_run(distance >= 10 km)`,
`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
distance. Daily rolling windows include the current local day plus the previous
N−1 local days, including history before the query. Whole-run rolling expressions
use elapsed N×24-hour windows. `days_since_run(condition)` accepts one existing
numeric, availability or title condition, evaluated against individual runs before
query filters; `days_since_run()` matches any run. Multiple definitions can appear
in the same query. Missing prior qualifying 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.
@@ -253,9 +256,17 @@ let hr_count = rolling_count(heart_rate, 14 days)
compare previous year
```
Metric functions can appear directly in summaries, filters, sorting and `let`
calculations. For example, `min(best_time(5 km))` selects each month's fastest
5 km effort, while `latest(rolling_sum(distance, 28 days))` selects its latest
trailing distance. The editor obtains function suggestions from the same registry
as the parser. No field or clause is added for a new window or condition.
Rolling functions use complete owner-scoped run history before filters, include
the current run, and exclude the exact lower elapsed-time boundary. They accept
1–365 days and an earlier metric/calculation. Means are unweighted, sums exclude
1–365 days and an earlier metric/calculation. On daily sources, windows use local
calendar days; `rolling_sum(sessions, 7 days)` counts running sessions, while
`rolling_count(distance, 7 days)` counts days with usable distance. Means are unweighted, sums exclude
missing inputs, and counts count usable inputs. Calendar-bucket rolling trends
remain separate operations. `compare previous year` uses the same local-date
interval one year earlier, clamping leap-day boundaries; time charts align by
@@ -316,7 +327,7 @@ Each summary card shows usable-run coverage and its definition.
| Metric | Input unit(s) |
|---|---|
| `distance`, `distance_change`, `rolling_7d_distance`, `rolling_28d_distance` | `km`, `m` |
| `distance`, `distance_change`, `rolling_sum(distance, N days)` | `km`, `m` |
| `duration` | `h`, `min`, `s` |
| `pace` | `/km`, such as `5:30 /km` or `330 /km` |
| `pace_change` | `sec/km`, signed; negative is faster |
@@ -329,13 +340,13 @@ Each summary card shows usable-run coverage and its definition.
| `speed` | `km/h`, `m/s` |
| `gap_since_previous_run` | `days`, `h`, `min` |
| `run_day_streak` | `days` |
| `count`, `rolling_7d_count`, `rolling_28d_count` | `runs` |
| `count`, `rolling_count(distance, N days)` | `runs` |
| `elevation_per_km` | `m/km` |
| `calories` | `kcal` |
| `training_effect` | `score` |
Changes compare with the immediately preceding recorded run before filtering.
Rolling 7/28-day metrics include this run and earlier runs less than 168/672 hours
Rolling N-day expressions include this run and earlier runs less than N×24 hours
old; the exact boundary is excluded. Streaks count consecutive local calendar days
with a run. Multiple runs on one day don't lengthen the streak.
@@ -362,7 +373,8 @@ matching units. Pace arithmetic uses seconds/km, duration uses hours; division o
equal units gives `ratio`. Scalar multiplication keeps the field's unit. Combined
units appear in validation and completion, e.g. `(km/h/bpm)` for efficiency.
Missing inputs, zero divisors and nonfinite results yield missing values.
Expressions cannot call functions, access attributes, index values or execute code.
Expressions can call the registered metric functions described above. They cannot
call arbitrary functions, access attributes, index values or execute code.
## Filters and periods