feat(train): interval plans, synced and sealed, with an editor and templates (ADR 0030, D42)

Train's server gains the synced `plan` table, a sealed payload alone;
the migration `plans` only adds it, its space index and the foreign key
to its sync space, and a person's deletion takes it with their space.

The app keeps plans as `plan` rows sealed for their row: a name, what
they are for, whether a step off target is told, and blocks of steps
repeated, each ending after a time, a distance or a lap tap and aiming
at a pace, speed, heart rate or zone, or the rower's split, watts or
stroke rate. Home's Plans tab lists them, a new one starts from nothing
or from a template (4×4 minutes, Tabata, 10×400 m), the editor changes
steps on a sheet, and a deletion asks first and can be undone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-28 22:35:22 +01:00
commit f406ddcc59
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -1,10 +1,10 @@
# ADR 0030: Halkyon Train, what it does and where its data comes from
- **Status:** decided 27–28 Oct 2026, by the developer (D1–D41 below). The shell (D12)
- **Status:** decided 27–28 Oct 2026, by the developer (D1–D43 below). The shell (D12)
is built; recording (D13–D28) is built on Android, iOS waiting for a Mac; Health
Connect (D29–D31) is built; the Loop's setup and keeping (7a, D34–D36) and its
daily data (7b, D37, D38), its sessions (7c, D39) and its firmware (D10, D40) are
built, and its live heart rate (7d, D41).
built, and its live heart rate (7d, D41); intervals (D42, D43) are being built.
- **Numbering:** 0025 is held by the federation draft (stashed), 0026–0029 by the .NET
rewrite on the local branch `rewrite-dotnet`, abandoned on 27 Oct; Train takes the next
free number so that neither is ever read as this one.
@ -801,6 +801,34 @@ Strava. What was found, 27 Oct:
nor a Loop is there. Not yet tried with a Loop: whether its live rate needs the
band in a mode of its own, and how far the wrist's rate lags a strap's.
- **D42 Interval plans, and who runs them** (recommended, the developer's; 28 Oct): a plan
is a name and a list of steps (warm-up, work, recovery, cool-down) with repeat
blocks; each step ends after a time, after a distance, or with a lap tap, and may
aim at a target: a pace or speed range (from GPS), a heart-rate range in bpm or one
of five zones, and on the rower a split, watts or a stroke rate (over pace and heart
rate alone). The zones are Polar's and most watches': 50–60, 60–70, 70–80, 80–90 and
90–100 % of the profile's highest heart rate, its default from age where unset, as
for the band (over Karvonen's heart-rate reserve, which needs a resting rate). Plans
are Train's synced, sealed `plan` rows, so one made on the desktop reaches the
phone (over the person's folder alone), with an editor and a few templates to start
from (4×4 min, Tabata 8×20/10 s, 10×400 m; over none). The recording service runs
the plan, sent to it as the recording starts: it moves from step to step on its own
moving time and distance, pauses stopping a step's clock, and writes `step` lines
to the recording file, which the app reads (over the open app running it, which
Android may stop with the screen off). Every step change gives a tone, a vibration
and, where the phone has a text-to-speech engine (GrapheneOS ships none; RHVoice or
eSpeak from F-Droid give one), a spoken line naming the step, its length and its
target; a timed step counts its last three seconds down; off target, a short cue at
most every 30 s, switchable per plan (over tones alone, and over no off-target
cues). A step on the rower doesn't set its resistance yet (over setting it through
FTMS's control point): whether the WP 5000 speaks FTMS is still unknown (D8).
- **D43 What an interval workout keeps** (recommended, the developer's; 28 Oct): the
workout keeps the plan's name and its steps as run, a lap each (when, how long, how
far), sealed in its payload; its page lists each step with its time, distance,
average pace or speed and heart rate, on the rower its split and watts, marked where
it held its target, and shades the charts by step (over laps without targets, and
over no trace of the plan).
## Consequences
- Train's sensors are one pattern: open profiles read by the app itself, on the phone;