12 KiB
Current implementation state
Snapshot date: 2026-09-16.
This document owns the current implemented state. Historical checkpoints and closed incidents belong in reviews and the changelog.
Product boundary
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 administration, inspection, maintenance, import/export, and technical-tooling surface. The local Web sibling now provides its embedded application shell; its future business surfaces will own analysis, visualization, and program/session preparation through Trainlog Core.
Trainlog Core owns business truth. The desktop SQLite database remains the canonical local source of truth and long-term history; no interface owns a parallel implementation of its rules.
Versions and compatibility
| 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 |
| Trainlog product version | 0.1.2 development, synchronized across Android and desktop; latest stable release: v0.1.1 |
| Interface language | TRAINLOG_I18N_V0_1_1=PASS: French default; English selectable in Settings → Language on both surfaces |
| 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 |
| Dashboard characterization | WEB_DASHBOARD_CHARACTERIZATION_V1=PASS/FROZEN |
| Dashboard Core read model | WEB_DASHBOARD_CORE_READ_MODEL_V1=PASS/FROZEN |
| TUI Dashboard adoption | WEB_TUI_READ_MODEL_ADOPTION_V1=PASS/FROZEN |
| Web CLI/HTTP infrastructure | WEB_CLI_HTTP_INFRASTRUCTURE_V1=PASS/FROZEN |
| Web frontend shell | WEB_FRONTEND_SHELL_V1=PASS/FROZEN |
| Web Dashboard grid | WEB_DASHBOARD_GRID_V1=PASS/FROZEN |
| Web Dashboard layout | WEB_DASHBOARD_LAYOUT_V1=PASS/FROZEN |
| Web Dashboard tiles | WEB_DASHBOARD_TILES_V1=PASS/FROZEN |
| Local Web | TRAINLOG_WEB_V1=CONTRACT_FROZEN / IMPLEMENTATION_STARTED |
Desktop and Android schema numbers are independent. Neither changes the frozen Trainlog JSON V1 contract.
Language is device-local presentation state. Android keeps it in dedicated
SharedPreferences; desktop keeps it in the XDG configuration file
trainlog/presentation.conf. A successful selection updates the UI
immediately. It does not enter either SQLite database, training data, stable
IDs, schemas, exchange artifacts, synchronization protocols, AI proposals,
MAX, or feedback. User-defined exercise and catalogue names are never
automatically translated. Where a recognized stable body-zone ID has a local
presentation label, only that label is localized; unknown IDs retain their
catalogue label. Numbers, dates, and other visible formatting are owned by the
selected presentation language.
Synchronization remains a protocol boundary: core, receipt, and persisted history summaries stay opaque operational bytes. Android and the TUI render their current synchronization state from local typed status and counters; they never inject a raw cross-device French summary into the visible interface. No raw exchange or protocol format changed for interface language support.
Storage and synchronization
- Android stores capture data in its private SQLite database.
- Android reads and writes exchange artifacts only in
/storage/emulated/0/Documents/Trainlogafter the user grants all-files access through system settings. - The old SAF/tree-URI path and
Download/Trainlogare 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 andtrainlog-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
rclonefor Drive inbox/archive and read-only history export. Android owns no Drive credentials.
Android
Android currently provides:
- 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 identity-preserving continuous multi-position drag reorder, resume, confirmed discard, and atomic completion;
- completed-session consultation, transient drag reorder, and atomic factual or order correction while retaining session/occurrence/feedback identities for synchronization;
- exercise catalogue editing with stable
exercise_idand 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, locally rendered typed receipt status/counters, and companion application.
- French-default/English-selectable presentation from Settings → Language, applied immediately without changing repository or synchronization state.
Android does not own canonical long-term analytics. The V1 session generator is implemented but intentionally hidden from normal navigation pending V2.
Desktop TUI
The desktop is a strict C17 application using Notcurses. It currently provides:
- 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 locally rendered typed synchronization status/history through the shared engine.
- French-default/English-selectable presentation from Settings → Language, including selected-language formatting without changing canonical data.
Rendering is not permitted to own SQL or business rules. Statistics are
read-only projections; they are not persisted as facts. The former Dashboard
exception is resolved: its typed Core read model owns the SQLite projection and
all characterized calculations, while the TUI supplies query state and renders
the result. The Web aggregate now exposes the distinct factual snapshot through
GET /api/v1/dashboard without changing the frozen TUI projection.
Local Web
TRAINLOG_WEB_V1 architecture, API independence, local-network boundary,
browser shell, Dashboard, layout ownership, build/runtime separation, and
security invariants are canonical. The CLI/local HTTP infrastructure and
embedded frontend shell are implemented: -w/--web, optional --port, exact
IPv4 loopback binding, /api/v1/health, React navigation and the persistent
Header/Body/Footer shell. Production assets are generated from the npm lockfile
and linked into the binary. The read-only Dashboard business snapshot and
factual Footer integration exist; no grid engine, business mutation, automatic
browser launch or layout persistence exists yet.
Data semantics
exercise_ididentifies a catalogue exercise;entry_ididentifies 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.
Validation status
The durable commands are owned by tests.md. On 2026-09-15 final
validation passed desktop compilation, 60/60 normal Meson tests and
60/60 ASan/UBSan Meson tests, Android debug assembly and 202 Android
tests (198 passed, 4 skipped, 0 failed), the JSON validator, and the
import-contract validator. The source-derived TUI
TRANSLATABLE_UI=0 check and Android resource parity also passed. Link and
diff safety checks pass in the final audit evidence.
The Dashboard Core extraction tranche passes 62/62 normal Meson tests and 62/62 ASan/UBSan Meson tests, including the standalone public-header and Core characterization targets, plus both canonical JSON validators.
The CLI/HTTP infrastructure tranche passes 67/67 normal Meson tests, adding pure CLI parsing, process-level help/version checks and an isolated loopback HTTP lifecycle/security suite. The same suite is required under ASan/UBSan.
The frontend shell tranche passes 70/70 normal and ASan/UBSan Meson tests,
including TypeScript typecheck, 10 Vitest component tests, deterministic asset
generation bounds, real embedded-asset HTTP coverage, SPA/API separation and
runtime execution without Node/npm or web/dist.
The Dashboard data-contract tranche passes 71/71 normal and ASan/UBSan Meson tests, including the bounded Core/JSON target, HTTP endpoint coverage and 12 Vitest tests for parsing and factual Footer integration.
WEB_DASHBOARD_GRID_V1=PASS/FROZEN uses react-grid-layout 2.2.4 behind an
independent Trainlog model/validator. Its 12-column desktop layout has seven
stable tile IDs, bounded per-tile dimensions, vertical collision compaction,
explicit edit/cancel/reset behavior, mouse drag/two-axis
resize, an announced keyboard alternative, and derived six/one-column
responsive projections. Persistence is supplied by the following frozen slice.
WEB_DASHBOARD_LAYOUT_V1=PASS/FROZEN adds a strict versioned seven-tile file
under the private XDG configuration directory, backend revalidation, atomic
0600 replacement, ETag/If-Match conflict control, Origin plus ephemeral CSRF
protection, and durable React load/save/reset behavior. Only the desktop
12-column canon persists.
WEB_DASHBOARD_TILES_V1=PASS/FROZEN renders all seven domains from the one
validated /api/v1/dashboard snapshot. Compact, medium and large densities
only reveal existing facts. Activity uses a factual CSS day map, MAX lists are
bounded 1/3/8, and muscle bars encode session_count only. Unavailable,
partial, invalid and transport-error states never synthesize values.
TRAINLOG_I18N_V0_1_1=PASS is covered by desktop presentation, persistence,
formatting, layout-invariance and source-derived text-boundary tests, plus
Android resource-parity, language-owner, typed sync-presentation, and
stable-data presentation tests. A real-device/manual visual language-switch
smoke remains a manual validation; it does not change the validated status.
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.
Active limitations
WEB_DASHBOARD_VISUALIZATIONS_V1: advanced curves and muscle visualization remain future work; Tile V1 intentionally uses bounded text, CSS and direct factual encodings without ECharts.APP_SHELL_V1still 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.