docs(adr): ADR 0030's D13–D17, how Train records
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
f749acb9ec
commit
ff91f62303
1 changed files with 61 additions and 2 deletions
|
|
@ -1,7 +1,7 @@
|
|||
# ADR 0030: Halkyon Train, what it does and where its data comes from
|
||||
|
||||
- **Status:** decided 27–28 Oct 2026, by the developer (D1–D12 below). Nothing is built
|
||||
yet.
|
||||
- **Status:** decided 27–28 Oct 2026, by the developer (D1–D17 below). The shell (D12)
|
||||
is built; recording (D13–D17) is 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.
|
||||
|
|
@ -225,6 +225,65 @@ Strava. What was found, 27 Oct:
|
|||
- **deployed once recording works** and the developer wants to use it, not as an
|
||||
empty shell first.
|
||||
|
||||
## Recording (28 Oct 2026, the developer's)
|
||||
|
||||
- **D13 Positions are recorded by Train's own platform code** (recommended, over the
|
||||
`geolocator` package and paid background-tracking packages): on Android a foreground
|
||||
service of its own, as Learn's Pomodoro timer has, reading `LocationManager`'s GPS
|
||||
provider as OpenTracks does and appending every fix to a recording file in the app's
|
||||
folder, which the app follows while open and takes in when it opens again; on iOS
|
||||
CoreLocation with background location; both behind one interface (`TrackRecorder`),
|
||||
faked in tests. So a recording goes on with the app swiped away, and nothing of Google
|
||||
Play services is in the app: `geolocator`'s Android part depends on Play services'
|
||||
location library even where its `forceLocationManager` keeps it from being used, a
|
||||
non-free library that F-Droid's main repository refuses, and its positions arrive in
|
||||
Dart, which a swipe ends. The strap and the rower join the same service later.
|
||||
- **D14 A workout and its series are kept apart** (recommended, over one row holding
|
||||
every sample and over sealed GPX or FIT files in the instance's storage): `workout`
|
||||
(type, start, end, name, notes, totals; changed when edited, the last writer winning, as
|
||||
a studyset's payload) and `workout_series` (a chunk of one series, positions, heart rate,
|
||||
strokes, pauses, of up to 10 minutes; written once as the workout is saved, never
|
||||
changed, deleted with its workout, as Learn's review log), every payload sealed (D7)
|
||||
and nothing readable in a column, not the type nor the start. Editing a workout touches
|
||||
one small row, two devices never conflict over samples, and every source is one more
|
||||
kind of series. A chunk's payload is JSON as every payload, each column (time,
|
||||
latitude, longitude, altitude, accuracy, …) a list of whole-number differences from the
|
||||
value before, gzipped before it is sealed, since sealed bytes compress no more. The
|
||||
recording file is the device's own and never synced. UUID v7 ids carry their creation
|
||||
time, which the sync engine's change times tell anyway (D7's list).
|
||||
- **D15 Sealing: the envelope moves into halkyon_app, Train holds its key itself**
|
||||
(recommended, over moving all of Learn's key management and over a copy of the
|
||||
envelope in Train): Learn's `PayloadEnvelope` (a payload sealed for its table, row and
|
||||
column; readable payloads signed by the account; what doesn't open `Locked`) moves
|
||||
unchanged into halkyon_app, Learn importing it from there; Train has one key per person
|
||||
in a synced `content_key` row, its sealed ID saying it is the person's, and a device
|
||||
without the account's keys writes nothing, as in Learn. Learn's tree (private or
|
||||
readable studysets, their records, rewrites) stays Learn's. Publishing a workout later
|
||||
doesn't change it (asked by the developer): a published workout is a readable copy made
|
||||
on the device (D7), which may leave out the heart rate or the first and last few hundred
|
||||
metres, as Strava's privacy zones do, the sealed workout staying as it is; the envelope
|
||||
can sign the copy with the account's key.
|
||||
- **D16 Auto-pause by each activity's best signal, never discarding samples**
|
||||
(recommended, over GPS alone and over manual pauses only): a pause, automatic or by
|
||||
hand, is a marker in a series of its own, and moving time, pace and the totals leave
|
||||
paused stretches out, so a misjudged pause is corrected from the data afterwards.
|
||||
Running and walking stop with the phone's step detector (Android's step sensor, iOS's
|
||||
pedometer; its permission asked for, GPS alone without it), confirmed by GPS; cycling
|
||||
by GPS speed, paused below 3 km/h for 5 s and going on above 5 km/h; rowing by the
|
||||
rower's stroke rate, no stroke for 5 s. On by default for running and cycling, the
|
||||
thresholds adjustable once Train has settings.
|
||||
- **D17 Running, walking, hiking, cycling and indoor rowing first, in this order of
|
||||
parts** (recommended): 5a the envelope moved, Train's key holder, the two models and
|
||||
their migration, the chunk codec and the first synced repository; 5b recording on
|
||||
Android (the service, the file taken in after a swipe, the recording screen,
|
||||
auto-pause, saving); 5c the workouts and a workout's page with its track on a map
|
||||
(D11's `flutter_map` and the instance's tile source brought forward from route
|
||||
planning, the developer's choice: a run without its track looks unfinished), totals,
|
||||
splits and charts; 5d recording on iOS; 5e the heart-rate strap; 5f the WP 5000 over
|
||||
FTMS, from frames recorded with nRF Connect. Health Connect (D6) and the Loop (D3)
|
||||
follow recording. Each type maps onto one of Health Connect's exercise types, and is a
|
||||
name in the sealed payload, so new ones need no migration.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Train's sensors are one pattern: open profiles read by the app itself, on the phone;
|
||||
|
|
|
|||
Loading…
Reference in a new issue