Add profile-aware continuous exercise tracking

This commit is contained in:
fy59 2026-09-06 13:16:17 +02:00
parent db349c609d
commit aa82e0f7fa
9 changed files with 646 additions and 0 deletions

View file

@ -153,3 +153,20 @@ Next:
- exposed PC -> Android canonical exercise-catalog direction;
- kept frozen Trainlog session JSON v1 unchanged.
<!-- TRAINLOG_SYNC_FINAL_CHANGELOG _END -->
<!-- TRAINLOG_PROFILE_AWARE_CHANGELOG -->
### Profile-aware and continuous exercise tracking
- added set-based versus continuous recording organization;
- added speed and distance supplemental-field metadata;
- added profiled catalog creation API;
- added profile-aware exercise creation in the TUI;
- added inline profiled exercise creation while recording a session;
- migrated SQLite persistence to schema v4;
- added one-to-one continuous activity persistence;
- kept continuous activities out of `performed_sets`;
- added profile-aware session detail loading;
- added continuous duration/speed/distance history display;
- made continuous TUI duration entry explicitly minute-based;
- preserved frozen session JSON v1 unchanged.
<!-- TRAINLOG_PROFILE_AWARE_CHANGELOG _END -->

View file

@ -284,3 +284,66 @@ and no set count.
Creating an exercise directly inside session entry must configure this metadata
before adding it to the catalog/session.
<!-- TRAINLOG_ANDROID_PROFILE_AWARE_ENTRY _END -->
<!-- TRAINLOG_ANDROID_PROFILE_CURSOR -->
## Android implementation cursor
Android is the next implementation area.
The application must share Trainlog's visual language with the TUI.
Theme direction:
```text
dark background
cyan/teal Trainlog accent
yellow active/focus role
green success
red error
```
Launcher icon:
```text
T
```
Only the letter `T`, using Trainlog theme colors.
Required recording sections:
```text
Séance
Exercice
Mensurations
```
Session recording must allow creating a new exercise inline without leaving the
session flow.
Android forms are driven by the same profile metadata as desktop:
```text
recording_mode
tracking_mode
data_fields
```
Examples:
```text
SETS + REPS
sets / reps / load / rest
SETS + DURATION
sets / duration / optional load / rest
CONTINUOUS + DURATION + SPEED_KMH
duration / speed
```
The app must never infer an input form from an exercise display name.
Initial development uses fictitious records. Test/development data is removed
before normal production use starts.
<!-- TRAINLOG_ANDROID_PROFILE_CURSOR _END -->

View file

@ -170,3 +170,30 @@ from USB/MTP backend details.
Current transport foundation supports folder creation, file upload, folder
listing, file download, and verified byte-for-byte roundtrip.
<!-- TRAINLOG_DIRECT_MTP_ARCHITECTURE _END -->
<!-- TRAINLOG_PROFILE_AWARE_ARCHITECTURE -->
## Profile-aware activity architecture
Trainlog has two distinct actual-work persistence paths:
```text
SET-based exercise
session_exercises
|
+--> performed_sets [0..N]
CONTINUOUS exercise
session_exercises
|
+--> continuous_activity [exactly 1]
```
The two paths must remain semantically distinct.
Catalog metadata determines future entry forms.
Session-exercise snapshot metadata determines historical rendering/editing.
The Android client must consume the same catalog profile metadata rather than
maintaining an independent exercise-type system.
<!-- TRAINLOG_PROFILE_AWARE_ARCHITECTURE _END -->

View file

@ -304,3 +304,57 @@ No name-based migration is allowed.
Continuous actual activity data is stored separately from `performed_sets`;
Trainlog will not manufacture a fake one-set workout.
<!-- TRAINLOG_EXERCISE_DATA_MODEL_V1 _END -->
<!-- TRAINLOG_SCHEMA_V4_CONTINUOUS -->
## Schema v4 — continuous exercise persistence
Current database schema:
```text
TRAINLOG_DATABASE_SCHEMA_VERSION = 4
PRAGMA user_version = 4
```
Relevant profile metadata is stored in both:
```text
exercises
session_exercises
```
`session_exercises` snapshots:
```text
recording_mode
data_fields
```
Continuous actual activity data is stored one-to-one in:
```text
continuous_activity
```
Columns:
```text
session_exercise_row_id
duration_seconds
speed_kmh nullable
distance_km nullable
```
For a valid continuous activity:
```text
target_sets NULL
target_reps NULL
target_duration_seconds NULL
load_mode none
rest_seconds 0
target_weight_kg NULL
performed_sets none
```
Schema migration never infers profile information from exercise names.
<!-- TRAINLOG_SCHEMA_V4_CONTINUOUS _END -->

View file

@ -193,3 +193,51 @@ data_fields
7. Android uses the same model
8. design session exchange v2
```
<!-- TRAINLOG_PROFILE_AWARE_IMPLEMENTED -->
## Implemented checkpoint
The profile-aware exercise model is now implemented in the C model, SQLite
persistence and TUI.
Current canonical rules:
```text
recording_mode = SETS | CONTINUOUS
tracking_mode = REPS | DURATION
known data_fields:
SPEED_KMH
DISTANCE_KM
```
Valid model-v1 combinations:
```text
SETS + REPS
SETS + DURATION
CONTINUOUS + DURATION
```
Continuous exercise actual data is persisted as one `continuous_activity`
record rather than a performed-set list.
A continuous activity never manufactures a one-set representation.
The TUI asks continuous duration in **minutes**, converts to seconds, and stores
seconds internally.
Example:
```text
Marche
CONTINUOUS + DURATION + SPEED_KMH
TUI entry:
Durée (minutes)
Vitesse km/h
```
Historical session rows snapshot recording metadata and are not reinterpreted
when catalog metadata later changes.
<!-- TRAINLOG_PROFILE_AWARE_IMPLEMENTED _END -->

View file

@ -0,0 +1,298 @@
# Profile-aware continuous exercise checkpoint
## Status
```text
EXERCISE_DATA_MODEL_V1=IMPLEMENTED
DATABASE_SCHEMA_V4=IMPLEMENTED
PROFILED_CATALOG_API=IMPLEMENTED
PROFILE_AWARE_EXERCISE_CREATION=IMPLEMENTED
CONTINUOUS_ACTIVITY_PERSISTENCE=IMPLEMENTED
CONTINUOUS_ACTIVITY_DETAIL_DISPLAY=IMPLEMENTED
CONTINUOUS_DURATION_MINUTES_UI=IMPLEMENTED
TRAINLOG_FORMAT_V1=FROZEN
ANDROID_APP=NEXT
```
The implementation now distinguishes set-based exercises from continuous
activities.
This checkpoint must be treated as the current architecture by future agents.
## Core model
Exercise catalog metadata:
```text
recording_mode = SETS | CONTINUOUS
tracking_mode = REPS | DURATION
data_fields = bounded supplemental-field bit mask
```
Known supplemental fields:
```text
SPEED_KMH
DISTANCE_KM
```
Initial valid combinations:
```text
SETS + REPS
SETS + DURATION
CONTINUOUS + DURATION
```
`CONTINUOUS + REPS` is invalid.
Behavior is driven by catalog metadata, never by exercise-name heuristics.
## Examples
```text
Presse à cuisses
SETS + REPS
Gainage
SETS + DURATION
Marche
CONTINUOUS + DURATION
SPEED_KMH
Vélo
CONTINUOUS + DURATION
SPEED_KMH | DISTANCE_KM
```
## Historical stability
Catalog metadata controls future entry.
Each `session_exercises` row stores a snapshot of:
```text
recording_mode
data_fields
```
Historical sessions must use their snapshot rather than current catalog
metadata.
Existing rows migrated from older schemas remain `SETS` unless explicitly
changed for future entries.
No migration guesses behavior from names such as `Marche`.
## SQLite schema v4
Current schema version:
```text
PRAGMA user_version = 4
```
Relevant tables:
```text
exercises
sessions
session_exercises
performed_sets
continuous_activity
body_observations
```
`continuous_activity` is one-to-one with a continuous session exercise and
contains:
```text
duration_seconds
speed_kmh nullable
distance_km nullable
```
A continuous activity has:
```text
target_sets = NULL
target_reps = NULL
target_duration_seconds = NULL
load_mode = none
rest_seconds = 0
performed_sets rows = 0
```
Trainlog must not create a fake one-set representation for a continuous
activity.
## TUI behavior
Set-based exercise:
```text
Charge
Séries prévues
Répétitions or duration target
Repos
Séries réellement faites
```
Continuous exercise:
```text
Durée (minutes)
optional configured supplemental fields
```
For `Marche + SPEED_KMH`:
```text
Durée (minutes)
Vitesse km/h
```
A bare duration value in this continuous form is minutes.
Example:
```text
15 -> 15 minutes -> 900 seconds persisted
```
SQLite still stores durations in seconds.
## Session detail behavior
Set-based history uses the existing sets presentation.
Continuous history displays its actual continuous values.
Example:
```text
Exercice 1/1 — Marche
Mode : continu
Durée : 15 min
Vitesse : 7.0 km/h
Réalisé : activité continue
```
It must never display:
```text
0 séries
0 série × 0 s
aucune série réalisée
```
for a valid continuous activity.
## Catalog creation
The lower-level catalog supports explicit profile creation.
Current API:
```text
trainlog_catalog_create_exercise_profiled(...)
```
Legacy exercise creation remains available and means:
```text
recording_mode = SETS
data_fields = 0
```
TUI creation from both:
```text
Exercices page
session inline creation
```
supports selecting continuous mode and supplemental fields.
## Frozen exchange boundary
Trainlog session JSON v1 remains frozen.
Continuous metrics are not forced into v1.
Trainlog must never:
- hide speed/distance in notes;
- synthesize a fake set to make continuous data fit v1;
- silently drop continuous metrics.
A future versioned exchange contract will carry profile-aware session data.
## Android implementation cursor
The next implementation area is the Android client.
Android must use the same model:
```text
recording_mode
tracking_mode
data_fields
```
Required top-level recording sections:
```text
Séance
Exercice
Mensurations
```
Inside session recording, the user must be able to create a new exercise
without leaving the session flow.
Android visual identity must match the TUI:
```text
dark background
Trainlog cyan/teal accent
yellow active/focused border role
green success
red error
```
The Android launcher icon is intentionally minimal:
```text
T
```
using the Trainlog theme colors.
Initial Android development uses fictitious data. The development database is
purged before normal use begins.
## Validation checkpoint
Normal build/test checkpoint after continuous activity work:
```text
15 tests expected
git diff --check clean
```
The important functional manual checks are:
```text
create continuous Marche + speed
record duration in minutes
persist duration as seconds
persist speed in continuous_activity
no performed_sets rows for continuous activity
reopen session detail
display duration + speed as continuous activity
```

View file

@ -309,3 +309,43 @@ supplemental fields: SPEED_KMH | DISTANCE_KM
Existing schema-v2 data migrates conservatively to `SETS`.
<!-- TRAINLOG_EXERCISE_DATA_MODEL_ROADMAP _END -->
<!-- TRAINLOG_PROFILE_AWARE_ROADMAP_FINAL -->
## Current implementation cursor
```text
MTP_TRANSPORT_FOUNDATION=PASS
TUI_SYNC_PAGE=PASS
EXERCISE_DATA_MODEL_V1=PASS
DATABASE_SCHEMA_V4=PASS
PROFILED_CATALOG_API=PASS
PROFILE_AWARE_EXERCISE_CREATION=PASS
CONTINUOUS_ACTIVITY_PERSISTENCE=PASS
CONTINUOUS_ACTIVITY_DETAIL_DISPLAY=PASS
CONTINUOUS_DURATION_MINUTES_UI=PASS
ANDROID_APP=NEXT
TRAINLOG_FORMAT_V1=FROZEN
PROFILE_AWARE_SESSION_EXCHANGE=DESIGN_LATER
```
Next Android slice:
```text
1. Android project scaffold
2. shared Trainlog visual identity
3. launcher icon = themed T
4. home/navigation
5. session recording
6. inline exercise creation
7. standalone exercise creation
8. standalone body measurement recording
9. fictitious local records
10. only then connect exchange/sync
```
Do not revert continuous activities to performed sets.
Do not modify JSON v1 to accommodate continuous metrics.
<!-- TRAINLOG_PROFILE_AWARE_ROADMAP_FINAL _END -->

View file

@ -190,3 +190,35 @@ The hardware probe is intentionally separate from the normal automated test
suite because CI is not expected to have a connected unlocked Android MTP
device.
<!-- TRAINLOG_MTP_VALIDATION _END -->
<!-- TRAINLOG_CONTINUOUS_TEST_CHECKPOINT -->
## Profile-aware / continuous validation
Expected normal test suite after this checkpoint:
```text
15 tests
```
Coverage added around:
```text
exercise profile schema
profiled catalog creation
schema migration
continuous session persistence
continuous session detail loading
```
Manual TUI validation includes:
```text
Marche configured CONTINUOUS + DURATION + SPEED_KMH
entry asks duration minutes + speed
no sets/rest/load prompts
continuous_activity row persisted
performed_sets count remains zero
history reopens as continuous
duration and speed render correctly
```
<!-- TRAINLOG_CONTINUOUS_TEST_CHECKPOINT _END -->

View file

@ -696,3 +696,70 @@ Continuous exercises do not display a set count.
`Marche` will use the continuous form only after its catalog metadata is
explicitly changed; behavior is never inferred from its name.
<!-- TRAINLOG_PROFILE_AWARE_ENTRY _END -->
<!-- TRAINLOG_CONTINUOUS_TUI_IMPLEMENTED -->
## Continuous exercise TUI — implemented
Exercise creation supports explicit organization:
```text
1 séries
2 continu
```
Continuous creation forces duration tracking in model v1 and can enable:
```text
speed
distance
```
The same creation path is available:
```text
from Exercices page
inline while recording a session
```
Session entry is profile-aware.
Set-based exercises retain:
```text
charge
sets
reps/duration
rest
performed sets
```
Continuous exercises display only their relevant fields.
For `Marche + SPEED_KMH`:
```text
Durée (minutes)
Vitesse km/h
```
Bare continuous duration input is interpreted as minutes.
Example:
```text
15 -> 15 min -> 900 seconds in SQLite
```
Session detail is also profile-aware.
Continuous detail example:
```text
Mode : continu
Durée : 15 min
Vitesse : 7.0 km/h
Réalisé : activité continue
```
Do not render set-oriented labels for a valid continuous activity.
<!-- TRAINLOG_CONTINUOUS_TUI_IMPLEMENTED _END -->