From aa82e0f7faf358ae1a32c90af394d2df24b5db12 Mon Sep 17 00:00:00 2001 From: fy59 Date: Sun, 6 Sep 2026 13:16:17 +0200 Subject: [PATCH] Add profile-aware continuous exercise tracking --- CHANGELOG.md | 17 ++ docs/android.md | 63 +++++ docs/architecture.md | 27 ++ docs/database.md | 54 ++++ docs/exercise_data_model.md | 48 ++++ docs/reviews/profile_aware_continuous.md | 298 +++++++++++++++++++++++ docs/roadmap.md | 40 +++ docs/tests.md | 32 +++ docs/tui.md | 67 +++++ 9 files changed, 646 insertions(+) create mode 100644 docs/reviews/profile_aware_continuous.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ff19c5..0429bc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -153,3 +153,20 @@ Next: - exposed PC -> Android canonical exercise-catalog direction; - kept frozen Trainlog session JSON v1 unchanged. + + +### 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. + diff --git a/docs/android.md b/docs/android.md index f323082..76a4c95 100644 --- a/docs/android.md +++ b/docs/android.md @@ -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. + + +## 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. + diff --git a/docs/architecture.md b/docs/architecture.md index 4607e4a..bc34623 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -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. + + +## 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. + diff --git a/docs/database.md b/docs/database.md index a9990a2..2542271 100644 --- a/docs/database.md +++ b/docs/database.md @@ -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. + + +## 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. + diff --git a/docs/exercise_data_model.md b/docs/exercise_data_model.md index 43580d6..56ba9d1 100644 --- a/docs/exercise_data_model.md +++ b/docs/exercise_data_model.md @@ -193,3 +193,51 @@ data_fields 7. Android uses the same model 8. design session exchange v2 ``` + + +## 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. + diff --git a/docs/reviews/profile_aware_continuous.md b/docs/reviews/profile_aware_continuous.md new file mode 100644 index 0000000..85f36ff --- /dev/null +++ b/docs/reviews/profile_aware_continuous.md @@ -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 +``` diff --git a/docs/roadmap.md b/docs/roadmap.md index f059a44..0c3369d 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -309,3 +309,43 @@ supplemental fields: SPEED_KMH | DISTANCE_KM Existing schema-v2 data migrates conservatively to `SETS`. + + +## 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. + diff --git a/docs/tests.md b/docs/tests.md index 496c02f..8a52065 100644 --- a/docs/tests.md +++ b/docs/tests.md @@ -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. + + +## 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 +``` + diff --git a/docs/tui.md b/docs/tui.md index 22a4118..206333a 100644 --- a/docs/tui.md +++ b/docs/tui.md @@ -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. + + +## 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. +