From 09f120566df39da5747351eb04e2b197803548b2 Mon Sep 17 00:00:00 2001 From: fy59 Date: Tue, 15 Sep 2026 08:08:36 +0200 Subject: [PATCH] release: prepare Trainlog 0.1.0 baseline --- AGENTS.md | 23 +- CHANGELOG.md | 13 + README.md | 572 ++++++--------- android/README.md | 16 +- ...TrainlogRepositoryDraftInstrumentedTest.kt | 5 + .../ui/SessionDraftUiInstrumentedTest.kt | 5 + .../trainlog/ui/DraftUiTestActivity.kt | 5 + .../com/labfytools/trainlog/MainActivity.kt | 5 + .../trainlog/data/BodyZoneCatalog.kt | 5 + .../trainlog/data/BodyZoneHomeOverview.kt | 5 + .../trainlog/data/DirectStoragePermission.kt | 5 + .../trainlog/data/EquipmentCatalog.kt | 5 + .../trainlog/data/ExchangeSafTree.kt | 5 + .../trainlog/data/ExerciseNameCatalog.kt | 5 + .../trainlog/data/PercentMaxCalculator.kt | 5 + .../trainlog/data/SessionGenerationEngine.kt | 5 + .../trainlog/data/SessionGenerationPolicy.kt | 5 + .../data/SessionGeneratorRepositoryModels.kt | 5 + .../trainlog/data/StatisticsModels.kt | 5 + .../trainlog/data/SyncCatalogInbox.kt | 5 + .../labfytools/trainlog/data/SyncExporter.kt | 5 + .../trainlog/data/SyncRequestOutbox.kt | 5 + .../trainlog/data/TrainingKnowledgeCatalog.kt | 5 + .../trainlog/data/TrainlogRepository.kt | 19 + .../trainlog/data/TrainlogTimestamp.kt | 5 + .../labfytools/trainlog/model/BodyModels.kt | 5 + .../trainlog/model/ExerciseProfile.kt | 5 + .../trainlog/model/SessionModels.kt | 5 + .../labfytools/trainlog/ui/AndroidAppShell.kt | 5 + .../ui/AndroidSpeechRecognitionAdapter.kt | 5 + .../labfytools/trainlog/ui/AppNavigation.kt | 5 + .../com/labfytools/trainlog/ui/BodyScreen.kt | 5 + .../ui/CompletedSessionCorrectionScreen.kt | 5 + .../labfytools/trainlog/ui/ExerciseScreen.kt | 5 + .../trainlog/ui/FeedbackDictation.kt | 5 + .../labfytools/trainlog/ui/FeedbackEditor.kt | 5 + .../labfytools/trainlog/ui/HistoryScreen.kt | 5 + .../com/labfytools/trainlog/ui/HomeScreen.kt | 5 + .../labfytools/trainlog/ui/SectionScreens.kt | 5 + .../trainlog/ui/SessionDetailScreen.kt | 5 + .../trainlog/ui/SessionGeneratorScreen.kt | 5 + .../labfytools/trainlog/ui/SessionScreen.kt | 5 + .../trainlog/ui/StatisticsScreen.kt | 5 + .../com/labfytools/trainlog/ui/SyncScreen.kt | 5 + .../com/labfytools/trainlog/ui/TrainlogApp.kt | 5 + .../trainlog/ui/TrainlogComponents.kt | 5 + .../labfytools/trainlog/ui/TrainlogIcons.kt | 5 + .../trainlog/ui/theme/TrainlogTheme.kt | 5 + .../data/AiSessionDraftRepositoryTest.kt | 5 + .../data/AndroidV10PlanningMigrationTest.kt | 5 + .../AndroidV11ExerciseAliasMigrationTest.kt | 5 + .../AndroidV16AiSessionDraftMigrationTest.kt | 5 + .../BodyZoneHomeOverviewRepositoryTest.kt | 5 + .../labfytools/trainlog/data/BodyZonesTest.kt | 5 + .../data/DirectExchangeStorageTest.kt | 5 + .../trainlog/data/EquipmentCatalogTest.kt | 5 + .../data/ExerciseProfileStateSyncTest.kt | 5 + .../trainlog/data/FeedbackElapsedLabelTest.kt | 5 + .../HistoricalSessionProfileImportTest.kt | 5 + .../trainlog/data/PercentMaxCalculatorTest.kt | 5 + ...lAndroidV12MachineExerciseMigrationTest.kt | 5 + ...AndroidV14FeedbackRevisionMigrationTest.kt | 5 + .../RealAndroidV9BodyZonesMigrationTest.kt | 5 + .../data/SessionGenerationEngineTest.kt | 5 + .../data/SessionGeneratorRepositoryTest.kt | 5 + .../trainlog/data/StatisticsRepositoryTest.kt | 5 + .../data/TrainingExerciseContextTest.kt | 5 + .../data/TrainingFeedbackRepositoryTest.kt | 5 + .../data/TrainingKnowledgeCatalogTest.kt | 5 + .../data/TrainlogRepositoryDraftTest.kt | 5 + .../trainlog/data/TrainlogTimestampTest.kt | 5 + .../trainlog/ui/AiSessionDraftUiWiringTest.kt | 5 + .../ui/AndroidSpeechRecognitionIntentTest.kt | 5 + .../trainlog/ui/AndroidUiRedesignTest.kt | 5 + .../trainlog/ui/AppNavigationStateTest.kt | 5 + .../ui/BodyZoneHomePresentationTest.kt | 5 + .../trainlog/ui/BodyZoneHomeSemanticsTest.kt | 5 + .../ui/DraftFeedbackUiReadbackTest.kt | 5 + .../ui/FeedbackDictationControllerTest.kt | 5 + .../trainlog/ui/FeedbackEditorVoiceUiTest.kt | 5 + .../SessionGeneratorPreviewControllerTest.kt | 5 + .../trainlog/ui/SessionSetRowEditorTest.kt | 5 + .../ui/StatisticsScreenPresentationTest.kt | 5 + .../trainlog/ui/SyncBundlePublicationTest.kt | 5 + .../ui/TrainlogAppNavigationCallbackTest.kt | 5 + docs/README.md | 73 ++ docs/current_state.md | 694 +++--------------- docs/database.md | 2 +- docs/roadmap.md | 552 ++------------ docs/tests.md | 29 +- docs/tui.md | 2 +- tools/export_pc_catalog.py | 3 + tools/import_mobile_export.py | 3 + tools/install_syncd_user.sh | 2 + tui/include/trainlog/app_shell.h | 5 + tui/include/trainlog/body_analytics.h | 5 + tui/include/trainlog/body_zone_catalog.h | 5 + tui/include/trainlog/bodyviz.h | 5 + tui/include/trainlog/catalog.h | 5 + tui/include/trainlog/chart.h | 5 + tui/include/trainlog/database.h | 5 + tui/include/trainlog/duration.h | 5 + tui/include/trainlog/equipment_catalog.h | 5 + tui/include/trainlog/exercise_name_catalog.h | 5 + tui/include/trainlog/id.h | 5 + tui/include/trainlog/measured_max.h | 5 + tui/include/trainlog/model.h | 5 + tui/include/trainlog/mtp.h | 5 + tui/include/trainlog/reps.h | 5 + tui/include/trainlog/session_generation.h | 5 + .../session_generation_policy_internal.h | 5 + tui/include/trainlog/statistics.h | 5 + tui/include/trainlog/status.h | 5 + tui/include/trainlog/sync.h | 5 + tui/include/trainlog/sync_history.h | 5 + tui/include/trainlog/sync_screen_action.h | 5 + tui/include/trainlog/terminal.h | 5 + tui/include/trainlog/theme.h | 5 + tui/include/trainlog/timeutil.h | 5 + tui/include/trainlog/training_context.h | 5 + tui/include/trainlog/training_knowledge.h | 5 + tui/include/trainlog/tui.h | 5 + tui/include/trainlog/usb.h | 5 + tui/src/bodyviz.c | 5 + tui/src/database_internal.h | 5 + tui/src/session_generation.c | 5 + tui/src/timestamp.c | 5 + tui/src/timestamp.h | 5 + tui/src/training_context.c | 5 + tui/src/usb.c | 5 + tui/tests/test_body_zones.c | 5 + tui/tests/test_bodyviz.c | 5 + tui/tests/test_continuous_detail.c | 5 + tui/tests/test_continuous_session.c | 5 + tui/tests/test_equipment_catalog.c | 5 + tui/tests/test_exercise_profile_schema.c | 5 + tui/tests/test_feedback_labels.c | 5 + tui/tests/test_mtp.c | 5 + tui/tests/test_reps.c | 5 + tui/tests/test_session_generation.c | 5 + tui/tests/test_sync_body_zone_wiring.c | 5 + tui/tests/test_sync_direction.c | 5 + tui/tests/test_sync_history.c | 5 + tui/tests/test_sync_screen_action.c | 5 + tui/tests/test_training_context.c | 5 + tui/tests/test_training_knowledge.c | 5 + tui/tests/test_usb.c | 5 + tui/tests/test_variable_sets.c | 5 + tui/tools/mtp_exchange_probe.c | 5 + tui/tools/mtp_mobile_export_probe.c | 5 + tui/tools/mtp_roundtrip_probe.c | 5 + tui/tools/usb_probe.c | 5 + 152 files changed, 1239 insertions(+), 1454 deletions(-) create mode 100644 docs/README.md diff --git a/AGENTS.md b/AGENTS.md index b89d804..c63c867 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -164,7 +164,7 @@ It is not the canonical analytics store. The Android UI is driven by exercise metadata, never by exercise-name heuristics. -Android local SQLite schema v12 retains the exactly-one durable active-session +Android local SQLite schema v17 retains the exactly-one durable active-session draft introduced in v4. Every meaningful draft/form mutation is persisted by the repository. Back, backgrounding and process death never delete the draft. Home offers explicit @@ -177,7 +177,9 @@ Android schema v11 additionally stores optional planning metadata separately from actual occurrence data after the additive v10 -> v11 migration. Existing rows retain `load_mode=none`, zero rest and NULL targets. Android v12 adds the durable flattened exercise-alias mapping used to resolve retired creator IDs. -Desktop schema v12 owns the same alias compatibility boundary. The active +Desktop schema v12 owns the same alias compatibility boundary. Later additive +desktop migrations reach v18 and Android migrations reach v17 without changing +that identity contract. The active completed-session exchange is the separate strict `trainlog-mobile-export` V3; V1/V2 remain readable and `TRAINLOG_FORMAT_V1` remains unchanged. @@ -230,9 +232,11 @@ Desktop SQLite schema is versioned with: PRAGMA user_version; ``` -The current desktop schema is v12. Schema v9 added an occurrence-owned explicit -maximum result; v10/v11 added body-zone and planning metadata, and v12 adds -durable flattened exercise aliases. None changes `TRAINLOG_FORMAT_V1`. +The current desktop schema is v18. Schema v9 added an occurrence-owned explicit +maximum result; v10/v11 added body-zone and planning metadata; v12 added durable +flattened exercise aliases; v13-v18 add machine metadata, feedback and +revisions, occurrence tracking snapshots, causal profile state, and AI proposal +storage/publication state. None changes `TRAINLOG_FORMAT_V1`. Every incompatible schema evolution requires an explicit migration and regression coverage. @@ -276,6 +280,11 @@ Canonical documents: - `docs/roadmap.md`; - `CHANGELOG.md`. +`README.md` is the concise repository entry point. `docs/README.md` is the +canonical documentation index. `docs/current_state.md` owns current implemented +status; `docs/roadmap.md` owns future work. Design and review records are +historical evidence and must not override those current owners. + Checkpoint history belongs in Git history and `docs/reviews`; canonical documents describe the current state rather than accumulating obsolete `NEXT` sections. @@ -302,6 +311,10 @@ cd android JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./gradlew assembleDebug ``` +Run Android unit and instrumented automation on the host/emulator. The primary +personal phone is reserved for manual, non-destructive install and sync smoke +tests; do not run `connectedDebugAndroidTest` on it. + Run ASan/UBSan at meaningful C implementation checkpoints. Hardware-dependent MTP tests remain explicit manual validations and are not diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d178f9..fe18e0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +- Documented stable-release distribution through GitHub Releases, including + prebuilt Android and architecture-specific dynamically linked Linux assets, + SHA-256 verification, runtime/build/optional dependencies, and the release + signing and exact-tag requirements. No v0.1.0 release is claimed until a + signed APK and authenticated GitHub publication path are available. + +- Completed `TRAINLOG_FULL_REPOSITORY_DOCUMENTATION_AUDIT_V2`: added the + canonical documentation index, made README a concise entry point, separated + current state from future roadmap ownership, corrected current schema and + validation descriptions, and added concise English ownership headers across + previously undocumented C, Kotlin, Python, and shell sources. The audit + changes documentation comments only and introduces no functional behavior. + - Fixed fresh Android database body-zone reconstruction by applying the PC-published body-zone companion immediately after catalog, flattened aliases and strict profile-state, before fallible downstream session, equipment, AI diff --git a/README.md b/README.md index c9dcef1..5d4ec77 100644 --- a/README.md +++ b/README.md @@ -1,405 +1,249 @@ # Trainlog -Trainlog is a local-first workout and body-tracking system with two user -interfaces: +Trainlog is a local-first workout and body-data system. Its native Android app +is the lightweight field companion for fast capture and glanceable summaries; +its C17/Notcurses desktop TUI is the detailed surface for correction, +catalogue management, analytics, graphs, and long-term follow-up. -- a native Android application optimized for fast data entry during training; -- a C17/Notcurses TUI used for durable history, editing, visualization, - statistics, and synchronization. +Android and desktop each own a local SQLite database. The desktop database is +the canonical long-term history. Trainlog synchronizes versioned JSON artifacts +over direct MTP; it never copies SQLite database files between devices. -The desktop SQLite database is the canonical long-term history. Android keeps -its own local SQLite database so recording remains usable independently from the -desktop. +## Product split -## Current status +| Surface | Primary responsibility | +|---|---| +| Android | Capture sets, repetitions, loads, durations, continuous activities, feedback, J+1 follow-ups, body measurements, active drafts, and AI proposals; trigger sync; show quick summaries. | +| Desktop TUI | Consult and correct canonical history; manage exercises and equipment; analyze body data, MAX results, training statistics, body zones, calendar periods, and longitudinal graphs. | -```text -TRAINLOG_FORMAT_V1=FROZEN -TRAINLOG_AI_SESSION_DRAFT_V1=VALIDATION_PENDING +In short: **Android captures and summarizes. The TUI analyzes and tracks over +time.** Android intentionally remains lightweight for analytics. -DESKTOP_SCHEMA_V11=PASS -ANDROID_LOCAL_WORKFLOWS=PASS -ANDROID_LOCAL_DATABASE_V10=PASS -ANDROID_LOCAL_DATABASE_V11=PASS -ANDROID_SESSION_DRAFT_V1=PASS -EXERCISE_EDIT_V1=PASS -ANDROID_BANNER_PARITY_V1=PASS +## Release links -VARIABLE_REPETITION_SETS=PASS -CONTINUOUS_ACTIVITY_TRACKING=PASS +- [Download the latest release](https://github.com/labfytools/trainlog/releases/latest) +- [Documentation](docs/README.md) +- [Changelog](CHANGELOG.md) -DIRECT_MTP_TRANSPORT=PASS -COMMON_SYNC_ENGINE=PASS -TRAINLOG_SYNCD=PASS -ANDROID_TRIGGERED_SYNC=PASS -ANDROID_SYNC_RECEIPT=PASS -BIDIRECTIONAL_SYNC_V1=PASS -MULTI_OCCURRENCE_SESSION_V2=PASS -EQUIPMENT_ASSOCIATIONS_V2=PASS -EQUIPMENT_DEFINITIONS_V1=PASS -EXERCISE_RECONCILIATION_V2=PASS -EXPLICIT_MAX_RESULTS_V1=PASS -BODY_ZONES_V1=PASS -BODY_ZONE_SYNC_V1=PASS -BODY_ZONES_DESKTOP_REAL_MIGRATION=PASS -BODY_ZONES_ANDROID_DEVICE_VALIDATION=PASS +## Installation -DESKTOP_TESTS=58/58 PASS (latest validated checkpoint) -ANDROID_BUILD=PASS +### Download a prebuilt release -TRAINING_KNOWLEDGE_V1=PASS -SESSION_GENERATOR_V1=PASS -APP_SHELL_V1=IMPLEMENTED_AWAITING_VISUAL_REVIEW_2 -``` +Stable releases publish an Android APK, an x86-64 Linux TUI executable, and a +`SHA256SUMS` file on [GitHub Releases](https://github.com/labfytools/trainlog/releases). +Verify the downloaded binary against `SHA256SUMS` before installing it. -`APP_SHELL_V1` provides the shared seven-section application shell on both -platforms: **Accueil**, **Séances**, **Exercices**, -**Statistiques**, **Synchronisation**, and **Paramètres**. Completed history -and the existing generator now live under **Séances**; existing body and MAX -views live under **Statistiques**. It records no new statistics, schema, or -synchronization protocol. Automated review repairs are recorded, but the -status remains awaiting human visual/accessibility review; see -[the APP_SHELL_V1 review record](docs/reviews/app_shell_v1.md). - -`TRAINING_KNOWLEDGE_V1` has passed its bounded scientific review, independent -temporal delta review, final engineering audit, repair verification, and final -executable validation. Its C and -Android occurrence pages and latest-MAX context share the settled exact-instant -ordering and source-text cursor contract. The independent temporal review -returned PASS with no findings. The initial full-tranche audit's four findings -were resolved by one bounded repair chain and independently verified. Fresh -validation passed: strict build, 56 Meson tests, Python knowledge/temporal -tests, validators, headers, sanitizers, 12-form temporal probes, Android 56 -tests with one known fixture skip, and Java 17 debug assembly. -The [temporal correction record](docs/reviews/training_knowledge_v1_temporal_contract.md) -defines the accepted grammar, regression evidence and remaining review boundary. - -## Architecture - -```text - Android application - local SQLite store - | - automatic mobile snapshot - | - v - Documents/Trainlog on Android storage - | - | direct MTP / libmtp - v - trainlog_sync_run() - / \ - / \ - Android -> PC PC -> Android - snapshot import catalog publish - \ / - \ / - sync receipt - | - v - Android - -Desktop TUI --------------------+ - | | - +-- same sync engine -------+ - | - v -desktop SQLite -canonical long-term history -``` - -No SQLite database file is copied between devices. The desktop does not require -a GVFS/FUSE mount of the phone. - -## Exercise model - -Trainlog does not infer behavior from exercise names. - -```text -recording_mode = SETS | CONTINUOUS -tracking_mode = REPS | DURATION -data_fields = SPEED_KMH | DISTANCE_KM -``` - -Valid model-v1 combinations are: - -```text -SETS + REPS -SETS + DURATION -CONTINUOUS + DURATION -``` - -Actual repetition sets are stored independently. The Notcurses desktop flow -collects planning only, then creates actual work in an ordered table: the user -explicitly adds every row and enters its actual repetitions (or duration) and -optional load. It does not accept compact performed-repetition input; normal -set sessions cannot finish with zero actual rows. - -A session may contain several ordered occurrences of the same catalogue -exercise. Each occurrence has a stable `entry_id`, distinct from the stable -`exercise_id` of the catalogue item. Equipment selection belongs to that -occurrence, as do its actual per-set loads. `external` records an applied or -machine-displayed load; `assistance` records assistance and is not interpreted -as increasing strength. An actual load is either absent or finite and -non-negative, so an explicit zero remains distinct from no recorded load; -planned targets remain strictly positive and are never substituted for actuals. - -In a `max_test` session, an occurrence may instead own one explicit positive -`max_weight_kg`. This result has no performed set, repetitions, or target-set -count. Its identity remains the movement's `exercise_id` plus the occurrence's -`entry_id`; optional equipment is context and never owns a shared maximum. - -During V2 synchronization, a different-ID normalized-name collision is merged -only when recording/tracking modes match, every other known invariant is -compatible, and one `data_fields` mask contains the other. The desktop identity -is retained as canonical, the bit-mask union preserves the richer capability, -and historical occurrence snapshots remain unchanged; absent optional values -stay absent. Incomparable profiles remain explicit conflicts. Name equality -alone is never sufficient. - -Exercise body zones are independent metadata sourced from the single canonical -[`catalog/body-zones-v1.json`](catalog/body-zones-v1.json) manifest. An exercise -may have one primary assignable zone and several distinct secondary zones. -Secondary relations require that primary; the explicit unclassified state has -no relations at all. -`upper_body` and `lower_body` are hierarchy groups used for display and -descendant-aware filtering; they are never duplicated as stored relations. -`full_body` and `core` remain autonomous. Historical exercises without an -objective stable-ID mapping remain visible as **Non renseignés**. - -## Repository layout - -```text -android/ native Kotlin/Compose Android client -tui/ C17 Notcurses desktop application and core -docs/ canonical project documentation -format/ frozen Trainlog JSON v1 schema material -catalog/ canonical versioned equipment and body-zone manifests -examples/ valid frozen-format examples -tests/ fixtures and cross-component tests -tools/ validators, import/export helpers, sync daemon tooling -``` - -## Desktop build and validation +The Linux TUI artifact is architecture-specific and dynamically linked. It is +not a universally portable Linux binary: the host must provide compatible +runtime libraries listed under [Dependencies](#dependencies). ```bash -meson setup --reconfigure build +chmod +x trainlog-tui-linux-x86_64-v0.1.0 +./trainlog-tui-linux-x86_64-v0.1.0 +``` + +The executable can remain in the download directory. Moving it into a directory +on `PATH`, such as a user-managed `~/.local/bin`, is optional. + +For Android, download the release APK, allow installation from the browser or +file manager when Android requests it, and install the package. Android 8.0 +(API 26) or later is required. Grant Trainlog all-files access only when direct +`Documents/Trainlog` synchronization is needed. Desktop synchronization also +requires the Linux side and its MTP dependencies to be installed and configured. + +Android and the TUI in one GitHub Release share the same Trainlog product +version. Database schemas and JSON protocol versions are independent. + +### Build from source + +Desktop: + +```bash +meson setup build meson compile -C build meson test -C build --print-errorlogs - -python tools/validate_json.py -python tools/validate_import_contract.py - -git diff --check ``` -## Local history export for external analysis - -Create the read-only `TRAINLOG_AI_EXPORT_V1` artifact in the current directory: - -```bash -python tools/export_ai_history.py --database ~/.local/share/trainlog/trainlog.db -``` - -The default output is `trainlog_ai_export_v1.json`. It is ignored by Git -because it contains user data. After every completely successful desktop sync, -the shared sync engine regenerates this artifact and asks the external desktop -`rclone` command to copy it to -`TrainLog Gdrive:Trainlog/AI/trainlog_ai_export_v1.json`. Export or Drive -failure is reported without changing the successful Trainlog sync result. -Android never runs `rclone`, and its configuration/OAuth credentials remain in -the user's normal `~/.config/rclone/` location outside this repository and the -APK. See [the exchange documentation](docs/exchange_format.md) for the -versioned raw-data contract and feedback ownership rules. - -## AI session-draft exchange - -`TRAINLOG_AI_SESSION_DRAFT_V1` is a separate, strict proposal exchange; it -does not alter `TRAINLOG_FORMAT_V1`, the mobile export, or the existing -read-only `TRAINLOG_AI_EXPORT_V1` history export. An external producer places -one source object at -`TrainLog Gdrive:Trainlog/AI/inbox/trainlog_ai_session_draft_v1.json`. The desktop -fetches it during synchronization, validates and imports it transactionally, -then copies those exact fetched bytes after that commit to -`TrainLog Gdrive:Trainlog/AI/archive/` under its stable `aid_` -identity. The mutable inbox object is never moved or deleted: its logical -replay is idempotent, and an archive failure is visible and retryable without -undoing the committed import. - -The desktop then publishes the distinct PC-to-Android companion -`trainlog-ai-session-drafts-v1.json` in `Documents/Trainlog`. Android keeps its -pending proposals as a collection, separate from its exactly-one active -capture draft. Starting one proposal copies targets only into that singleton -draft and atomically tombstones the proposal; deleting a proposal also leaves -a tombstone, so replay cannot recreate it. No proposal creates performed work, -history, MAX, or feedback. - -The source and companion are bounded and strict: UUIDv4 `aid_` identities, -nonempty trimmed text when supplied (title 120 and draft notes 2,000 characters; -entries have no notes), at most 64 ordered entries, target sets 1..99, target -reps 1..999, and at most 256 unpublished drafts per deterministic publication. -Successful MTP publication advances the durable batch cursor; failure retries -the same batch. Only `SETS` plans are -allowed; the selected exercise's REPS-or-DURATION profile determines the one -valid target metric. The final real Google Drive and Android-triggered -bidirectional smoke test remains manual, so this checkpoint is documented as -`VALIDATION_PENDING`, not PASS. See [AI draft exchange](docs/exchange_format.md). - -## Android build - -Android keeps one durable in-progress workout in its local SQLite database. -Home offers **Reprendre la séance en cours** after navigation, app switching, -Activity recreation, process death or force-stop/relaunch. Added exercises and -raw unfinished form text are retained. Removing an exercise affects only the -draft; abandoning the draft requires confirmation. Final save atomically -creates completed history and clears the draft. Drafts never enter mobile -export or desktop synchronization as completed sessions. - -Schema migrations are additive and preserve existing capture data. See -[Android behavior](docs/android.md) and [validation](docs/tests.md). - -The current Android schema is v17. Its additive v4 -> v17 chain adds the shared -equipment catalogue, per-occurrence equipment links, durable occurrence -identities, custom-equipment definition support, explicit MAX results and -stable-source Test max resumption, then direct primary/secondary body-zone -relations and occurrence planning, without recreating completed history or -discarding the active draft. The additive v11 -> v12 migration stores flattened -exercise aliases used to resolve retired IDs during synchronization. - -Exercises can be renamed in place from Android. The `ex_` identity is -unchanged; completed history, an active draft, and synchronization therefore -continue to resolve the same logical exercise. Referenced profiles are locked; -only unreferenced catalog exercises may change their recording/tracking profile. - -The local Android SDK is intentionally not committed. Configure it with either -`ANDROID_HOME` or `android/local.properties`. - -Example: +Android: ```bash cd android - -printf 'sdk.dir=%s\n' "$HOME/Android/Sdk" > local.properties - -JAVA_HOME=/usr/lib/jvm/java-17-openjdk \ -./gradlew testDebugUnitTest assembleDebug +JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./gradlew test +JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./gradlew assembleRelease ``` -## Android-triggered synchronization +`assembleRelease` produces a distributable stable APK only when release signing +is configured by the release operator. The repository does not contain signing +credentials and does not silently generate them. -Launch the desktop TUI from this built checkout with: +## Dependencies -```bash -cd /home/fy59/Documents/trainlog -./build/tui/trainlog -``` +### Linux runtime dependencies -The desktop database is `$XDG_DATA_HOME/trainlog/trainlog.db`, or -`~/.local/share/trainlog/trainlog.db` when `XDG_DATA_HOME` is unset. +The published x86-64 TUI is dynamically linked. The current build directly +requires compatible versions of: -Build the desktop first, then install the user service: +- glibc and the GCC support runtime; +- SQLite 3; +- libuuid; +- utf8proc; +- libudev; +- libmtp; +- Notcurses Core; +- the standard math library. -```bash -bash tools/install_syncd_user.sh -``` +Distribution packages may pull additional transitive libraries, including +libusb, ncursesw, unistring, gpm, libgcrypt, libgpg-error, and libdeflate. +Package names and ABI versions vary by distribution; inspect the release's +`ldd` evidence and install packages from the target distribution rather than +assuming one universal package command. -Check it with: +### Optional runtime and integration dependencies -```bash -systemctl --user is-active trainlog-syncd.service -tail -f ~/.local/state/trainlog/syncd.log -``` +- Android is optional when using the desktop TUI alone. USB/MTP synchronization + requires the Android companion, libudev, libmtp, and an unlocked connected + device. +- `trainlog-syncd` installation expects a systemd user session. Manual TUI + synchronization does not require the user service. +- `rclone` is required only for automatic AI history upload and Drive + inbox/archive workflows. Core capture, local history, analytics, and direct + MTP synchronization work without `rclone`. -On Android: +### Build dependencies -```text -Sync --> Synchroniser maintenant -``` +Desktop builds require: -The request is consumed by `trainlog-syncd`, the shared bidirectional engine -runs, a receipt is returned to Android, and the PC catalog is applied locally. -The active completed-session exchange is V3 and preserves occurrence -`entry_id`, per-set weights and equipment associations. Frozen V1 artifacts -remain readable as legacy artifacts; they are not silently redefined as V2. -Exercise-zone metadata travels separately in the sole bidirectional -`trainlog-exercise-body-zones-v1.json` companion. +- Meson and Ninja; +- a C17 compiler toolchain; +- `pkg-config`; +- Notcurses Core development headers; +- SQLite, libuuid, utf8proc, libudev, and libmtp development headers; +- Python 3 for generated sources, validators, import/export helpers, and tests. + +Android builds require JDK 17, an Android SDK supporting the configured API +levels, and the Gradle wrapper committed in this repository. People installing +the APK do not need Java, Gradle, or the Android SDK. ## Documentation -- `docs/current_state.md`: compact canonical implementation snapshot; -- `docs/architecture.md`: component and ownership boundaries; -- `docs/exercise_data_model.md`: exercise semantics; -- `docs/database.md`: desktop SQLite schema and migrations; -- `docs/android.md`: Android behavior; -- `docs/tui.md`: desktop TUI behavior; -- `docs/sync_exchange.md`: MTP synchronization artifacts and protocol; -- `docs/exchange_format.md`: frozen Trainlog JSON v1 contract; -- `docs/tests.md`: validation strategy; -- `docs/roadmap.md`: completed gates and future cursor; -- `docs/domain/knowledge_system.md`: read-only scientific knowledge system, - runtime-context boundary and documented future planning pipeline; -- `AGENTS.md`: development contract. +| Topic | Document | Purpose | +|---|---|---| +| Documentation map | [docs/README.md](docs/README.md) | Canonical index and ownership map. | +| Current state | [docs/current_state.md](docs/current_state.md) | Current implemented schemas, capabilities, validation, and limitations. | +| Architecture | [docs/architecture.md](docs/architecture.md) | Component, storage, process, and ownership boundaries. | +| Android | [docs/android.md](docs/android.md) | Field-companion behavior and local persistence. | +| Desktop TUI | [docs/tui.md](docs/tui.md) | Notcurses workflows, correction, and analytics. | +| Database | [docs/database.md](docs/database.md) | Desktop persistence schema and migration contracts. | +| Exercise model | [docs/exercise_data_model.md](docs/exercise_data_model.md) | Exercise, occurrence, load, and MAX semantics. | +| Synchronization | [docs/sync_exchange.md](docs/sync_exchange.md) | Active MTP flow and companion artifacts. | +| Exchange formats | [docs/exchange_format.md](docs/exchange_format.md) | Frozen and separately versioned JSON contracts. | +| Training feedback | [docs/training_feedback.md](docs/training_feedback.md) | Immediate feedback, revisions, and J+1 follow-ups. | +| Tests | [docs/tests.md](docs/tests.md) | Durable validation commands and coverage strategy. | +| Roadmap | [docs/roadmap.md](docs/roadmap.md) | Current cursor and future work only. | +| Development contract | [AGENTS.md](AGENTS.md) | Repository invariants and contribution rules. | +| Change history | [CHANGELOG.md](CHANGELOG.md) | Chronological implementation history. | + +## Architecture overview + +```text +Android local SQLite + | + | versioned JSON snapshots and requests + v +Documents/Trainlog on Android storage + | + | direct MTP / libmtp + v +trainlog_sync_run() <---- trainlog-syncd or desktop TUI + | + +---- import Android snapshot into desktop SQLite + +---- publish desktop catalog companions to Android + +---- write a synchronization receipt + +desktop SQLite = canonical long-term history +``` + +The optional desktop AI flow exports read-only history and exchanges session +proposals through Google Drive via the external `rclone` process. Android does +not contain cloud credentials and does not run `rclone`. + +## Current status + +As of 2026-09-15: + +- `TRAINLOG_FORMAT_V1=PASS/FROZEN`; +- desktop SQLite schema v18 and Android SQLite schema v17; +- Notcurses is the only active desktop terminal backend; +- direct storage is `/storage/emulated/0/Documents/Trainlog` under Android's + all-files access setting; +- mobile export V3 is active; V1/V2 remain readable legacy inputs; +- `STATS_V1=IMPLEMENTED`, `TRAINING_KNOWLEDGE_V1=PASS`, and + `SESSION_GENERATOR_V1=PASS` (the generator is hidden pending V2); +- `APP_SHELL_V1=IMPLEMENTED_AWAITING_VISUAL_REVIEW_2`; +- `TRAINLOG_AI_SESSION_DRAFT_V1=VALIDATION_PENDING` pending a real Drive plus + Android-triggered bidirectional smoke test. + +The latest executable result belongs in +[current state](docs/current_state.md), not in multiple README narratives. + +## Desktop development quick start + +Requirements include Meson, Ninja, SQLite3, utf8proc, libuuid, libudev, +libmtp, and Notcurses. + +```bash +meson setup build +meson compile -C build +meson test -C build --print-errorlogs +./build/tui/trainlog +``` + +The database path is `$XDG_DATA_HOME/trainlog/trainlog.db`, or +`~/.local/share/trainlog/trainlog.db` when `XDG_DATA_HOME` is unset. + +## Android development quick start + +Use Java 17 and provide the Android SDK through `ANDROID_HOME` or the untracked +`android/local.properties` file. + +```bash +cd android +JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./gradlew test +JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./gradlew assembleDebug +``` + +Instrumented tests belong on an emulator. Do not run +`connectedDebugAndroidTest` on the primary personal phone. + +## Synchronization quick start + +```bash +meson compile -C build +bash tools/install_syncd_user.sh +systemctl --user is-active trainlog-syncd.service +``` + +On Android, grant all-files access for the fixed `Documents/Trainlog` +directory, then use **Synchronisation → Synchroniser maintenant**. Hardware MTP +validation requires an unlocked connected device and remains an explicit manual +check. ## Development principles -- local-first; -- no mandatory cloud account; -- user-owned data; -- versioned persistent and exchange formats; -- stable identities; -- idempotent synchronization; -- no fake data representation to force incompatible models together; -- strict compiler warnings; -- documentation and tests are part of feature completion. +- Preserve frozen, versioned compatibility boundaries. +- Use stable IDs; display names are not identities. +- Keep performed work separate from plans and continuous activity separate + from fake sets. +- Keep Android capture, desktop analytics, persistence, transport, and + rendering responsibilities distinct. +- Prefer explicit failure to silent data loss or corruption. +- Treat migrations, idempotence, tests, and documentation as part of feature + completion. +- Keep scientific catalogs separate from runtime user data and preserve stated + uncertainty. -## Measured max +## License and project notes -Explicit `max_test` sessions are the only source of measured maxima. Schema v9 -stores each new weight result in a one-to-one `max_results` row; it no longer -encodes a maximum as a synthetic `1 × 1` set. - -Ordinary training best sets remain ordinary performance even when they exceed a -previous max-test result. - -The desktop exercise catalog exposes a separate measured-max view with current -result, same-mode record, test history, a dedicated graph, and 60/70/80/90% -working loads for external resistance. Working loads are rounded to a selectable -practical increment and are not calculated for assistance. - -Android and the TUI expose a dedicated `Test max` form containing exercise, -optional equipment, and `Poids max (kg)`. Android can reopen an existing Test -max and atomically replace its ordered entries while preserving the original -session and occurrence identities. - -```text -MEASURED_MAX_V1=PASS -WORKING_LOAD_PERCENTAGES=PASS -ANDROID_MAX_TEST_SESSION=PASS -EXPLICIT_MAX_RESULTS_V1=PASS -``` - -## Body analytics - -Body analytics are desktop-only. Android remains a capture client. - -The TUI derives descriptive ratios, left/right asymmetry, and an optional -circumference-based body-fat estimate from real body observations. - -The estimate requires a local desktop-only analytics profile containing the -formula branch and height. Estimated fat mass and lean mass are calculated only -when a real body weight is present. - -Estimated values are never persisted as direct measurements. - -```text -BODY_ANALYTICS_V1=PASS -BODY_COMPOSITION_ESTIMATE=PASS -BODY_PROPORTION_RATIOS=PASS -BODY_SYMMETRY_ANALYTICS=PASS -DESKTOP_TESTS=39/39 PASS -``` - -`SESSION_GENERATOR_V1` remains implemented but is hidden from normal Android -and TUI navigation pending V2. `catalog/exercise-names-v1.json` owns mapped -exercise display metadata across sync while preserving stable IDs and history. +See [LICENSE](LICENSE). Forgejo is the primary repository; GitHub is a mirror. +Repository layout, detailed contracts, and historical review records are linked +from [docs/README.md](docs/README.md). diff --git a/android/README.md b/android/README.md index 47ffb0f..20c5a98 100644 --- a/android/README.md +++ b/android/README.md @@ -11,8 +11,10 @@ ANDROID_INLINE_EXERCISE_ROUTE=IMPLEMENTED ANDROID_EXERCISE_SHELL=IMPLEMENTED ANDROID_BODY_SHELL=IMPLEMENTED -LOCAL_PERSISTENCE=NEXT -MTP_SYNC=AFTER_LOCAL_WORKFLOW +LOCAL_PERSISTENCE=IMPLEMENTED +DIRECT_STORAGE=IMPLEMENTED +MTP_SYNC=IMPLEMENTED +ANDROID_SCHEMA=17 ``` ## Visual contract @@ -68,10 +70,12 @@ minSdk 26 JDK 17 ``` -A Gradle wrapper is intentionally not committed by the scaffold script unless -it can be generated locally. From this directory: +The committed Gradle wrapper is the canonical entry point. From this directory: ```bash -gradle wrapper --gradle-version 9.6.0 -./gradlew assembleDebug +JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./gradlew test +JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./gradlew assembleDebug ``` + +Instrumented tests run on an emulator. Do not run +`connectedDebugAndroidTest` on the primary personal phone. diff --git a/android/app/src/androidTest/java/com/labfytools/trainlog/data/TrainlogRepositoryDraftInstrumentedTest.kt b/android/app/src/androidTest/java/com/labfytools/trainlog/data/TrainlogRepositoryDraftInstrumentedTest.kt index d314fd3..944bb7b 100644 --- a/android/app/src/androidTest/java/com/labfytools/trainlog/data/TrainlogRepositoryDraftInstrumentedTest.kt +++ b/android/app/src/androidTest/java/com/labfytools/trainlog/data/TrainlogRepositoryDraftInstrumentedTest.kt @@ -1,3 +1,8 @@ +/* + * Android TrainlogRepositoryDraftInstrumentedTest. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/androidTest/java/com/labfytools/trainlog/ui/SessionDraftUiInstrumentedTest.kt b/android/app/src/androidTest/java/com/labfytools/trainlog/ui/SessionDraftUiInstrumentedTest.kt index 8779c17..648ed70 100644 --- a/android/app/src/androidTest/java/com/labfytools/trainlog/ui/SessionDraftUiInstrumentedTest.kt +++ b/android/app/src/androidTest/java/com/labfytools/trainlog/ui/SessionDraftUiInstrumentedTest.kt @@ -1,3 +1,8 @@ +/* + * Android SessionDraftUiInstrumentedTest. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import android.content.Context diff --git a/android/app/src/debug/java/com/labfytools/trainlog/ui/DraftUiTestActivity.kt b/android/app/src/debug/java/com/labfytools/trainlog/ui/DraftUiTestActivity.kt index 69fb1da..b51e79e 100644 --- a/android/app/src/debug/java/com/labfytools/trainlog/ui/DraftUiTestActivity.kt +++ b/android/app/src/debug/java/com/labfytools/trainlog/ui/DraftUiTestActivity.kt @@ -1,3 +1,8 @@ +/* + * Debug-only DraftUiTestActivity. + * + * Supports isolated Android UI validation and does not participate in release behavior. + */ package com.labfytools.trainlog.ui import android.os.Bundle diff --git a/android/app/src/main/java/com/labfytools/trainlog/MainActivity.kt b/android/app/src/main/java/com/labfytools/trainlog/MainActivity.kt index 132024c..ef3bd09 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/MainActivity.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/MainActivity.kt @@ -1,3 +1,8 @@ +/* + * Android MainActivity. + * + * Connects the application lifecycle to Trainlog UI without owning domain or persistence behavior. + */ package com.labfytools.trainlog import android.os.Bundle diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/BodyZoneCatalog.kt b/android/app/src/main/java/com/labfytools/trainlog/data/BodyZoneCatalog.kt index 14aa68c..ee2ab5b 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/BodyZoneCatalog.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/BodyZoneCatalog.kt @@ -1,3 +1,8 @@ +/* + * Android BodyZoneCatalog. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/BodyZoneHomeOverview.kt b/android/app/src/main/java/com/labfytools/trainlog/data/BodyZoneHomeOverview.kt index fb54ac5..2387ef6 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/BodyZoneHomeOverview.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/BodyZoneHomeOverview.kt @@ -1,3 +1,8 @@ +/* + * Android BodyZoneHomeOverview. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data enum class BodyZoneHomeState(val label: String) { diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/DirectStoragePermission.kt b/android/app/src/main/java/com/labfytools/trainlog/data/DirectStoragePermission.kt index d7b2a95..16403d3 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/DirectStoragePermission.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/DirectStoragePermission.kt @@ -1,3 +1,8 @@ +/* + * Android DirectStoragePermission. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/EquipmentCatalog.kt b/android/app/src/main/java/com/labfytools/trainlog/data/EquipmentCatalog.kt index bb74329..ebd8614 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/EquipmentCatalog.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/EquipmentCatalog.kt @@ -1,3 +1,8 @@ +/* + * Android EquipmentCatalog. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/ExchangeSafTree.kt b/android/app/src/main/java/com/labfytools/trainlog/data/ExchangeSafTree.kt index c00ea41..20a88da 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/ExchangeSafTree.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/ExchangeSafTree.kt @@ -1,3 +1,8 @@ +/* + * Android ExchangeSafTree. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/ExerciseNameCatalog.kt b/android/app/src/main/java/com/labfytools/trainlog/data/ExerciseNameCatalog.kt index 7fe831d..eaf0a9e 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/ExerciseNameCatalog.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/ExerciseNameCatalog.kt @@ -1,3 +1,8 @@ +/* + * Android ExerciseNameCatalog. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/PercentMaxCalculator.kt b/android/app/src/main/java/com/labfytools/trainlog/data/PercentMaxCalculator.kt index b3ee080..c7403a7 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/PercentMaxCalculator.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/PercentMaxCalculator.kt @@ -1,3 +1,8 @@ +/* + * Android PercentMaxCalculator. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data enum class GeneratorLoadChoice { AUTOMATIC, PERCENT_MAX, NONE } diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/SessionGenerationEngine.kt b/android/app/src/main/java/com/labfytools/trainlog/data/SessionGenerationEngine.kt index 9605b97..1cefe01 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/SessionGenerationEngine.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/SessionGenerationEngine.kt @@ -1,3 +1,8 @@ +/* + * Android SessionGenerationEngine. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data import com.labfytools.trainlog.model.RecordingMode diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/SessionGenerationPolicy.kt b/android/app/src/main/java/com/labfytools/trainlog/data/SessionGenerationPolicy.kt index cec110f..d3f96ae 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/SessionGenerationPolicy.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/SessionGenerationPolicy.kt @@ -1,3 +1,8 @@ +/* + * Android SessionGenerationPolicy. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/SessionGeneratorRepositoryModels.kt b/android/app/src/main/java/com/labfytools/trainlog/data/SessionGeneratorRepositoryModels.kt index 1c6bcbb..f2841e4 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/SessionGeneratorRepositoryModels.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/SessionGeneratorRepositoryModels.kt @@ -1,3 +1,8 @@ +/* + * Android SessionGeneratorRepositoryModels. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data import com.labfytools.trainlog.model.SessionExercisePlan diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/StatisticsModels.kt b/android/app/src/main/java/com/labfytools/trainlog/data/StatisticsModels.kt index 6358366..8329376 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/StatisticsModels.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/StatisticsModels.kt @@ -1,3 +1,8 @@ +/* + * Android StatisticsModels. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data /** STATS_V1 is a read-only projection: none of these values are persisted as facts. */ diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/SyncCatalogInbox.kt b/android/app/src/main/java/com/labfytools/trainlog/data/SyncCatalogInbox.kt index 621351c..399fe07 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/SyncCatalogInbox.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/SyncCatalogInbox.kt @@ -1,3 +1,8 @@ +/* + * Android SyncCatalogInbox. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/SyncExporter.kt b/android/app/src/main/java/com/labfytools/trainlog/data/SyncExporter.kt index f8af07d..200eedc 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/SyncExporter.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/SyncExporter.kt @@ -1,3 +1,8 @@ +/* + * Android SyncExporter. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/SyncRequestOutbox.kt b/android/app/src/main/java/com/labfytools/trainlog/data/SyncRequestOutbox.kt index 5b7acce..768c0dc 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/SyncRequestOutbox.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/SyncRequestOutbox.kt @@ -1,3 +1,8 @@ +/* + * Android SyncRequestOutbox. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/TrainingKnowledgeCatalog.kt b/android/app/src/main/java/com/labfytools/trainlog/data/TrainingKnowledgeCatalog.kt index 3948ba6..3014fc0 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/TrainingKnowledgeCatalog.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/TrainingKnowledgeCatalog.kt @@ -1,3 +1,8 @@ +/* + * Android TrainingKnowledgeCatalog. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/TrainlogRepository.kt b/android/app/src/main/java/com/labfytools/trainlog/data/TrainlogRepository.kt index e85e799..88e4a56 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/TrainlogRepository.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/TrainlogRepository.kt @@ -1,3 +1,8 @@ +/* + * Android TrainlogRepository. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data import android.content.ContentValues @@ -62,6 +67,13 @@ internal fun exerciseProfileRevision(parent: String, recording: String, tracking return "pr2_" + UUID(bytes.long, bytes.long).toString() } +/* + * Advances one exercise profile along its bounded causal revision chain. + * + * The transaction-owning caller supplies the database. This function mutates + * only profile-state ancestry, returns false for missing/exhausted state, and + * never rewrites historical occurrence snapshots. + */ private fun advanceExerciseProfileRevision( db: SQLiteDatabase, rowId: Long, recording: String, tracking: String, fields: Int, ): Boolean { @@ -6884,6 +6896,13 @@ private const val MAX_AI_DRAFT_ENTRIES = 64 private const val MAX_AI_TARGET_SETS = 99 private const val MAX_AI_TARGET_REPS = 999 +/* + * Owns creation and ordered migration of the Android-local capture database. + * + * SQLiteOpenHelper serializes lifecycle callbacks. Each additive migration + * preserves completed history and the singleton active draft; desktop schema + * numbering and synchronization remain separate contracts. + */ private class TrainlogDatabaseHelper( private val appContext: Context, databaseName: String, diff --git a/android/app/src/main/java/com/labfytools/trainlog/data/TrainlogTimestamp.kt b/android/app/src/main/java/com/labfytools/trainlog/data/TrainlogTimestamp.kt index 93820eb..8c01f87 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/data/TrainlogTimestamp.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/data/TrainlogTimestamp.kt @@ -1,3 +1,8 @@ +/* + * Android TrainlogTimestamp. + * + * Owns this data-layer boundary while keeping UI state, canonical desktop history, and exchange contracts separate. + */ package com.labfytools.trainlog.data internal data class TrainlogTimestampKey( diff --git a/android/app/src/main/java/com/labfytools/trainlog/model/BodyModels.kt b/android/app/src/main/java/com/labfytools/trainlog/model/BodyModels.kt index 48a0a37..f12f40d 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/model/BodyModels.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/model/BodyModels.kt @@ -1,3 +1,8 @@ +/* + * Android BodyModels model. + * + * Defines in-memory capture semantics without owning persistence, synchronization, or presentation. + */ package com.labfytools.trainlog.model data class BodyObservationDraft( diff --git a/android/app/src/main/java/com/labfytools/trainlog/model/ExerciseProfile.kt b/android/app/src/main/java/com/labfytools/trainlog/model/ExerciseProfile.kt index 974f3d1..888339d 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/model/ExerciseProfile.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/model/ExerciseProfile.kt @@ -1,3 +1,8 @@ +/* + * Android ExerciseProfile model. + * + * Defines in-memory capture semantics without owning persistence, synchronization, or presentation. + */ package com.labfytools.trainlog.model enum class RecordingMode( diff --git a/android/app/src/main/java/com/labfytools/trainlog/model/SessionModels.kt b/android/app/src/main/java/com/labfytools/trainlog/model/SessionModels.kt index 6dd9a31..55bd8ba 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/model/SessionModels.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/model/SessionModels.kt @@ -1,3 +1,8 @@ +/* + * Android SessionModels model. + * + * Defines in-memory capture semantics without owning persistence, synchronization, or presentation. + */ package com.labfytools.trainlog.model enum class SessionType( diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/AndroidAppShell.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/AndroidAppShell.kt index 24ce4dd..f084827 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/AndroidAppShell.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/AndroidAppShell.kt @@ -1,3 +1,8 @@ +/* + * Android AndroidAppShell. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import androidx.activity.compose.BackHandler diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/AndroidSpeechRecognitionAdapter.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/AndroidSpeechRecognitionAdapter.kt index 6a97692..505cb78 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/AndroidSpeechRecognitionAdapter.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/AndroidSpeechRecognitionAdapter.kt @@ -1,3 +1,8 @@ +/* + * Android AndroidSpeechRecognitionAdapter. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import android.content.Context diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/AppNavigation.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/AppNavigation.kt index 4d75c59..38ebe43 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/AppNavigation.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/AppNavigation.kt @@ -1,3 +1,8 @@ +/* + * Android AppNavigation. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import androidx.compose.runtime.getValue diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/BodyScreen.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/BodyScreen.kt index d7ad7f9..c862095 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/BodyScreen.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/BodyScreen.kt @@ -1,3 +1,8 @@ +/* + * Android BodyScreen. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import androidx.compose.foundation.background diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/CompletedSessionCorrectionScreen.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/CompletedSessionCorrectionScreen.kt index 4675d95..c59e93c 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/CompletedSessionCorrectionScreen.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/CompletedSessionCorrectionScreen.kt @@ -1,3 +1,8 @@ +/* + * Android CompletedSessionCorrectionScreen. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import androidx.compose.runtime.Composable diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/ExerciseScreen.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/ExerciseScreen.kt index ec33934..69ccaaf 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/ExerciseScreen.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/ExerciseScreen.kt @@ -1,3 +1,8 @@ +/* + * Android ExerciseScreen. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import androidx.compose.foundation.background diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/FeedbackDictation.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/FeedbackDictation.kt index f65777d..27be6d2 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/FeedbackDictation.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/FeedbackDictation.kt @@ -1,3 +1,8 @@ +/* + * Android FeedbackDictation. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui /** Explicit, platform-independent dictation state used by Compose and tests. */ diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/FeedbackEditor.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/FeedbackEditor.kt index 477c468..6c4004a 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/FeedbackEditor.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/FeedbackEditor.kt @@ -1,3 +1,8 @@ +/* + * Android FeedbackEditor. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import android.Manifest diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/HistoryScreen.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/HistoryScreen.kt index 56b0bcc..90408f9 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/HistoryScreen.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/HistoryScreen.kt @@ -1,3 +1,8 @@ +/* + * Android HistoryScreen. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import androidx.compose.runtime.Composable diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/HomeScreen.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/HomeScreen.kt index 844a1db..5808067 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/HomeScreen.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/HomeScreen.kt @@ -1,3 +1,8 @@ +/* + * Android HomeScreen. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import androidx.compose.foundation.Canvas diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/SectionScreens.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/SectionScreens.kt index c8b49d6..30e49d2 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/SectionScreens.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/SectionScreens.kt @@ -1,3 +1,8 @@ +/* + * Android SectionScreens. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import androidx.activity.compose.rememberLauncherForActivityResult diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/SessionDetailScreen.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/SessionDetailScreen.kt index 873a0a8..d2558cd 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/SessionDetailScreen.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/SessionDetailScreen.kt @@ -1,3 +1,8 @@ +/* + * Android SessionDetailScreen. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import androidx.compose.runtime.Composable diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/SessionGeneratorScreen.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/SessionGeneratorScreen.kt index b4581e7..fa413df 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/SessionGeneratorScreen.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/SessionGeneratorScreen.kt @@ -1,3 +1,8 @@ +/* + * Android SessionGeneratorScreen. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import androidx.compose.runtime.Composable diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/SessionScreen.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/SessionScreen.kt index 0cf0d5f..572613d 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/SessionScreen.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/SessionScreen.kt @@ -1,3 +1,8 @@ +/* + * Android SessionScreen. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui /* TRAINLOG_ANDROID_MAX_TEST_SESSION_V1 */ diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/StatisticsScreen.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/StatisticsScreen.kt index b9b0d31..44278c2 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/StatisticsScreen.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/StatisticsScreen.kt @@ -1,3 +1,8 @@ +/* + * Android StatisticsScreen. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import androidx.compose.foundation.Canvas diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/SyncScreen.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/SyncScreen.kt index fd13a5a..a1de1fd 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/SyncScreen.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/SyncScreen.kt @@ -1,3 +1,8 @@ +/* + * Android SyncScreen. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui /* TRAINLOG_ANDROID_TRIGGERED_SYNC_V1 */ diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/TrainlogApp.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/TrainlogApp.kt index 42f7965..3ec4f49 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/TrainlogApp.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/TrainlogApp.kt @@ -1,3 +1,8 @@ +/* + * Android TrainlogApp. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui /* TRAINLOG_PC_CATALOG_AUTO_APPLY */ diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/TrainlogComponents.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/TrainlogComponents.kt index 26cb5de..7bed439 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/TrainlogComponents.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/TrainlogComponents.kt @@ -1,3 +1,8 @@ +/* + * Android TrainlogComponents. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import androidx.compose.foundation.background diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/TrainlogIcons.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/TrainlogIcons.kt index b9f3c02..65279a0 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/TrainlogIcons.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/TrainlogIcons.kt @@ -1,3 +1,8 @@ +/* + * Android TrainlogIcons. + * + * Owns this Compose presentation boundary; durable state and domain rules remain in repository and model layers. + */ package com.labfytools.trainlog.ui import androidx.compose.ui.graphics.Color diff --git a/android/app/src/main/java/com/labfytools/trainlog/ui/theme/TrainlogTheme.kt b/android/app/src/main/java/com/labfytools/trainlog/ui/theme/TrainlogTheme.kt index 5aea737..a623186 100644 --- a/android/app/src/main/java/com/labfytools/trainlog/ui/theme/TrainlogTheme.kt +++ b/android/app/src/main/java/com/labfytools/trainlog/ui/theme/TrainlogTheme.kt @@ -1,3 +1,8 @@ +/* + * Android TrainlogTheme. + * + * Owns shared presentation tokens without changing domain, persistence, or synchronization semantics. + */ package com.labfytools.trainlog.ui.theme import androidx.compose.runtime.Composable diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/AiSessionDraftRepositoryTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/AiSessionDraftRepositoryTest.kt index f264738..ec2a019 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/AiSessionDraftRepositoryTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/AiSessionDraftRepositoryTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for AiSessionDraftRepositoryTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/AndroidV10PlanningMigrationTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/AndroidV10PlanningMigrationTest.kt index 1817d4e..beaeea6 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/AndroidV10PlanningMigrationTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/AndroidV10PlanningMigrationTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for AndroidV10PlanningMigrationTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/AndroidV11ExerciseAliasMigrationTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/AndroidV11ExerciseAliasMigrationTest.kt index 79e6879..3373a78 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/AndroidV11ExerciseAliasMigrationTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/AndroidV11ExerciseAliasMigrationTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for AndroidV11ExerciseAliasMigrationTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/AndroidV16AiSessionDraftMigrationTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/AndroidV16AiSessionDraftMigrationTest.kt index 83c5192..f8e2a54 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/AndroidV16AiSessionDraftMigrationTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/AndroidV16AiSessionDraftMigrationTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for AndroidV16AiSessionDraftMigrationTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/BodyZoneHomeOverviewRepositoryTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/BodyZoneHomeOverviewRepositoryTest.kt index 59a7425..8a6423b 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/BodyZoneHomeOverviewRepositoryTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/BodyZoneHomeOverviewRepositoryTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for BodyZoneHomeOverviewRepositoryTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/BodyZonesTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/BodyZonesTest.kt index 8507af8..2d8b53a 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/BodyZonesTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/BodyZonesTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for BodyZonesTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/DirectExchangeStorageTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/DirectExchangeStorageTest.kt index c858403..a9742cc 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/DirectExchangeStorageTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/DirectExchangeStorageTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for DirectExchangeStorageTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.Manifest diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/EquipmentCatalogTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/EquipmentCatalogTest.kt index 8d66cdd..01c11c4 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/EquipmentCatalogTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/EquipmentCatalogTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for EquipmentCatalogTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import androidx.test.core.app.ApplicationProvider diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/ExerciseProfileStateSyncTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/ExerciseProfileStateSyncTest.kt index dec4214..77d21c0 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/ExerciseProfileStateSyncTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/ExerciseProfileStateSyncTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for ExerciseProfileStateSyncTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/FeedbackElapsedLabelTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/FeedbackElapsedLabelTest.kt index 0e0dd95..d056952 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/FeedbackElapsedLabelTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/FeedbackElapsedLabelTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for FeedbackElapsedLabelTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/HistoricalSessionProfileImportTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/HistoricalSessionProfileImportTest.kt index 1c35cff..84274ae 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/HistoricalSessionProfileImportTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/HistoricalSessionProfileImportTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for HistoricalSessionProfileImportTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/PercentMaxCalculatorTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/PercentMaxCalculatorTest.kt index 8ce115c..244905b 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/PercentMaxCalculatorTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/PercentMaxCalculatorTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for PercentMaxCalculatorTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import org.junit.Assert.assertEquals diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/RealAndroidV12MachineExerciseMigrationTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/RealAndroidV12MachineExerciseMigrationTest.kt index decf3be..c772613 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/RealAndroidV12MachineExerciseMigrationTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/RealAndroidV12MachineExerciseMigrationTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for RealAndroidV12MachineExerciseMigrationTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/RealAndroidV14FeedbackRevisionMigrationTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/RealAndroidV14FeedbackRevisionMigrationTest.kt index 1f5349c..9273a42 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/RealAndroidV14FeedbackRevisionMigrationTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/RealAndroidV14FeedbackRevisionMigrationTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for RealAndroidV14FeedbackRevisionMigrationTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/RealAndroidV9BodyZonesMigrationTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/RealAndroidV9BodyZonesMigrationTest.kt index 099f5e4..830325e 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/RealAndroidV9BodyZonesMigrationTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/RealAndroidV9BodyZonesMigrationTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for RealAndroidV9BodyZonesMigrationTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/SessionGenerationEngineTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/SessionGenerationEngineTest.kt index b4735c5..8b7b7c3 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/SessionGenerationEngineTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/SessionGenerationEngineTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for SessionGenerationEngineTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import androidx.test.core.app.ApplicationProvider diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/SessionGeneratorRepositoryTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/SessionGeneratorRepositoryTest.kt index 98317c9..33edc2f 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/SessionGeneratorRepositoryTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/SessionGeneratorRepositoryTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for SessionGeneratorRepositoryTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/StatisticsRepositoryTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/StatisticsRepositoryTest.kt index 373f182..38a20ec 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/StatisticsRepositoryTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/StatisticsRepositoryTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for StatisticsRepositoryTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/TrainingExerciseContextTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/TrainingExerciseContextTest.kt index 94e1590..666d191 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/TrainingExerciseContextTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/TrainingExerciseContextTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for TrainingExerciseContextTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/TrainingFeedbackRepositoryTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/TrainingFeedbackRepositoryTest.kt index cf1e49b..9903c6f 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/TrainingFeedbackRepositoryTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/TrainingFeedbackRepositoryTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for TrainingFeedbackRepositoryTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/TrainingKnowledgeCatalogTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/TrainingKnowledgeCatalogTest.kt index ad8cf56..574caf3 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/TrainingKnowledgeCatalogTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/TrainingKnowledgeCatalogTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for TrainingKnowledgeCatalogTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/TrainlogRepositoryDraftTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/TrainlogRepositoryDraftTest.kt index 2aa8f4d..98f2d6f 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/TrainlogRepositoryDraftTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/TrainlogRepositoryDraftTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for TrainlogRepositoryDraftTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/data/TrainlogTimestampTest.kt b/android/app/src/test/java/com/labfytools/trainlog/data/TrainlogTimestampTest.kt index aaaabc4..49d5943 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/data/TrainlogTimestampTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/data/TrainlogTimestampTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for TrainlogTimestampTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.data import org.junit.Assert.assertEquals diff --git a/android/app/src/test/java/com/labfytools/trainlog/ui/AiSessionDraftUiWiringTest.kt b/android/app/src/test/java/com/labfytools/trainlog/ui/AiSessionDraftUiWiringTest.kt index 7731f79..b443088 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/ui/AiSessionDraftUiWiringTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/ui/AiSessionDraftUiWiringTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for AiSessionDraftUiWiringTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.ui import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/ui/AndroidSpeechRecognitionIntentTest.kt b/android/app/src/test/java/com/labfytools/trainlog/ui/AndroidSpeechRecognitionIntentTest.kt index f60309a..331b2e1 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/ui/AndroidSpeechRecognitionIntentTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/ui/AndroidSpeechRecognitionIntentTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for AndroidSpeechRecognitionIntentTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.ui import android.speech.RecognizerIntent diff --git a/android/app/src/test/java/com/labfytools/trainlog/ui/AndroidUiRedesignTest.kt b/android/app/src/test/java/com/labfytools/trainlog/ui/AndroidUiRedesignTest.kt index 85bb05c..3233956 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/ui/AndroidUiRedesignTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/ui/AndroidUiRedesignTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for AndroidUiRedesignTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.ui import androidx.compose.ui.test.junit4.createComposeRule diff --git a/android/app/src/test/java/com/labfytools/trainlog/ui/AppNavigationStateTest.kt b/android/app/src/test/java/com/labfytools/trainlog/ui/AppNavigationStateTest.kt index de2dcc1..6d7f7c4 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/ui/AppNavigationStateTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/ui/AppNavigationStateTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for AppNavigationStateTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.ui import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/ui/BodyZoneHomePresentationTest.kt b/android/app/src/test/java/com/labfytools/trainlog/ui/BodyZoneHomePresentationTest.kt index 6b9085a..6dde12d 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/ui/BodyZoneHomePresentationTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/ui/BodyZoneHomePresentationTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for BodyZoneHomePresentationTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.ui import com.labfytools.trainlog.data.BodyZoneHomeState diff --git a/android/app/src/test/java/com/labfytools/trainlog/ui/BodyZoneHomeSemanticsTest.kt b/android/app/src/test/java/com/labfytools/trainlog/ui/BodyZoneHomeSemanticsTest.kt index b1edea0..f40ce86 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/ui/BodyZoneHomeSemanticsTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/ui/BodyZoneHomeSemanticsTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for BodyZoneHomeSemanticsTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.ui import androidx.compose.foundation.layout.Box diff --git a/android/app/src/test/java/com/labfytools/trainlog/ui/DraftFeedbackUiReadbackTest.kt b/android/app/src/test/java/com/labfytools/trainlog/ui/DraftFeedbackUiReadbackTest.kt index 32f0a29..49c878c 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/ui/DraftFeedbackUiReadbackTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/ui/DraftFeedbackUiReadbackTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for DraftFeedbackUiReadbackTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.ui import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/ui/FeedbackDictationControllerTest.kt b/android/app/src/test/java/com/labfytools/trainlog/ui/FeedbackDictationControllerTest.kt index 7f82469..e4ef12c 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/ui/FeedbackDictationControllerTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/ui/FeedbackDictationControllerTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for FeedbackDictationControllerTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.ui import org.junit.Assert.* diff --git a/android/app/src/test/java/com/labfytools/trainlog/ui/FeedbackEditorVoiceUiTest.kt b/android/app/src/test/java/com/labfytools/trainlog/ui/FeedbackEditorVoiceUiTest.kt index d671756..be037bf 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/ui/FeedbackEditorVoiceUiTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/ui/FeedbackEditorVoiceUiTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for FeedbackEditorVoiceUiTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.ui import android.Manifest diff --git a/android/app/src/test/java/com/labfytools/trainlog/ui/SessionGeneratorPreviewControllerTest.kt b/android/app/src/test/java/com/labfytools/trainlog/ui/SessionGeneratorPreviewControllerTest.kt index d5b20ba..98e6336 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/ui/SessionGeneratorPreviewControllerTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/ui/SessionGeneratorPreviewControllerTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for SessionGeneratorPreviewControllerTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.ui import com.labfytools.trainlog.data.BodyZoneRecentExposure diff --git a/android/app/src/test/java/com/labfytools/trainlog/ui/SessionSetRowEditorTest.kt b/android/app/src/test/java/com/labfytools/trainlog/ui/SessionSetRowEditorTest.kt index 05604a5..82beefb 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/ui/SessionSetRowEditorTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/ui/SessionSetRowEditorTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for SessionSetRowEditorTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.ui import com.labfytools.trainlog.model.ExerciseProfile diff --git a/android/app/src/test/java/com/labfytools/trainlog/ui/StatisticsScreenPresentationTest.kt b/android/app/src/test/java/com/labfytools/trainlog/ui/StatisticsScreenPresentationTest.kt index e1b9c4a..8cb4198 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/ui/StatisticsScreenPresentationTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/ui/StatisticsScreenPresentationTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for StatisticsScreenPresentationTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.ui import androidx.compose.foundation.layout.Column diff --git a/android/app/src/test/java/com/labfytools/trainlog/ui/SyncBundlePublicationTest.kt b/android/app/src/test/java/com/labfytools/trainlog/ui/SyncBundlePublicationTest.kt index afdbfa6..1bd5d2a 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/ui/SyncBundlePublicationTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/ui/SyncBundlePublicationTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for SyncBundlePublicationTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.ui import android.content.Context diff --git a/android/app/src/test/java/com/labfytools/trainlog/ui/TrainlogAppNavigationCallbackTest.kt b/android/app/src/test/java/com/labfytools/trainlog/ui/TrainlogAppNavigationCallbackTest.kt index a02abfb..c79f58c 100644 --- a/android/app/src/test/java/com/labfytools/trainlog/ui/TrainlogAppNavigationCallbackTest.kt +++ b/android/app/src/test/java/com/labfytools/trainlog/ui/TrainlogAppNavigationCallbackTest.kt @@ -1,3 +1,8 @@ +/* + * Regression coverage for TrainlogAppNavigationCallbackTest. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ package com.labfytools.trainlog.ui import android.content.Context diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..9493a67 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,73 @@ +# Trainlog documentation + +This file is the canonical documentation index. Canonical documents describe +the current contract or state; `reviews/` and `CHANGELOG.md` retain historical +evidence and chronology. + +## Start here + +- [Current state](current_state.md) owns present schemas, capabilities, + validation, and active limitations. +- [Architecture](architecture.md) owns component, process, storage, transport, + and responsibility boundaries. +- [Roadmap](roadmap.md) owns the current cursor and future work. + +## Interfaces + +- [Android](android.md) owns field-companion capture, local persistence, + glanceable summaries, permissions, and Android interaction rules. +- [Desktop TUI](tui.md) owns Notcurses navigation, correction, detailed + consultation, analytics, graphs, and long-term follow-up behavior. + +## Data model + +- [Exercise data model](exercise_data_model.md) owns exercise profiles, + occurrence identity, planned-versus-actual work, load, and MAX semantics. +- [Database](database.md) owns desktop SQLite tables, constraints, transactions, + and migrations. +- [Training feedback](training_feedback.md) owns immediate feedback, immutable + revisions, and J+1/session follow-up semantics. +- [Domain documentation](domain/) owns cited anatomy, biomechanics, equipment + interpretation, training knowledge, and session-generation science. + +## Synchronization and exchange + +- [Synchronization exchange](sync_exchange.md) owns the active MTP workflow, + artifact direction, replay, publication, receipts, and daemon behavior. +- [Exchange formats](exchange_format.md) owns frozen Trainlog JSON V1 and + separately versioned contracts, including AI exchange definitions. + +## Analytics + +- [Desktop TUI](tui.md) owns visible statistics, MAX, body analytics, calendar + buckets, and graph behavior. +- [Current state](current_state.md) records which analytics are implemented. +- [Exercise data model](exercise_data_model.md) owns the distinctions between + measured MAX, performed work, plans, and estimates. + +## Development + +- [Tests and validation](tests.md) owns durable build, test, sanitizer, + contract, and hardware-validation commands. +- [Coding style](coding_style.md) owns C17/Kotlin style and comment rules. +- [Development contract](../AGENTS.md) owns frozen boundaries, invariants, + validation policy, and safe device-testing policy. +- [Android build notes](../android/README.md) are the Android setup entry point. +- [Format material](../format/README.md) indexes frozen schema assets. + +## Design + +- [Design records](design/) retain proposals and design-gate evidence. They are + not the authority for current implementation status. + +## Reviews and history + +- [Review records](reviews/) retain historical audits, incidents, checkpoints, + and validation evidence. Their status and paths are historical. +- [Changelog](../CHANGELOG.md) owns chronological change history. + +## Ownership rule + +Do not copy long normative explanations between documents. The repository +`README.md` is the entry point, this file is the index, +`current_state.md` is the snapshot, and `roadmap.md` is future-oriented. diff --git a/docs/current_state.md b/docs/current_state.md index eb31763..00f13e2 100644 --- a/docs/current_state.md +++ b/docs/current_state.md @@ -1,615 +1,133 @@ # Current implementation state -Canonical snapshot: 2026-09-10. +Snapshot date: **2026-09-15**. -This document is the compact source of truth for the implemented Trainlog -baseline. Detailed behavior belongs in the topic-specific documents. +This document owns the current implemented state. Historical checkpoints and +closed incidents belong in [reviews](reviews/) and the +[changelog](../CHANGELOG.md). -## Status +## Product boundary -```text -GATE_0_PROJECT_CONTRACT=PASS -GATE_1_TRAINLOG_FORMAT_V1=PASS/FROZEN -GATE_2_PERSISTENCE_AND_USABLE_TUI=PASS +Android is the field companion: it captures training and body data, preserves +the active draft, receives AI proposals, triggers synchronization, and shows +quick summaries. The C17/Notcurses TUI is the detailed consultation, +correction, catalogue, analytics, graphing, and long-term tracking surface. -TRAINLOG_FORMAT_V1=FROZEN -TRAINLOG_AI_EXPORT_V1=PASS -TRAINLOG_AI_GDRIVE_SYNC_V1=PASS -TRAINLOG_AI_SESSION_DRAFT_V1=VALIDATION_PENDING -TRAINLOG_ANDROID_BODY_ZONE_REPOPULATION_FIX=PASS +Android captures and summarizes. The TUI analyzes and tracks over time. The +desktop SQLite database remains the canonical long-term history. -DESKTOP_SCHEMA_V11=PASS -ANDROID_LOCAL_DATABASE_V10=PASS -ANDROID_LOCAL_DATABASE_V11=PASS -ANDROID_SESSION_DRAFT_V1=PASS -ANDROID_DRAFT_DURABLE=PASS -ANDROID_DRAFT_BACKGROUND_SURVIVAL=PASS -ANDROID_DRAFT_PROCESS_DEATH_SURVIVAL=PASS -ANDROID_DRAFT_FORCE_STOP_SURVIVAL=PASS -ANDROID_SESSION_RESUME=PASS -ANDROID_DRAFT_FORM_RESTORE=PASS -ANDROID_DRAFT_EXERCISE_REMOVE=PASS -ANDROID_DRAFT_DISCARD=PASS -ANDROID_DRAFT_FINALIZE_ATOMIC=PASS -ANDROID_DRAFT_NOT_EXPORTED_AS_SESSION=PASS -EXERCISE_EDIT_V1=PASS -EXERCISE_RENAME_STABLE_ID=PASS -ANDROID_BANNER_PARITY_V1=PASS -ANDROID_INSTALL_ADB=PASS -ANDROID_USER_DATA_PRESERVED=PASS -ANDROID_MAX_V9_INSTALL_ADB=PASS -ANDROID_MAX_V9_REAL_DATA_MIGRATION=PASS -DESKTOP_MAX_V9_REAL_DATA_MIGRATION=PASS -REAL_DATABASE_APPLICATION=PASS +## Versions and compatibility -PROFILE_AWARE_EXERCISES=PASS -CONTINUOUS_ACTIVITY=PASS -VARIABLE_REPETITION_SETS=PASS +| Boundary | Current state | +|---|---| +| Frozen project exchange | `TRAINLOG_FORMAT_V1=PASS/FROZEN` | +| Desktop SQLite | schema v18 | +| Android SQLite | schema v17 | +| Mobile snapshot | V3 active; V1/V2 readable legacy inputs | +| Desktop terminal backend | Notcurses only | +| AI history export | `TRAINLOG_AI_EXPORT_V1` active | +| AI session proposals | `TRAINLOG_AI_SESSION_DRAFT_V1=VALIDATION_PENDING` | +| Training knowledge | `TRAINING_KNOWLEDGE_V1=PASS` | +| Session generator | `SESSION_GENERATOR_V1=PASS`, hidden pending V2 | +| Application shell | `APP_SHELL_V1=IMPLEMENTED_AWAITING_VISUAL_REVIEW_2` | +| Statistics | `STATS_V1=IMPLEMENTED` | -DIRECT_MTP_TRANSPORT=PASS -ANDROID_TO_PC_IMPORT=PASS -PC_TO_ANDROID_CATALOG=PASS -COMMON_SYNC_ENGINE=PASS -TRAINLOG_SYNCD=PASS -ANDROID_TRIGGERED_SYNC=PASS -ANDROID_SYNC_RECEIPT=PASS -TUI_SYNC_LOG_SHOW=PASS -BIDIRECTIONAL_SYNC_V1=PASS -MULTI_OCCURRENCE_SESSION_V2=PASS -EQUIPMENT_ASSOCIATIONS_V2=PASS -EQUIPMENT_DEFINITIONS_V1=PASS -EXERCISE_RECONCILIATION_V2=PASS -EXPLICIT_MAX_RESULTS_V1=PASS -MAX_TEST_RESUME_STABLE_ID=PASS -BODY_ZONES_V1=PASS -BODY_ZONE_SYNC_V1=PASS -BODY_ZONES_DESKTOP_REAL_MIGRATION=PASS -BODY_ZONES_TUI_REAL_VALIDATION=PASS -BODY_ZONES_ANDROID_DEVICE_VALIDATION=PASS +Desktop and Android schema numbers are independent. Neither changes the frozen +Trainlog JSON V1 contract. -TRAINING_KNOWLEDGE_V1=PASS -SESSION_GENERATOR_V1=PASS -APP_SHELL_V1=IMPLEMENTED_AWAITING_VISUAL_REVIEW_2 +## Storage and synchronization -DESKTOP_TESTS=52/52 PASS (normal); affected ASan/UBSan tests=6/6 PASS -ANDROID_BUILD=PASS -TRAINLOG_ANDROID_UI_REDESIGN_V1=PASS -HARDWARE_SYNC_VALIDATION=HISTORICAL_PASS -``` - -## Desktop - -Implemented: - -- C17/Notcurses true-color TUI with the APP_SHELL_V1 persistent seven-section - shell (72x20 minimum, UTF-8 bounded editors, resize fallback, F6 navigation, - F7 actions, and restored focus after overlays/routes); -- UTF-8 cell-aware scrolling training-knowledge screen, tested at the 72x20 - minimum terminal; -- SQLite schema v18, with stable ordered `session_exercises.entry_id`, an - immutable occurrence-owned `tracking_mode` snapshot, - bounded durable current-profile revision ancestry, - occurrence-level equipment identity, and desktop-local custom-equipment - definitions, plus occurrence-owned `max_results`; its v9 -> v10 migration - rebuilds only `performed_sets` to permit explicit zero actual loads while - preserving historic NULL and positive rows; -- canonical generated body-zone taxonomy, direct primary/secondary exercise - relations, stable-ID-only initial migration and descendant-aware filtering; -- direct session entry; -- normal desktop SETS planning followed by the table-only explicit actual-row - editor; zero-row completion is rejected while MAX and continuous entries keep - their separate no-set contracts; -- persisted session detail and editing; -- exercise removal from a session through transactional child replacement; -- exercise catalog; -- supplied-equipment browsing/search/detail and desktop-local custom-equipment - creation/selection; -- profile-aware set and continuous activities; -- heterogeneous repetition sets; -- multiple occurrences of one catalogue exercise in a session; -- per-set actual loads with distinct external/assistance semantics; -- body-observation creation/history/editing; -- `TRAINLOG_TUI_MEASUREMENTS_GRAPH_V1=PASS`: a reusable Notcurses body-history - chart with elapsed-time X spacing, labelled and margined Y scale, Braille 2x4 - line rasterization, distinct real-measurement markers, responsive geometry, - and terminal-free calculation/raster regressions; -- `TRAINLOG_TUI_STATISTICS_V1=PASS`: the TUI statistics hub covers recorded - body history, global 7-day/30-day/all-time activity, canonical-exercise - facts and graphs, persisted primary/secondary body-zone activity, and - explicit MAX history. Aggregations are read-only and terminal-independent; - volume, planning and feedback scopes remain conservative and auditable; -- `TRAINLOG_TUI_STATISTICS_REFINEMENT_V1=PASS`: finite graph windows preserve - their selected domain, weekly totals use zero-based discrete bars and local - Monday buckets, wide summaries use semantic panels, zone bars share one - numeric scale, and MAX defaults to explicitly measured exercises; -- `TRAINLOG_TUI_STATISTICS_PERIOD_BUCKETING_V1=PASS`: the 7-day summary compares - up to four consecutive calendar-week buckets and preserves empty periods; -- `TRAINLOG_TUI_STATISTICS_PERIOD_BUCKET_SIZE_FIX=PASS`: historical checkpoint - that separated bucket sizes before the subsequent calendar alignment. Its - duration-based full-history adaptation remains active; -- `TRAINLOG_TUI_STATISTICS_CALENDAR_BUCKETS_V1=PASS`: the current `7j` summary - and bars are Monday–Sunday calendar weeks, while `30j` uses the current and - preceding Gregorian calendar months. Persisted civil dates determine bucket - membership without reinterpretation through the machine timezone; empty - weeks/months and partial current periods remain explicit; -- normalized body overlays; -- exercise performance history; -- direct USB/MTP device access; -- manual Android -> PC, PC -> Android, and bidirectional synchronization; -- structured synchronization history and detail. - -`TRAINLOG_AI_SESSION_DRAFT_V1` is implemented but awaits one real external -Drive/Android-triggered bidirectional smoke test. The Drive source is the -single strict `TRAINLOG_AI_SESSION_DRAFT` V1 object at -`TrainLog Gdrive:Trainlog/AI/inbox/trainlog_ai_session_draft_v1.json`; after a -transactional, idempotent desktop import its exact fetched bytes are copied to -the archive by stable `aid_` ID. The inbox object remains available for logical -replay and archive/status convergence. -Desktop exports the separate `trainlog-ai-session-drafts-v1.json` companion to -Android in deterministic batches of at most 256 unpublished proposals. It -marks exactly a batch successfully published over MTP and retries an unchanged -batch after publication failure; source replay identities remain permanent. -The Android pending proposal collection is not the durable singleton -active capture draft: explicit start copies targets only and tombstones the -proposal in one transaction; explicit deletion tombstones it too. The 64-entry, -99-set, 999-rep and 256-proposal limits, profile compatibility and replay rules -are enforced. The always-visible **Brouillons** action reports the pending -proposal count, and a successful catalogue/companion import invalidates the -pending-screen query so newly imported proposals appear without restarting the -application. Inbound `NONE`, `IMPORTED`, `ALREADY_IMPORTED`, `REJECTED`, -`DRIVE_FAIL`, and `ARCHIVE_FAIL` outcomes remain visible in successful sync -history. A transport/archive failure never rolls back a committed import. - -The September 2026 connected-device diagnosis found that the installed APK was -the older 2026-09-13 build: its copied local database was still schema v16 and -had no `ai_session_drafts` table. That APK therefore could not have imported the -Android companion. After a current APK is installed, one new synchronization is -required to import the still-pending companion. This diagnosis is not the real -Drive/Android acceptance smoke test, which remains pending. - -Primary navigation is now shared with Android: - -```text -Accueil | Séances | Exercices | Statistiques | Synchronisation | Paramètres -``` - -`Séances` contains the current draft, the existing generator, manual entry, -and **Séances effectuées**. `Statistiques` exposes existing mensurations, -body views and explicit MAX/performance views only. Navigation neither writes -data nor launches synchronization. The second automated repair review covered -the TUI root search/action paths, selection/focus restoration and section hubs, -plus Android compact controls, hidden internal IDs and latest-MAX display -semantics. Human visual/accessibility review is still required before this -status can advance. +- Android stores capture data in its private SQLite database. +- Android reads and writes exchange artifacts only in + `/storage/emulated/0/Documents/Trainlog` after the user grants all-files + access through system settings. +- The old SAF/tree-URI path and `Download/Trainlog` are historical recovery + boundaries, not active storage choices. +- Desktop synchronization uses direct libudev/libmtp discovery and object + access. No GVFS/FUSE mount is required. +- `trainlog_sync_run()` is shared by the TUI and `trainlog-syncd`. +- The desktop imports Android snapshots, publishes catalog/profile/feedback/AI + companions, and returns a receipt. Stable IDs and tombstones make defined + replay paths idempotent. +- SQLite database files are never synchronized. +- The desktop AI flow uses external `rclone` for Drive inbox/archive and + read-only history export. Android owns no Drive credentials. ## Android -Implemented: +Android currently provides: -- native Kotlin/Compose application; -- local SQLite database v17, with non-destructive migrations through v17; -- one durable active-session draft, Home resume and raw-form restoration; -- `BODY_FOCUS_HOME_V1`: a compact accessible Home front/back BODY ZONES map, - textual top-three exposure ranking and Catalogue/Statistics drill-through; -- explicit confirmed discard and atomic completed-save/draft-clear; -- schema v15 immutable feedback wording revisions, Android correction UX, - read-only TUI display, and Training Feedback V2 synchronization; -- exercise creation; -- stable-ID exercise rename/editing with referenced-profile protection; -- primary/secondary body-zone selection, display, hierarchy filtering and - prefix-search composition, including visible unclassified exercises; -- inline exercise creation during session entry; -- profile-aware session recording; -- heterogeneous repetition-set entry; -- exercise removal from the current session draft; -- continuous activity recording; -- shared equipment selection, local custom equipment creation and occurrence - equipment persistence; -- local session history/detail; -- body measurements; -- automatic mobile snapshot maintenance; -- PC catalog application through user-enabled direct all-files access to the - fixed `Documents/Trainlog` directory; -- Android-triggered synchronization request; -- synchronization receipt handling. +- metadata-driven SETS+REPS, SETS+DURATION, and CONTINUOUS+DURATION capture; +- actual per-set values, optional occurrence equipment, and explicit MAX rows; +- exactly one durable active session draft with resume, confirmed discard, and + atomic completion; +- completed-session consultation and correction; +- exercise catalogue editing with stable `exercise_id` and referenced-profile + protection; +- supplied/custom equipment and machine-exercise metadata; +- body measurements and recent BODY ZONES summaries; +- immediate exercise feedback, immutable wording revisions, and J+1/session + follow-ups; +- pending AI proposal collection, explicit start/delete, and durable tombstones; +- 7/30/90-day, year, and all-history quick statistics; +- direct-storage snapshot publication, sync triggering, receipt display, and + companion application. -The Home BODY ZONES overview is exposure-only and read-only. It uses only -actual performed sets, continuous activities and explicit MAX results from -completed history, with canonical parsed-instant 7/30-day windows. Plans, -targets and drafts never qualify. Exactly the eight child anatomical zones are -processed; grouping zones cannot double count. Primary exposure dominates the -stable ranking, while secondary exposure is a weaker tie modifier. Alias -history resolves once to the canonical exercise. Unsupported zones are shown -as **Aucun exercice résolu disponible** and excluded from suggestions; empty -history is stated explicitly and suggests supported zones only. The existing -session generator remains hidden from normal UI, and the overview makes no -recovery, readiness, fatigue or prescription claim. +Android does not own canonical long-term analytics. The V1 session generator is +implemented but intentionally hidden from normal navigation pending V2. -The Android catalog exposes **Modifier** for every existing exercise. A rename -updates `name` and `normalized_name` in the original row, never creates an ID, -and remains valid for completed session and active-draft references. A profile -change is only accepted while the row has neither completed-session nor draft -references. Same-ID catalog reconciliation updates display metadata in place. -A different-ID normalized-name collision is reconciled only when recording and -tracking modes match, other known invariants are compatible, and one -`data_fields` mask contains the other. PC identity is canonical on Android; -the existing desktop identity is canonical on desktop. The richer bit-mask -union is retained without rewriting historical occurrence snapshots. +## Desktop TUI -All Android screens are hosted by the fixed `AndroidAppShell` Material 3 -`Scaffold` and `TopAppBar`: root routes show `TRAINLOG`, non-root routes show -their route title, and page content is rendered beneath that shell. The drawer, -top bar and content host keep navigation separate from page ownership. +The desktop is a strict C17 application using Notcurses. It currently provides: -## Training knowledge V1 +- a keyboard-first seven-section shell, semantic true-color roles, UTF-8 input, + resize recovery, and a 72x20 minimum-terminal fallback; +- session creation, history, detail, and transactional correction; +- exercise and equipment catalogue management; +- explicit measured-MAX consultation and working-load calculations; +- body observation history, correction, derived analytics, and longitudinal + graphs; +- statistics derived from canonical occurrence-owned actual work, including + exact calendar-week/month buckets, performance, body, frequency, exercise, + and BODY ZONES views; +- detailed synchronization status and history through the shared engine. -The implemented read-only training-knowledge layer loads shared versioned JSON -catalogs as the sole authored scientific source, generates the immutable C -catalog representation, and loads the same assets on Android. It has no -database migration, no auto-seeding, and no synchronization artifact. The -desktop database is schema v18 and Android is schema v17. Schema v13 is additive: exercise -rows own machine-facing load semantics, optional legacy equipment provenance, -an optional scientific profile, and an explicit resolved/unresolved science -state. Legacy equipment tables and occurrence columns remain intact. +Rendering does not own SQL or business rules. Statistics are read-only +projections; they are not persisted as facts. -Desktop `training_knowledge.h` and Android `TrainingKnowledgeCatalog` expose -source-linked science lookups and resolved-candidate filters. The additive -`equipment-exercise-relations-v2.json` catalog is the canonical -equipment-to-exercise compatibility source. Equipment owns physical identity, -load semantics, configuration labels, confidence, and source references only; -exercise knowledge exclusively owns muscles, movements, and BODY ZONES. Desktop -`training_context.h` and Android `TrainlogRepository` compose one real runtime -exercise with its persisted zones, compatible equipment, latest explicit MAX, -and bounded chronological occurrence/set history. Persisted zones remain -separate from scientific mappings; missing scientific knowledge is valid. +## Data semantics -The scientific review passed and the reviewed catalog bytes remain unchanged. -The independent temporal review returned `TEMPORAL_DELTA_REVIEW=PASS`, with no -temporal defects or repairs. It reviewed the grammar, calendar and offset -bounds, fraction precision, bytewise ties, cursor aliasing and exclusivity, -source capacity, snapshots, and Android/Python parity; it ran the targeted -Meson and four Python temporal tests. The initial full-tranche engineering -audit initially failed with stale temporal-defect documentation (BLOCKER), -Android loader parity gaps (BLOCKER), omitted Meson generator inputs (BLOCKER), -and a C role-only query mismatch (HIGH). One bounded repair chain resolved all -four findings; independent repair verification returned -`FINAL_REVIEW_REPAIR_VERIFICATION=PASS` and -`TRAINING_KNOWLEDGE_V1_ENGINEERING_REVIEW=PASS`. Fresh final validation passed: -strict build, 56 Meson tests, eight knowledge and four temporal Python tests, -knowledge/JSON/import validators, three C17 headers, affected C knowledge and -context tests under ASan/UBSan plus Python timestamp validation, normal and -sanitized 12-form temporal probes, and Android 56 tests with zero failures or -errors and one known missing-real-v9-fixture skip; Java 17 `assembleDebug` also -passed. Generated C is byte-identical with SHA-256 -`e8c099f67eb111d61621b5d76592c049823af5508d43e73ec646f22e4c377fca`; all six -Android assets are byte-identical. Preservation before and after repair confirms -historical desktop/Android schemas v11/v10, unchanged catalog/science/temporal bytes, and unchanged real -database logical SHA-256 `26139cafeffbde3ec08f6ef23c5069e75afb9cd69ffffb40be5c099006fedc4d`, -counts, integrity, and foreign keys. `TRAINING_KNOWLEDGE_V1=PASS`. The -[temporal contract](reviews/training_knowledge_v1_temporal_contract.md) -defines the settled reader behavior. No manual Android install, manual TUI -visual validation or manual MTP validation is claimed for this tranche. +- `exercise_id` identifies a catalogue exercise; `entry_id` identifies one + ordered occurrence in a session. +- Plans and performed work are distinct. A continuous activity is not a fake + performed set, and actual repetitions may be heterogeneous. +- Explicit MAX results are occurrence-owned and distinct from ordinary best + sets. Equipment/resistance/execution context remains relevant. +- BODY ZONES are a UX/business projection over explicit scientific knowledge, + not a complete anatomical taxonomy. +- Feedback roots retain identity while append-only revisions preserve wording + history. J+1/session follow-ups are session-owned. +- AI proposals contain target-only plans and never create performed work, + history, MAX, or feedback until the user explicitly starts and completes a + normal capture draft. -## Synchronization +## Validation status -Canonical exchange directory: +The durable commands are owned by [tests.md](tests.md). On 2026-09-15 this audit +passed desktop compilation, **58/58 Meson tests**, Android unit tests, Android +debug assembly, the JSON validator, and the import-contract validator. Link and +diff safety checks also pass in the final audit evidence. -```text -Documents/Trainlog -``` +Hardware-dependent MTP and the final real Drive plus Android-triggered AI-draft +smoke test are not automated. The latter is why +`TRAINLOG_AI_SESSION_DRAFT_V1` remains `VALIDATION_PENDING`. -Artifacts: +## Active limitations -```text -Android -> PC - trainlog-mobile-equipment-definitions-v1.json - trainlog-mobile-export-v3.json - trainlog-equipment-associations-v2.json - trainlog-exercise-body-zones-v1.json - -PC -> Android - trainlog-pc-equipment-definitions-v1.json - trainlog-pc-catalog-v1.json - trainlog-pc-mobile-export-v3.json - trainlog-equipment-associations-v2.json - trainlog-exercise-body-zones-v1.json - -Android -> PC agent - trainlog-sync-request-v1.json - -PC agent -> Android - trainlog-sync-receipt-v1.json -``` - -The desktop TUI and `trainlog-syncd` share `trainlog_sync_run()`. Its explicit -`a`, `p`, and `b` modes perform Android -> PC only, PC -> Android only, and -inbound-then-outbound respectively. Each direction reconciles equipment -definitions V1 before V2 artifacts that reference them. - -After the shared engine has reached a definitive successful result (including -publication of an Android-request receipt when applicable), the desktop runs -`TRAINLOG_AI_EXPORT_V1` and then the external `rclone copyto` publication to -`TrainLog Gdrive:Trainlog/AI/trainlog_ai_export_v1.json`. The TUI summary and -`trainlog-syncd` log expose `SYNC`, `AI_EXPORT`, and `GDRIVE_UPLOAD` separately. -An export or Drive failure never retroactively changes the successful Trainlog -sync result. Android does not execute `rclone`; all rclone/OAuth configuration -remains external under the user's normal `~/.config/rclone/` directory. - -Each structured local sync-history run persists its selected `a`, `p`, or `b` -direction. `direction inconnue` is reserved for legacy history rows whose -direction was not recorded; it is never used for a current run. - -On the TUI Sync page, `a`, `p`, and `b` directly open one confirmation for the -selected direction; `Enter` runs that confirmed action once, while `Esc` -cancels it without an operation (or returns when idle). `r` refreshes device -status only, and the former `s` shortcut is inert. Full and compact footers use -the same three directional actions, with compact labels only abbreviating the -endpoints. - -V2 resolves equipment by `(session_id, entry_id)`, never by display name or -catalogue identity alone. V1 files remain legacy-compatible and do not gain -multi-occurrence semantics retroactively. - -Body-zone relations have one direction-neutral companion and are keyed only by -canonical zone IDs and `exercise_id`. Identical state is an idempotent skip; a -successful publication records that exact state as the publisher baseline, so -a later peer-only edit of a new custom exercise is accepted. Simultaneous -divergence is an explicit conflict and secondary lists are never unioned. The -unclassified state has no relations; orphan secondary rows are invalid. Parent -groups are derived from the manifest and never serialized as exercise -relations. - -Supplied equipment remains generated from `catalog/equipment-v1.json`; its IDs -are reserved. User-created definitions synchronize additively through the -directional definitions V1 artifacts. Equal same-ID definitions are idempotent; -divergent definitions, unknown references, and association conflicts are -reported explicitly without silent overwrite. - -Conflict summaries identify the stable session, body-observation, association, -or definition identity and the source artifact/direction. Existing persisted -content is preserved when a conflict is reported. - -Synchronization addition counters describe durable inserts only. Exercise -rekeys or profile enrichments remain available through the separate -reconciliation counter; a compatible different-ID lookup that requires no -database write is an idempotent skip. This prevents a repeated Android -snapshot carrying a retired creator ID from being displayed as `+1 exercice` -when the canonical desktop catalog row and all business tables are unchanged. - -The current Marche collision is safely reconciled to desktop identity -`ex_b1e6ffc6-75b5-45ff-a3c0-e7433c58013d`. Its catalog profile is the compatible -union `continuous/duration/data_fields=3`; prior `data_fields=1` occurrences -retain their own snapshots and absent distance values. The Android occurrence -`sxe_f25142c8-455e-4346-9bfc-31d0989e275d` retains its duration, speed, distance -and equipment. No reference to the retired Android exercise identity remains -in the validated merged database copy. - -No SQLite file is copied. - -No mounted Android filesystem is required. - -## Session generator V1 - -`SESSION_GENERATOR_V1=PASS`. -The frozen separate policy is loaded identically by C and Android. It generates a -read-only, editable proposal for `full_body`, `upper_body`, `lower_body`, or -one of the eight remaining leaf zones, with four goals and policy-owned duration -bounds. It uses complete completed-history evidence, deterministic candidate -selection, explicit shortages, and an observed repeated-dose load only when the -exact exercise and compatible external equipment have a qualifying 28-day -anchor. MAX is context only and never produces a numeric target. - -The Android v10 -> v11 migration adds nullable planning metadata to normal and -draft occurrences. Existing rows receive `load_mode=none`, `rest_seconds=0`, -and null targets without reconstruction. Android acceptance atomically creates -the existing normal singleton draft with no actual sets; an existing draft is a -non-mutating conflict. TUI `g` opens its preview and then the normal editor; -completion still needs actual work. Empty proposals cannot be accepted. -Nonempty partial proposals retain explicit shortages and may enter normal draft -editing. The separate active V3 mobile export preserves plan and actual fields -atomically; V1/V2 remain readable legacy formats. - -The initial [independent engineering delta review](reviews/session_generator_v1_engineering_review.md) -found no findings, and the one deep final audit then found three repairable -blockers. Its bounded repairs and bounded final repair review passed. The final -matrix passed 45/45 Meson tests, named ASan/UBSan 4/4, and Android 75 tests with -zero failures/errors and one known unavailable external real-v9 fixture skip; -the structural v10 migration test executed and passed. Validators, strict C17 -headers, deterministic generation and APK asset byte comparisons passed. Real -desktop preservation is baseline-equal with logical SHA-256 -`5bff76850581cc3abafd583377a5de2c16d6313607a4cacb812376cfebd36cce`, ten -protected catalog/format files unchanged, and an empty index. No real app -upgrade/install or hardware MTP exercise is claimed. - -## Validation checkpoint - -Desktop: - -```text -Historical checkpoint: 39/39 Meson tests PASS for desktop schema v11 -JSON valid/invalid checks PASS -import-contract validator 6/6 PASS -Historical checkpoint: ASan/UBSan 39/39 Meson tests PASS with leak detection -standalone public-header C17 syntax PASS -real Notcurses binary zone workflows PASS in Kitty -git diff --check PASS -``` - -Android: - -```text -Android unit tests 44/44 PASS with a real v9 copy enabled, including body-zone -v9 -> v10 migration and sync -assembleDebug PASS -APK Signature Scheme v2 verification PASS -APK certificate SHA-256 matches the local debug keystore -APK SHA-256 5355f54e83f00ef31dc0e2f1db866c43ea3e9d880875f67878b1ffe169b5dc50 -``` - -Current real-data/environment boundary: - -```text -BODY_ZONES_DESKTOP_BACKUP=PASS -BODY_ZONES_DESKTOP_REAL_V10_TO_V11=PASS -BODY_ZONES_DESKTOP_HISTORY_ROW_EQUALITY=PASS -BODY_ZONES_DESKTOP_RELATIONS=32/20_EXERCISES -BODY_ZONES_DESKTOP_UNCLASSIFIED=3 -BODY_ZONES_ANDROID_INSTALL=PASS -BODY_ZONES_ANDROID_REAL_V9_COPY_TO_V10=PASS -BODY_ZONES_ANDROID_INSTALLED_DB_V10=PASS -BODY_ZONES_LIVE_MTP_ROUNDTRIP=PASS -BODY_ZONES_LIVE_MTP_SECOND_PASS_IDEMPOTENT=PASS -REAL_ANDROID_ARTIFACT_COPY_ROUNDTRIP=PASS -PC_EXPORT_ANDROID_IMPORT_THREE_PASS_COPY=PASS -ANDROID_INSTALL_R_DATABASE_HASH_PRESERVED=PASS -``` - -The real desktop v10 database was backed up with SQLite to -`backups/body-zones-v1-20260909T101310Z/trainlog-v10-before.db` under the Trainlog -user-data directory (SHA-256 -`9d5dcacd8be941be17bd3b98bbbc1815944fec9dc1b18133111ca481f50684e9`). -The production binary migrated it to v11; integrity/FK checks pass and every -row of all eight historical tables compares equal in both directions with the -backup. The migration added 32 direct relations for 20 of 23 exercises and -left Gym échauffement, Gym/Échauffement and Marche unclassified. - -The Samsung SM-G990B application data was freshly backed up before installation -under `backups/body-zones-v1-android-20260909TVFprJ8/`. The coherent v9 SQLite -copy has SHA-256 -`c402b69cdbfa4912eec1553a84754af1e892fa8da0cae6c3cbd14c4f10198401`; -its integrity check passed and its foreign-key check was empty. The installed, -built and established-keystore certificate fingerprints all matched -`aa56c97f2781a0d01f007f4444c3970deb58ad8327ca3da7b0b90f37dbe2ad25` -before `adb install -r`. The normal installed migration reached v10 with every -row of the 16 existing application tables plus `android_metadata` equal in both -directions to the v9 backup. Integrity/FK checks pass, 32 direct relations cover -20 of 23 exercises, and Gym échauffement, Gym/Échauffement and Marche remain -unclassified. - -The real Android UI displayed primary, secondary and derived-group metadata; -the chest, upper-body descendant, lower-body descendant and unclassified -filters; and the `Dos` + `lat` prefix intersection. Editing `Lat pull` -preloaded `Dos` and secondary `Bras`; cancellation left every application table -unchanged. Live sync runs `sy_0b00dc46-d899-4865-8718-c95085a380b2` and -`sy_fb0630a8-1938-4d62-9836-b0281955f625` both completed successfully. The -second run reported zero additions/reconciliations, both stores retained the -same 32-relation stable-ID hash, and Android application tables plus companion -exercise states compared equal to the first pass. Android now resolves the -exact request and every outbound artifact through direct filesystem access to -`Documents/Trainlog`. Historical numbered copies remain untouched. One -transaction-local exact-name snapshot is shared -by the complete export and request on the I/O dispatcher; each later sync takes -a fresh snapshot. The redundant application-start export was removed, and -request-ID replay protection remains authoritative. - -`TRAINLOG_ANDROID_DIRECT_STORAGE_V1=PASS`. Android no longer uses SAF for -exchange artifacts. User-enabled all-files access gates the fixed -`/storage/emulated/0/Documents/Trainlog` directory; direct temporary-file -replacement preserves canonical names. A physical Samsung Android 16 one-sync -and its identical second run completed successfully without suffixes, and the -recovered `Dos + biceps` proposal remained visible after replay. - -## Current implementation cursor - -Body Zones V1, exercise reconciliation, definition-first V2 synchronization -and the current real-data importer/exporter copy validation are complete. The -body-zone taxonomy now supplies the read boundary required by a future -zone-driven planner; no session generator or proposed-load calculation is part -of this tranche. - -```text -MEASURED_MAX_V1=PASS -WORKING_LOAD_PERCENTAGES=PASS -ANDROID_MAX_TEST_SESSION=PASS -EXPLICIT_MAX_RESULTS_V1=PASS -MAX_TEST_RESUME_STABLE_ID=PASS -CURRENT_OPERATIONAL_CURSOR=REAL_DATA_BASELINE_V1 -NEXT_FEATURE=GYM_CATALOG_V1 -``` - -Future work must start from this validated baseline rather than from obsolete -historical `NEXT` notes. - -## Measured max v1 - -```text -MEASURED_MAX_V1=PASS -MEASURED_MAX_ONLY_FROM_MAX_TEST=PASS -WORKING_LOAD_PERCENTAGES=PASS -ASSISTANCE_DIRECTION_AWARE=PASS -ANDROID_MAX_TEST_SESSION=PASS -EXPLICIT_MAX_RESULTS_V1=PASS -MAX_TEST_RESUME_STABLE_ID=PASS -DESKTOP_TESTS=58/58 PASS -``` - -A measured maximum belongs to an exercise occurrence in an explicit `max_test` -session. Schema v9 introduced the positive `max_weight_kg` separately from sets; -equipment is optional context, so one physical machine may carry independent -Pec Fly and Rear Delt Fly results. Ordinary training is never promoted -implicitly. - -The Android and TUI max forms request no set or repetition count. Android loads -a completed Test max without changing `session_id`, existing `entry_id` values, -order, exercise identity, or equipment context; finalization replaces that -session's children atomically, permits explicit value/equipment corrections, -and may append new entries. - -The current measured result is the newest successful max test. The historical -record compares max tests using the same load mode. - -External-load working percentages are pure calculations from the current -measured load; they are not persisted and no estimated 1RM is introduced. - -`PERCENT_MAX_INPUT_V1` additionally provides a user-directed 1..100 integer -calculator in desktop planning, Android ordinary set-based manual planning, and -both generator previews. It requires the exact exercise and -external-resistance equipment identity; assistance is unavailable. It uses -`MAX × percentage / 100`, makes no recommendation, and persists only the -resulting `target_weight_kg`. Automatic generation retains the frozen V1 -observed-load policy. Latest MAX means the chronologically latest explicit -result, not an aggregate record. - -## Body analytics v1 - -```text -BODY_ANALYTICS_V1=PASS -BODY_ANALYTICS_TUI_ONLY=PASS -BODY_COMPOSITION_ESTIMATE=PASS -BODY_PROPORTION_RATIOS=PASS -BODY_SYMMETRY_ANALYTICS=PASS -NO_ESTIMATE_PERSISTENCE=PASS -DESKTOP_TESTS=58/58 PASS -``` - -Android remains capture-only for this feature. - -The TUI derives analytics from canonical body observations. A local -desktop-only profile provides height and the circumference-formula branch -needed for the optional body-fat estimate. - -No estimated body-fat, fat-mass, lean-mass, ratio, or asymmetry value is stored -as if it were a real measurement. - -## Shell and naming closeout - -`SESSION_GENERATOR_V1` is technically retained but hidden from normal UI pending -V2. Manual `%MAX` remains available. `exercise-names-v1.json` supplies -movement-oriented canonical metadata for mapped stable IDs; stale peer labels -cannot overwrite those names, while custom exercise naming remains editable. -`STATS_V1=IMPLEMENTED`: Android exposes a Material 3 Catppuccin Mocha/Lavender -statistics landing dashboard with selected-period fact counts, weekly -conservative working/MAX improvement-event counts, bounded measurements, weekly -session frequency, and context-owned drill-down series. The Notcurses Statistics -route loads a bounded, transactionally consistent controller snapshot outside -rendering and presents the same global facts at wide and compact widths. Working -events compare every set only within exact exercise, resolved external equipment -and performed-dose context; equal canonical instants never create an event. A -session contributes once when it owns a -performed set, continuous activity, or explicit MAX; `ended_at` does not gate -persisted history, and plans/empty occurrences contribute nothing. Exact parsed -instants, rather than SQLite text ordering, choose and order points. Its >=100-column multi-region and 72x20 -compact layouts retain the same three detail actions. -Malformed legacy timestamps are skipped before sorting with a nonfatal dashboard -warning on both platforms. -No statistics schema or exchange-format field was added. +- `APP_SHELL_V1` still awaits the recorded human visual/accessibility review. +- AI proposal exchange still awaits one real Drive plus Android-triggered + bidirectional smoke test. +- Session Generator V1 is hidden while V2 planning semantics are developed. +- Hardware MTP validation requires a connected unlocked Android device. +- Scientific knowledge is bounded to reviewed catalog entries; unknown custom + exercises remain unclassified rather than inferred from names. diff --git a/docs/database.md b/docs/database.md index 928804b..bb849e6 100644 --- a/docs/database.md +++ b/docs/database.md @@ -17,7 +17,7 @@ is a later, separately versioned migration. ```text TRAINLOG_DATABASE_SCHEMA_VERSION=18 -DATABASE_SCHEMA_V18=IMPLEMENTED_VALIDATION_PENDING +DATABASE_SCHEMA_V18=IMPLEMENTED TRAINLOG_FORMAT_V1=FROZEN ``` diff --git a/docs/roadmap.md b/docs/roadmap.md index 9a3d76d..20650e9 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -1,523 +1,103 @@ # Roadmap -## MACHINE_EXERCISE_MODEL_V1 — implementation awaiting human review - -Phase 1 introduces additive schema v13, machine-facing exercise identities, -exercise-owned load semantics, reusable scientific profile references, exact -manifest splits, and exercise-centric Android/TUI navigation. Real database -migration remains gated on copy validation and human review. - -`EQUIPMENT_SCHEMA_CLEANUP_V1` remains a later phase after real-world -validation; it may remove obsolete legacy tables, fields, companions, and UI -only with a new explicit migration and compatibility decision. - -This file is the canonical product roadmap for Trainlog. - -Historical implementation detail belongs in Git history and `docs/reviews`. -The published Trainlog JSON v1 compatibility boundary remains frozen unless a -future feature explicitly introduces a new version. - -## TRAINLOG_AI_SESSION_DRAFT_V1 — implementation validation pending - -The implemented proposal path is deliberately separate from completed-session -exchange and the singleton capture draft. A strict single Drive source, -`TRAINLOG_AI_SESSION_DRAFT` V1, imports target-only SETS proposals into desktop -schema v18, archive-copies the exact fetched snapshot only after commit while -retaining the inbox object for logical replay, then produces the bounded -`trainlog-ai-session-drafts` V1 Android companion in deterministic batches of -at most 256 unpublished proposals. Only successful MTP publication advances -the desktop cursor; replay identities remain permanent. Android v17 retains a -pending collection, while explicit start/delete creates durable tombstones so -replay is idempotent and cannot resurrect proposals. The remaining gate is one -real Drive plus Android-triggered bidirectional synchronization smoke test; -therefore this item is `VALIDATION_PENDING` and is not PASS. - -## Completed foundation - -```text -GATE_0=PASS -GATE_1=PASS -GATE_2=PASS - -TRAINLOG_FORMAT_V1=FROZEN -DESKTOP_SCHEMA_V11=PASS -ANDROID_LOCAL_DATABASE_V10=PASS -ANDROID_LOCAL_DATABASE_V11=PASS -SESSION_GENERATOR_V1=PASS - -DIRECT_MTP_TRANSPORT=PASS -BIDIRECTIONAL_SYNC_V1=PASS - -VARIABLE_REPETITION_SETS=PASS -MEASURED_MAX_V1=PASS -EXPLICIT_MAX_RESULTS_V1=PASS -MAX_TEST_RESUME_STABLE_ID=PASS -BODY_ANALYTICS_V1=PASS -EXERCISE_EDIT_V1=PASS -ANDROID_BANNER_PARITY_V1=PASS -BODY_ZONES_V1=PASS -BODY_ZONE_SYNC_V1=PASS -BODY_ZONES_ANDROID_DEVICE_VALIDATION=PASS - -DESKTOP_TESTS=58/58 PASS (latest validated checkpoint) -TUI_NOTCURSES_V1=PASS -TRAINLOG_TUI_MEASUREMENTS_GRAPH_V1=PASS -TRAINLOG_TUI_STATISTICS_V1=PASS -TRAINLOG_TUI_STATISTICS_REFINEMENT_V1=PASS -TRAINLOG_TUI_STATISTICS_PERIOD_BUCKETING_V1=PASS -TRAINLOG_TUI_STATISTICS_PERIOD_BUCKET_SIZE_FIX=PASS -TRAINLOG_TUI_STATISTICS_CALENDAR_BUCKETS_V1=PASS -NCURSESW_REMOVED_FROM_ACTIVE_TUI=PASS -NOTCURSES_TRUECOLOR_THEME=PASS -``` - -The current product baseline includes: - -- SQLite persistence and explicit migrations; -- usable Notcurses desktop TUI; -- native Android capture client; -- exercise catalog; -- canonical hierarchical body zones, primary/secondary relations and filters; -- Android `BODY_FOCUS_HOME_V1` recent-exposure map and deterministic supported-zone ranking; -- profile-aware set and continuous activity; -- heterogeneous repetition sets; -- session history and editing; -- body measurements and body history; -- measured-max sessions and measured-max analysis; -- explicit max-weight capture without synthetic sets, with stable-ID continuation; -- desktop body analytics; -- direct USB/MTP transport; -- bidirectional Android/PC synchronization; -- safe V2 exercise-identity reconciliation with richer compatible profiles; -- supplied and custom equipment definitions with occurrence-level links; -- shared synchronization engine and `trainlog-syncd`. - -`BODY_ZONES_V1` is complete infrastructure for session generation: one shared -manifest, desktop v11/Android v10 relations, Android/TUI edit and display, -descendant-aware filters, unclassified history and one explicit-conflict sync -companion. The implemented generator uses this infrastructure; custom zones are -still outside this checkpoint and proposed loads remain editable plans rather -than actual work. - -`TRAINING_KNOWLEDGE_V1=PASS` is read-only infrastructure. Scientific review, -independent temporal review, final engineering review, repair verification, and -final executable validation passed. The temporal contract preserves source text -and exact C/Android chronological pagination; one bounded repair chain closed -the audit's stale-documentation, Android-loader, Meson-input, and role-only C -query findings. -It provides catalog-backed scientific lookup and runtime context composition -without prescriptions, schema changes or catalog seeding. The implemented -separate session generator consumes that boundary; multi-session programming is -still not a roadmap gate. See -[Training knowledge system V1](domain/knowledge_system.md). - -`EXERCISE_EDIT_V1` is a completed capture correction: Android permits -stable-ID renames, protects referenced profiles, and reconciles same-ID display -metadata without duplicates. `ANDROID_BANNER_PARITY_V1` is a presentation-only -completed checkpoint: all Android screens share the Notcurses-derived compact -header; it does not reorder the roadmap below. - -`BODY_FOCUS_HOME_V1` is a completed Android Home presentation/query tranche. -It adds no schema, sync or catalog semantics. The overview uses completed -actual work only, canonical exact-instant windows and exactly eight anatomical -child zones. Its stable order is: absent primary, oldest primary, lower primary -7d then 30d, weaker lower secondary 7d then 30d, oldest secondary, then stable -zone ID. Only zones backed by a current canonical exercise with a resolved -direct relation are eligible; unsupported zones stay visible but cannot be -recommended. It is descriptive exposure guidance, not medical recovery, -fatigue/readiness analysis or a session prescription. Session Generator V1 -remains hidden. +This document owns future work. The implemented baseline is summarized in +[current_state.md](current_state.md); completed narratives and evidence belong +in [reviews](reviews/) and [CHANGELOG.md](../CHANGELOG.md). ## Product boundary -`ANDROID_SESSION_DRAFT_V1` is an implemented P0 capture-reliability correction: -one durable active draft, Home resume, explicit discard and atomic completion. -Host and device validation and the final tranche review pass. This repair -does not introduce planning/templates or reorder the product roadmap below. - -The intended split remains: - ```text -ANDROID -= fast capture during real use - -DESKTOP TUI -= planning -+ catalog management -+ history -+ analytics -+ long-term decision support +Android captures and summarizes. +The TUI analyzes and tracks over time. +Desktop SQLite is canonical long-term history. ``` -Android must not become the main analytics surface unless this boundary is -explicitly revised later. +Future work must preserve the frozen Trainlog JSON V1 contract, stable +identities, actual-versus-planned separation, direct MTP transport, and the +distinction between measured values and estimates. -## Operational cursor — real data baseline +## Current baseline -The immediate priority is not another implementation block. +Desktop schema v18, Android schema v17, Notcurses, direct +`Documents/Trainlog` storage, mobile export V3, Training Knowledge V1, Body +Zones V1, Training Feedback V1/V2, STATS V1, and Session Generator V1 are +implemented. Session Generator V1 is hidden pending V2. AI session-draft +exchange and APP_SHELL_V1 retain their explicit manual validation/review gates. -Trainlog now needs real measurements and real training sessions so later -analytics are based on useful data rather than fixtures. +## Current cursor ```text CURRENT_OPERATIONAL_CURSOR=REAL_DATA_BASELINE_V1 ``` -Expected baseline: +Collect real body observations and training sessions through Android, sync them +to desktop, and record MAX only through explicit `max_test` results. Do not seed +fictitious user history into canonical databases. -- first complete real body observation; -- first real training sessions; -- Android used for capture; -- Android -> PC synchronization after training; -- measured max recorded only through explicit `max_test` results; -- no fictitious user data in the canonical databases. +## Next -Gate: +### Gym catalog V1 -```text -REAL_DATA_BASELINE_V1=PASS -``` +Build an inventory from the equipment actually available in the user's gym. +Keep physical equipment, exercises, movement patterns, muscles, and BODY ZONES +distinct. One photographed machine may support several exercises. Record model +or manufacturer only when evidence identifies it. -## Next feature — gym catalog v1 +### Exercise metadata V1 -```text -NEXT_FEATURE=GYM_CATALOG_V1 -``` +After the gym inventory is normalized, design any remaining structured metadata +such as movement family and laterality. Reuse existing equipment and BODY ZONES +identities; do not encode semantics in display names or notes. -The catalog must be based on the equipment actually available in the user's -gym rather than on a generic Internet exercise list. +### Session Generator V2 -The initial inventory will be built from a complete photo survey of the gym. +Replace the hidden V1 product surface with duration-aware construction that can +represent warm-up, ramp-up, main work, cool-down, transitions, setup time, and +candidate scarcity without claiming unsupported physiological precision. -For each useful equipment item, record where applicable: +### Session templates V1 -```text -gym zone -equipment family -machine name -manufacturer/model if identifiable -useful duplicate count -supported exercise(s) -Trainlog recording profile -load semantics -primary body zone (BODY_ZONES_V1) -secondary body zones (BODY_ZONES_V1) -``` +Offer editable conveniences built on the real catalogue and planning model. +Templates are not rigid prescriptions and never become performed work before +normal capture. -Important rule: +## Later -```text -one photographed machine != one exercise -``` +- evolve training analytics only where sufficient real history supports the + metric, without aggregating incomparable loads; +- add body baseline and trend comparisons while keeping direct measurements + distinct from estimates; +- add conservative, editable progression suggestions with correct external-load + and assistance interpretation; +- support explicit user objectives without mandatory gamification; +- add user-controlled dated backup and complete/period-limited exports. -A single piece of equipment may support multiple exercises. Equipment and -exercise identity must remain distinct concepts. -The primary/secondary body-zone dimension is already implemented by Body Zones -V1; gym inventory should link stable exercise identities to that model rather -than inventing another free-text body-region field. - -Gate: - -```text -GYM_CATALOG_V1=PASS -``` - -## Exercise metadata v1 - -After the real gym inventory is normalized, enrich the exercise catalog with -structured metadata needed by planning and analytics. - -Remaining candidate metadata: - -```text -equipment -movement_family -laterality -``` - -The final schema must be designed before implementation. Do not encode these -concepts into names or free-form notes as a substitute for a real model. -Body-zone metadata is no longer future scope here; its frozen V1 taxonomy and -direct relations must be reused. - -Gate: - -```text -EXERCISE_METADATA_V1=PASS -``` - -## Session generator v1 - -`SESSION_GENERATOR_V1=PASS`. -It provides -a bounded policy-driven generator in both UIs, then hands accepted nonempty -proposals to normal draft/editor flows where actual work is captured separately. -It does not create reusable templates, a planned-session sync product surface, -or a multi-session program. The one deep final audit found repairable gaps; -its bounded repairs, review, and final validation matrix passed. - -`PERCENT_MAX_INPUT_V1` is an explicit calculator layered on editable V1 targets; -it does not change automatic selection policy. Any broader multi-session, -periodized, or program-producing work is deferred to a future -`SESSION_GENERATOR_V2` and is not present today. - -## Session templates v1 - -Templates are built from the real exercise catalog and planning model. - -Candidate examples: - -```text -glutes + arms -back + shoulders -chest + arms -legs -full body -cardio -``` - -Templates are conveniences, not rigid training prescriptions. - -Gate: - -```text -SESSION_TEMPLATES_V1=PASS -``` - -## Training analytics v1 - -Implement only after enough real sessions exist to make the output meaningful. - -Candidate views: - -```text -7 days -30 days -90 days -since baseline -``` - -Candidate metrics: - -- training frequency; -- sets; -- repetitions; -- duration; -- external load; -- assistance; -- measured-max progression; -- useful volume metrics where semantically valid; -- progression by exercise. - -Use the existing Body Zones V1 read surface to aggregate by canonical body zone -and hierarchy when evaluating training balance. A separate movement-family -taxonomy, if ever needed, must be versioned rather than inferred from names. - -Gate: - -```text -TRAINING_ANALYTICS_V1=PASS -``` - -## Body analytics v2 - -Implement after multiple real body observations exist. - -Possible additions: - -- baseline comparison; -- previous-observation comparison; -- 7/30/90-day trends; -- moving-average weight trend; -- waist trend; -- anthropometric estimate trend; -- left/right asymmetry trend; -- obvious measurement-outlier warnings. - -Permanent semantic rule: - -```text -DIRECT_MEASUREMENT != ESTIMATE -``` - -Derived body-composition values remain explicitly labelled estimates. - -Gate: - -```text -BODY_ANALYTICS_V2=PASS -``` - -## Progression assist v1 - -Use accumulated history to produce conservative training suggestions. - -Examples: - -```text -external load: -stable completed work --> suggest a small load increase - -assistance: -stable completed work --> suggest a small assistance decrease -``` - -The system proposes. It does not silently change planned training. - -Measured max and estimated performance must remain distinct concepts. - -Gate: - -```text -PROGRESSION_ASSIST_V1=PASS -``` - -## Objectives v1 - -Support explicit user-defined objectives such as: - -```text -body weight -waist circumference -plank duration -exercise load -repetitions -measured max -weekly training frequency -``` - -Display current value, target, remaining difference, and trend where the data -supports it. - -Avoid mandatory gamification. - -Gate: - -```text -OBJECTIVES_V1=PASS -``` - -## Backup and export v1 - -SQLite remains canonical. - -Provide durable user-controlled export and backup: - -```text -SQLite --> dated backup --> complete JSON export --> CSV export where useful --> period-limited export -``` - -Gate: - -```text -BACKUP_EXPORT_V1=PASS -``` - -## Canonical implementation order +## Canonical order ```text REAL_DATA_BASELINE_V1 - | - v -GYM_CATALOG_V1 - | - v -EXERCISE_METADATA_V1 - | - v -SESSION_PLANNER_V1 - | - v -SESSION_TEMPLATES_V1 - | - v -TRAINING_ANALYTICS_V1 - | - v -BODY_ANALYTICS_V2 - | - v -PROGRESSION_ASSIST_V1 - | - v -OBJECTIVES_V1 - | - v -BACKUP_EXPORT_V1 + -> GYM_CATALOG_V1 + -> EXERCISE_METADATA_V1 + -> SESSION_GENERATOR_V2 + -> SESSION_TEMPLATES_V1 + -> ANALYTICS_EVOLUTION + -> BODY_ANALYTICS_V2 + -> PROGRESSION_ASSIST_V1 + -> OBJECTIVES_V1 + -> BACKUP_EXPORT_V1 ``` -This order is canonical until explicitly revised. +## Outstanding validation gates -## APP_SHELL_V1 visual-review boundary - -`APP_SHELL_V1=IMPLEMENTED_AWAITING_VISUAL_REVIEW_2`. The implemented shell does -not open STATS_V1, EXERCISE_NAMING_V1, a schema migration, or a new -synchronization feature. The remaining checkpoint is a human visual and -accessibility review of the existing seven-root shell: TUI at 72x20, 80x24, -100x25, 100x30, 120x31 and 120x35; Android at 320, 360, 393 and 412 dp, with -large system font, IME form interaction, durable-draft leave guards and -TalkBack. The `_2` suffix records the completed automated repair review only; -its human-review outcome is not recorded here in advance. +- `APP_SHELL_V1=IMPLEMENTED_AWAITING_VISUAL_REVIEW_2`: complete the recorded + human visual/accessibility matrix without redefining product semantics. +- `TRAINLOG_AI_SESSION_DRAFT_V1=VALIDATION_PENDING`: complete one real Drive + plus Android-triggered bidirectional synchronization smoke test. ## Permanent constraints -Do not regress to: - -```text -SQLite file synchronization -mandatory mounted Android filesystem -exercise-name identity heuristics -fake performed sets for continuous activity -fake uniform targets for heterogeneous actual sets -ordinary training promoted to measured max -assistance interpreted as external load -body-composition estimates presented as direct measurements -incompatible changes to Trainlog JSON v1 without a new format version -``` - -## Session generator V2 - -V1 remains technically implemented but hidden from normal UI. V2 must construct -the requested duration with warm-up, appropriate ramp-up, coherent main work, -cool-down, transition/setup time, and explicit candidate-scarcity handling. - -## STATS_V1 - -Implemented as a derived-query tranche with no summary schema: the Android -landing dashboard provides 7/30/90-day, year and all-history filters; -the performance landing graph counts weekly improvements from every performed -set under strict canonical exercise/nonempty resolved external-equipment/ -performed-dose comparison, with explicit MAX classified separately. Only a -strictly later canonical instant can improve; equal-instant IDs order display -only. Raw values remain drill-down data and are never globally aggregated -as kilograms. Body charts show only actually recorded measures; weekly frequency -uses MAX as a marker on the once-counted session. The Notcurses -landing route gives the same visual dashboard hierarchy and routes to the -existing detailed persisted views. Its controller-owned snapshot is loaded -outside rendering; wide terminals show performance, body and frequency regions -while 80x24 and 72x20 retain all three factual summaries. The selected-period -summary reports sessions, performed sets, distinct actual exercises and explicit -MAX records; body selects the latest actually observed metric, and weekly frequency counts each stable session -ID exactly once when it owns at least one persisted performed set, continuous -activity, or explicit MAX result. Planned targets and empty occurrences do not -count; `ended_at` is presentation/lifecycle metadata, not the history gate. -Exact parsed instants govern boundaries and ordering. Assistance, missing values -and incomparable equipment contexts are never coerced into progress values. -Malformed legacy timestamps are skipped by the projection with a visible warning -while valid statistics remain available. -Future equipment identification may collect manufacturer, model, name, photo, -pictogram, and notes to form a proposal which the user must verify before -persistence. OCR/image recognition and a custom-equipment relation schema are -not part of EQUIPMENT_KNOWLEDGE_V2. -## TRAINING_FEEDBACK_V1 - -Implemented for human review: schema v14, Android voice/manual append-only -capture and readback, desktop read-only consultation, and bidirectional strict -companion convergence. Automatic interpretation and recommendations remain -future scope. +Do not regress to SQLite-file synchronization, a mandatory mounted Android +filesystem, exercise-name identity heuristics, fake sets for continuous work, +synthetic uniform actuals, ordinary training promoted to measured MAX, +assistance interpreted as external load, or estimates presented as direct +measurements. Incompatible exchange semantics require a new version. diff --git a/docs/tests.md b/docs/tests.md index 2628757..484dade 100644 --- a/docs/tests.md +++ b/docs/tests.md @@ -120,8 +120,9 @@ tui_workflows app_shell ``` -The current desktop suite, including APP_SHELL_V1 production-transition -coverage and the AI-draft exchange regressions, is 56/56. The following generator-specific checkpoint counts remain +The desktop suite includes APP_SHELL_V1 production-transition coverage and the +AI-draft exchange regressions. The configured suite size and latest result are +recorded once in `current_state.md`; the following generator-specific checkpoint counts remain historical evidence: ```text @@ -234,6 +235,28 @@ Notable regression coverage: ## 5. Build +Stable-release validation additionally builds the signed release variant and +checks the packaged product versions and binary linkage: + +```bash +meson compile -C build +meson test -C build --print-errorlogs + +cd android +JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./gradlew test +JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./gradlew assembleRelease + +file trainlog-tui-linux-x86_64-v0.1.0 +ldd trainlog-tui-linux-x86_64-v0.1.0 +sha256sum trainlog-android-v0.1.0.apk \ + trainlog-tui-linux-x86_64-v0.1.0 +``` + +An unsigned release APK is build evidence only and must not be published as the +canonical stable Android artifact. Release assets must come from the exact +tagged source state, and the tag, Android `versionName`, Meson project version, +TUI product version, asset names, and release title must agree. + ```bash meson setup --reconfigure build meson compile -C build @@ -533,7 +556,7 @@ Coverage proves: and footer F6/F7 single-occurrence output at 120x35, 100x30, 80x24, and 72x20. -Historical validation checkpoint (the current desktop suite is 56/56): +Historical validation checkpoint (not the current suite size): ```text 39/39 Meson tests PASS diff --git a/docs/tui.md b/docs/tui.md index 36963df..0e64631 100644 --- a/docs/tui.md +++ b/docs/tui.md @@ -548,7 +548,7 @@ meson test -C build --print-errorlogs Validated current normal suite: ```text -39/39 Meson tests PASS +39/39 Meson tests PASS (historical checkpoint) ``` ## 16. Measured max view diff --git a/tools/export_pc_catalog.py b/tools/export_pc_catalog.py index 91ff06e..ef06267 100755 --- a/tools/export_pc_catalog.py +++ b/tools/export_pc_catalog.py @@ -1,4 +1,7 @@ #!/usr/bin/env python3 +"""Trainlog export pc catalog helper. + +Owns this command-line workflow while preserving the versioned database and exchange contracts it consumes.""" import argparse import json import os diff --git a/tools/import_mobile_export.py b/tools/import_mobile_export.py index e077246..b21c9c6 100755 --- a/tools/import_mobile_export.py +++ b/tools/import_mobile_export.py @@ -1,4 +1,7 @@ #!/usr/bin/env python3 +"""Trainlog import mobile export helper. + +Owns this command-line workflow while preserving the versioned database and exchange contracts it consumes.""" import argparse import json import math diff --git a/tools/install_syncd_user.sh b/tools/install_syncd_user.sh index 69ef2b0..6524d05 100755 --- a/tools/install_syncd_user.sh +++ b/tools/install_syncd_user.sh @@ -1,4 +1,6 @@ #!/usr/bin/env bash +# Trainlog install syncd user helper. +# Owns this command-line workflow while preserving the versioned database and exchange contracts it consumes. set -euo pipefail ROOT="$( diff --git a/tui/include/trainlog/app_shell.h b/tui/include/trainlog/app_shell.h index 215ef05..5dd0114 100644 --- a/tui/include/trainlog/app_shell.h +++ b/tui/include/trainlog/app_shell.h @@ -1,3 +1,8 @@ +/* + * Trainlog app shell interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_APP_SHELL_H #define TRAINLOG_APP_SHELL_H diff --git a/tui/include/trainlog/body_analytics.h b/tui/include/trainlog/body_analytics.h index 03eda97..a781582 100644 --- a/tui/include/trainlog/body_analytics.h +++ b/tui/include/trainlog/body_analytics.h @@ -1,3 +1,8 @@ +/* + * Trainlog body analytics interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_BODY_ANALYTICS_H #define TRAINLOG_BODY_ANALYTICS_H diff --git a/tui/include/trainlog/body_zone_catalog.h b/tui/include/trainlog/body_zone_catalog.h index ecd354c..4c052a2 100644 --- a/tui/include/trainlog/body_zone_catalog.h +++ b/tui/include/trainlog/body_zone_catalog.h @@ -1,3 +1,8 @@ +/* + * Trainlog body zone catalog interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_BODY_ZONE_CATALOG_H #define TRAINLOG_BODY_ZONE_CATALOG_H diff --git a/tui/include/trainlog/bodyviz.h b/tui/include/trainlog/bodyviz.h index 4f3bfe6..c5156eb 100644 --- a/tui/include/trainlog/bodyviz.h +++ b/tui/include/trainlog/bodyviz.h @@ -1,3 +1,8 @@ +/* + * Trainlog bodyviz interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_BODYVIZ_H #define TRAINLOG_BODYVIZ_H diff --git a/tui/include/trainlog/catalog.h b/tui/include/trainlog/catalog.h index f02ef99..b03a7a5 100644 --- a/tui/include/trainlog/catalog.h +++ b/tui/include/trainlog/catalog.h @@ -1,3 +1,8 @@ +/* + * Trainlog catalog interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_CATALOG_H #define TRAINLOG_CATALOG_H diff --git a/tui/include/trainlog/chart.h b/tui/include/trainlog/chart.h index ad8d2e4..894b4fb 100644 --- a/tui/include/trainlog/chart.h +++ b/tui/include/trainlog/chart.h @@ -1,3 +1,8 @@ +/* + * Trainlog chart interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_CHART_H #define TRAINLOG_CHART_H diff --git a/tui/include/trainlog/database.h b/tui/include/trainlog/database.h index 7f091d6..0d7cd53 100644 --- a/tui/include/trainlog/database.h +++ b/tui/include/trainlog/database.h @@ -1,3 +1,8 @@ +/* + * Trainlog database interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_DATABASE_H #define TRAINLOG_DATABASE_H diff --git a/tui/include/trainlog/duration.h b/tui/include/trainlog/duration.h index 9625312..a8a56ae 100644 --- a/tui/include/trainlog/duration.h +++ b/tui/include/trainlog/duration.h @@ -1,3 +1,8 @@ +/* + * Trainlog duration interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_DURATION_H #define TRAINLOG_DURATION_H diff --git a/tui/include/trainlog/equipment_catalog.h b/tui/include/trainlog/equipment_catalog.h index 02e357b..d0eb0a1 100644 --- a/tui/include/trainlog/equipment_catalog.h +++ b/tui/include/trainlog/equipment_catalog.h @@ -1,3 +1,8 @@ +/* + * Trainlog equipment catalog interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_EQUIPMENT_CATALOG_H #define TRAINLOG_EQUIPMENT_CATALOG_H diff --git a/tui/include/trainlog/exercise_name_catalog.h b/tui/include/trainlog/exercise_name_catalog.h index 85c777e..12a3534 100644 --- a/tui/include/trainlog/exercise_name_catalog.h +++ b/tui/include/trainlog/exercise_name_catalog.h @@ -1,3 +1,8 @@ +/* + * Trainlog exercise name catalog interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_EXERCISE_NAME_CATALOG_H #define TRAINLOG_EXERCISE_NAME_CATALOG_H diff --git a/tui/include/trainlog/id.h b/tui/include/trainlog/id.h index 2ef6b85..71953d1 100644 --- a/tui/include/trainlog/id.h +++ b/tui/include/trainlog/id.h @@ -1,3 +1,8 @@ +/* + * Trainlog id interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_ID_H #define TRAINLOG_ID_H diff --git a/tui/include/trainlog/measured_max.h b/tui/include/trainlog/measured_max.h index d9cdeba..311738b 100644 --- a/tui/include/trainlog/measured_max.h +++ b/tui/include/trainlog/measured_max.h @@ -1,3 +1,8 @@ +/* + * Trainlog measured max interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_MEASURED_MAX_H #define TRAINLOG_MEASURED_MAX_H diff --git a/tui/include/trainlog/model.h b/tui/include/trainlog/model.h index 90ce05b..c0f5f05 100644 --- a/tui/include/trainlog/model.h +++ b/tui/include/trainlog/model.h @@ -1,3 +1,8 @@ +/* + * Trainlog model interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_MODEL_H #define TRAINLOG_MODEL_H diff --git a/tui/include/trainlog/mtp.h b/tui/include/trainlog/mtp.h index 6e6cc67..3d17a80 100644 --- a/tui/include/trainlog/mtp.h +++ b/tui/include/trainlog/mtp.h @@ -1,3 +1,8 @@ +/* + * Trainlog mtp interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_MTP_H #define TRAINLOG_MTP_H diff --git a/tui/include/trainlog/reps.h b/tui/include/trainlog/reps.h index f3f4004..a8493c3 100644 --- a/tui/include/trainlog/reps.h +++ b/tui/include/trainlog/reps.h @@ -1,3 +1,8 @@ +/* + * Trainlog reps interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_REPS_H #define TRAINLOG_REPS_H diff --git a/tui/include/trainlog/session_generation.h b/tui/include/trainlog/session_generation.h index 2f26a74..237dac7 100644 --- a/tui/include/trainlog/session_generation.h +++ b/tui/include/trainlog/session_generation.h @@ -1,3 +1,8 @@ +/* + * Trainlog session generation interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_SESSION_GENERATION_H #define TRAINLOG_SESSION_GENERATION_H diff --git a/tui/include/trainlog/session_generation_policy_internal.h b/tui/include/trainlog/session_generation_policy_internal.h index bea00a7..8bed777 100644 --- a/tui/include/trainlog/session_generation_policy_internal.h +++ b/tui/include/trainlog/session_generation_policy_internal.h @@ -1,3 +1,8 @@ +/* + * Trainlog session generation policy internal interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_SESSION_GENERATION_POLICY_INTERNAL_H #define TRAINLOG_SESSION_GENERATION_POLICY_INTERNAL_H diff --git a/tui/include/trainlog/statistics.h b/tui/include/trainlog/statistics.h index cca75ac..85b5246 100644 --- a/tui/include/trainlog/statistics.h +++ b/tui/include/trainlog/statistics.h @@ -1,3 +1,8 @@ +/* + * Trainlog statistics interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_STATISTICS_H #define TRAINLOG_STATISTICS_H diff --git a/tui/include/trainlog/status.h b/tui/include/trainlog/status.h index 0cc1474..5fc8101 100644 --- a/tui/include/trainlog/status.h +++ b/tui/include/trainlog/status.h @@ -1,3 +1,8 @@ +/* + * Trainlog status interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_STATUS_H #define TRAINLOG_STATUS_H diff --git a/tui/include/trainlog/sync.h b/tui/include/trainlog/sync.h index edc0a9b..0c1fe96 100644 --- a/tui/include/trainlog/sync.h +++ b/tui/include/trainlog/sync.h @@ -1,3 +1,8 @@ +/* + * Trainlog sync interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_SYNC_H #define TRAINLOG_SYNC_H diff --git a/tui/include/trainlog/sync_history.h b/tui/include/trainlog/sync_history.h index e5f337b..f1334ae 100644 --- a/tui/include/trainlog/sync_history.h +++ b/tui/include/trainlog/sync_history.h @@ -1,3 +1,8 @@ +/* + * Trainlog sync history interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_SYNC_HISTORY_H #define TRAINLOG_SYNC_HISTORY_H diff --git a/tui/include/trainlog/sync_screen_action.h b/tui/include/trainlog/sync_screen_action.h index 59eda7e..508ac8c 100644 --- a/tui/include/trainlog/sync_screen_action.h +++ b/tui/include/trainlog/sync_screen_action.h @@ -1,3 +1,8 @@ +/* + * Trainlog sync screen action interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_SYNC_SCREEN_ACTION_H #define TRAINLOG_SYNC_SCREEN_ACTION_H diff --git a/tui/include/trainlog/terminal.h b/tui/include/trainlog/terminal.h index 085ac1e..82b2fda 100644 --- a/tui/include/trainlog/terminal.h +++ b/tui/include/trainlog/terminal.h @@ -1,3 +1,8 @@ +/* + * Trainlog terminal interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_TERMINAL_H #define TRAINLOG_TERMINAL_H diff --git a/tui/include/trainlog/theme.h b/tui/include/trainlog/theme.h index 668ee43..f56e1a0 100644 --- a/tui/include/trainlog/theme.h +++ b/tui/include/trainlog/theme.h @@ -1,3 +1,8 @@ +/* + * Trainlog theme interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_THEME_H #define TRAINLOG_THEME_H diff --git a/tui/include/trainlog/timeutil.h b/tui/include/trainlog/timeutil.h index 0749c06..161d839 100644 --- a/tui/include/trainlog/timeutil.h +++ b/tui/include/trainlog/timeutil.h @@ -1,3 +1,8 @@ +/* + * Trainlog timeutil interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_TIMEUTIL_H #define TRAINLOG_TIMEUTIL_H diff --git a/tui/include/trainlog/training_context.h b/tui/include/trainlog/training_context.h index 9a7707b..d0d4101 100644 --- a/tui/include/trainlog/training_context.h +++ b/tui/include/trainlog/training_context.h @@ -1,3 +1,8 @@ +/* + * Trainlog training context interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_TRAINING_CONTEXT_H #define TRAINLOG_TRAINING_CONTEXT_H diff --git a/tui/include/trainlog/training_knowledge.h b/tui/include/trainlog/training_knowledge.h index 5dae941..7e101a0 100644 --- a/tui/include/trainlog/training_knowledge.h +++ b/tui/include/trainlog/training_knowledge.h @@ -1,3 +1,8 @@ +/* + * Trainlog training knowledge interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_TRAINING_KNOWLEDGE_H #define TRAINLOG_TRAINING_KNOWLEDGE_H diff --git a/tui/include/trainlog/tui.h b/tui/include/trainlog/tui.h index 2a65ed3..ab3b13e 100644 --- a/tui/include/trainlog/tui.h +++ b/tui/include/trainlog/tui.h @@ -1,3 +1,8 @@ +/* + * Trainlog tui interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_TUI_H #define TRAINLOG_TUI_H diff --git a/tui/include/trainlog/usb.h b/tui/include/trainlog/usb.h index b4fed58..2a29093 100644 --- a/tui/include/trainlog/usb.h +++ b/tui/include/trainlog/usb.h @@ -1,3 +1,8 @@ +/* + * Trainlog usb interface. + * + * Declares the module boundary and ownership contract; implementation and persistence remain in their owning modules. + */ #ifndef TRAINLOG_USB_H #define TRAINLOG_USB_H diff --git a/tui/src/bodyviz.c b/tui/src/bodyviz.c index 8ed3b4b..94d64ff 100644 --- a/tui/src/bodyviz.c +++ b/tui/src/bodyviz.c @@ -1,3 +1,8 @@ +/* + * Trainlog bodyviz implementation. + * + * Owns this module's bounded behavior and does not redefine persistence, synchronization, or UI contracts owned elsewhere. + */ #include "trainlog/bodyviz.h" #include diff --git a/tui/src/database_internal.h b/tui/src/database_internal.h index a8504ac..e8c27c6 100644 --- a/tui/src/database_internal.h +++ b/tui/src/database_internal.h @@ -1,3 +1,8 @@ +/* + * Trainlog database internal implementation. + * + * Owns this module's bounded behavior and does not redefine persistence, synchronization, or UI contracts owned elsewhere. + */ #ifndef TRAINLOG_DATABASE_INTERNAL_H #define TRAINLOG_DATABASE_INTERNAL_H diff --git a/tui/src/session_generation.c b/tui/src/session_generation.c index 9e8886d..61225c0 100644 --- a/tui/src/session_generation.c +++ b/tui/src/session_generation.c @@ -1,3 +1,8 @@ +/* + * Trainlog session generation implementation. + * + * Owns this module's bounded behavior and does not redefine persistence, synchronization, or UI contracts owned elsewhere. + */ #include "trainlog/session_generation.h" #include "trainlog/body_zone_catalog.h" diff --git a/tui/src/timestamp.c b/tui/src/timestamp.c index b48d0cc..edc40cf 100644 --- a/tui/src/timestamp.c +++ b/tui/src/timestamp.c @@ -1,3 +1,8 @@ +/* + * Trainlog timestamp implementation. + * + * Owns this module's bounded behavior and does not redefine persistence, synchronization, or UI contracts owned elsewhere. + */ #include "timestamp.h" #include diff --git a/tui/src/timestamp.h b/tui/src/timestamp.h index 27b5f39..fbaa5cf 100644 --- a/tui/src/timestamp.h +++ b/tui/src/timestamp.h @@ -1,3 +1,8 @@ +/* + * Trainlog timestamp implementation. + * + * Owns this module's bounded behavior and does not redefine persistence, synchronization, or UI contracts owned elsewhere. + */ #ifndef TRAINLOG_INTERNAL_TIMESTAMP_H #define TRAINLOG_INTERNAL_TIMESTAMP_H diff --git a/tui/src/training_context.c b/tui/src/training_context.c index 96fd291..f150023 100644 --- a/tui/src/training_context.c +++ b/tui/src/training_context.c @@ -1,3 +1,8 @@ +/* + * Trainlog training context implementation. + * + * Owns this module's bounded behavior and does not redefine persistence, synchronization, or UI contracts owned elsewhere. + */ #include "trainlog/training_context.h" #include diff --git a/tui/src/usb.c b/tui/src/usb.c index 38d13e4..ad3c457 100644 --- a/tui/src/usb.c +++ b/tui/src/usb.c @@ -1,3 +1,8 @@ +/* + * Trainlog usb implementation. + * + * Owns this module's bounded behavior and does not redefine persistence, synchronization, or UI contracts owned elsewhere. + */ #include "trainlog/usb.h" #include diff --git a/tui/tests/test_body_zones.c b/tui/tests/test_body_zones.c index 701c7e6..e8c19e3 100644 --- a/tui/tests/test_body_zones.c +++ b/tui/tests/test_body_zones.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for body zones. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include #include diff --git a/tui/tests/test_bodyviz.c b/tui/tests/test_bodyviz.c index 508451a..19dc21c 100644 --- a/tui/tests/test_bodyviz.c +++ b/tui/tests/test_bodyviz.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for bodyviz. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include #include diff --git a/tui/tests/test_continuous_detail.c b/tui/tests/test_continuous_detail.c index 843f1a3..075a1ad 100644 --- a/tui/tests/test_continuous_detail.c +++ b/tui/tests/test_continuous_detail.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for continuous detail. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include #include #include diff --git a/tui/tests/test_continuous_session.c b/tui/tests/test_continuous_session.c index 49d74a2..a39d07f 100644 --- a/tui/tests/test_continuous_session.c +++ b/tui/tests/test_continuous_session.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for continuous session. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include #include #include diff --git a/tui/tests/test_equipment_catalog.c b/tui/tests/test_equipment_catalog.c index cb72318..3f42171 100644 --- a/tui/tests/test_equipment_catalog.c +++ b/tui/tests/test_equipment_catalog.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for equipment catalog. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include #include diff --git a/tui/tests/test_exercise_profile_schema.c b/tui/tests/test_exercise_profile_schema.c index 7fff91a..258a705 100644 --- a/tui/tests/test_exercise_profile_schema.c +++ b/tui/tests/test_exercise_profile_schema.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for exercise profile schema. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include #include #include diff --git a/tui/tests/test_feedback_labels.c b/tui/tests/test_feedback_labels.c index 351e5a5..c25bc4f 100644 --- a/tui/tests/test_feedback_labels.c +++ b/tui/tests/test_feedback_labels.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for feedback labels. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include "trainlog/timeutil.h" #include #include diff --git a/tui/tests/test_mtp.c b/tui/tests/test_mtp.c index 9cf1611..6e93f78 100644 --- a/tui/tests/test_mtp.c +++ b/tui/tests/test_mtp.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for mtp. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include #include diff --git a/tui/tests/test_reps.c b/tui/tests/test_reps.c index a9da918..9b32541 100644 --- a/tui/tests/test_reps.c +++ b/tui/tests/test_reps.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for reps. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include #include diff --git a/tui/tests/test_session_generation.c b/tui/tests/test_session_generation.c index e7ba351..78e7cba 100644 --- a/tui/tests/test_session_generation.c +++ b/tui/tests/test_session_generation.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for session generation. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include "trainlog/session_generation.h" #include "trainlog/database.h" diff --git a/tui/tests/test_sync_body_zone_wiring.c b/tui/tests/test_sync_body_zone_wiring.c index 5eb2093..031ecad 100644 --- a/tui/tests/test_sync_body_zone_wiring.c +++ b/tui/tests/test_sync_body_zone_wiring.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for sync body zone wiring. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include #include #include diff --git a/tui/tests/test_sync_direction.c b/tui/tests/test_sync_direction.c index d70303e..8d005b2 100644 --- a/tui/tests/test_sync_direction.c +++ b/tui/tests/test_sync_direction.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for sync direction. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include #include #include "trainlog/sync.h" diff --git a/tui/tests/test_sync_history.c b/tui/tests/test_sync_history.c index b6721e0..1861b91 100644 --- a/tui/tests/test_sync_history.c +++ b/tui/tests/test_sync_history.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for sync history. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include #include #include diff --git a/tui/tests/test_sync_screen_action.c b/tui/tests/test_sync_screen_action.c index e921f45..9148834 100644 --- a/tui/tests/test_sync_screen_action.c +++ b/tui/tests/test_sync_screen_action.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for sync screen action. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include #include diff --git a/tui/tests/test_training_context.c b/tui/tests/test_training_context.c index dcf8c01..acaa2d7 100644 --- a/tui/tests/test_training_context.c +++ b/tui/tests/test_training_context.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for training context. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include "trainlog/training_context.h" #include diff --git a/tui/tests/test_training_knowledge.c b/tui/tests/test_training_knowledge.c index 8672ce3..a701012 100644 --- a/tui/tests/test_training_knowledge.c +++ b/tui/tests/test_training_knowledge.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for training knowledge. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include "trainlog/training_knowledge.h" #include diff --git a/tui/tests/test_usb.c b/tui/tests/test_usb.c index be8dbac..ce2c4de 100644 --- a/tui/tests/test_usb.c +++ b/tui/tests/test_usb.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for usb. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include #include diff --git a/tui/tests/test_variable_sets.c b/tui/tests/test_variable_sets.c index c3caeb7..8fe68b1 100644 --- a/tui/tests/test_variable_sets.c +++ b/tui/tests/test_variable_sets.c @@ -1,3 +1,8 @@ +/* + * Regression coverage for variable sets. + * + * Exercises production contracts without owning runtime behavior or persistent formats. + */ #include #include #include diff --git a/tui/tools/mtp_exchange_probe.c b/tui/tools/mtp_exchange_probe.c index 20726ff..6301550 100644 --- a/tui/tools/mtp_exchange_probe.c +++ b/tui/tools/mtp_exchange_probe.c @@ -1,3 +1,8 @@ +/* + * Trainlog mtp exchange probe diagnostic tool. + * + * Exercises a bounded production boundary without owning application state or protocol semantics. + */ #include #include #include diff --git a/tui/tools/mtp_mobile_export_probe.c b/tui/tools/mtp_mobile_export_probe.c index 6bca502..406d5a2 100644 --- a/tui/tools/mtp_mobile_export_probe.c +++ b/tui/tools/mtp_mobile_export_probe.c @@ -1,3 +1,8 @@ +/* + * Trainlog mtp mobile export probe diagnostic tool. + * + * Exercises a bounded production boundary without owning application state or protocol semantics. + */ #include #include #include diff --git a/tui/tools/mtp_roundtrip_probe.c b/tui/tools/mtp_roundtrip_probe.c index adef925..a14d1bf 100644 --- a/tui/tools/mtp_roundtrip_probe.c +++ b/tui/tools/mtp_roundtrip_probe.c @@ -1,3 +1,8 @@ +/* + * Trainlog mtp roundtrip probe diagnostic tool. + * + * Exercises a bounded production boundary without owning application state or protocol semantics. + */ #include #include #include diff --git a/tui/tools/usb_probe.c b/tui/tools/usb_probe.c index e5f022b..3c59ae3 100644 --- a/tui/tools/usb_probe.c +++ b/tui/tools/usb_probe.c @@ -1,3 +1,8 @@ +/* + * Trainlog usb probe diagnostic tool. + * + * Exercises a bounded production boundary without owning application state or protocol semantics. + */ #include #include "trainlog/status.h"