57 KiB
Current implementation state
Private installation and Sleep PDF treatments layout
The private daily installation runs the ordered Program rescheduling rollout
from trainlog-program-recalage-v1 at 3a4ec34, with desktop schema v37,
Android schema v34, and the capability-selected trainlog-programs V2
projection. The PC/Web bundle from trainlog-sleep-pdf-treatments-space-v1
at 3758875 is served, while synchronization agents retain the compatible
Program rollout bundle. This PDF change builds on the deployed blue completed
sport overlay from e2c07f1; no Android, schema, domain, or synchronization
change accompanied it.
Firefox downloaded a four-page PDF from the served Web. All pages were rendered
and inspected. The PDF's 65 individual medication lines match its summary,
its remarks remain visible, and no extracted word exceeds the page margins.
The actual sport markers remain blue in Web, their recorded start time matches
the PDF, and the PDF retains black-outlined blue sport bands. A separate
synthetic set of 7, 14, 21, and 30 nights in French and English, plus long
continuations, was rendered page by page and checked in grayscale. Rollout
packaging requires a Meson -Dweb=enabled build with embedded frontend tests.
Full-generation synchronization uses one generation/ACK business engine across versioned transports. On the paired 0.1.4 deployment, automatic local selection is Bluetooth Classic RFCOMM first and direct USB/MTP second. The desktop BlueZ service accepts only the configured bonded Android address, Android proves the persisted Trainlog peer identity in the first bounded frame, and reconnect noise is rate-limited so proximity does not create repeated generations. MTP remains the wired recovery path. The separately configured private Drive transport remains available to its legacy mirror/fallback workflow. No transport copies SQLite.
Automatic Bluetooth restart recovery preserves the immutable generation
identity across conversation-run changes and recognizes the exact original-run
ACK by immutable generation ID and manifest digest before full SQLite
validation. An unacknowledged branch is excluded
from the bounded admission count only when a different sibling has a durable,
ledger-backed consumed acknowledgement; the superseded bytes and row remain
retained. The desktop service installer retires the exact obsolete private
ExecStart override that omitted required runtime paths and installs both
trainlog-syncd and the BlueZ RFCOMM agent.
The daemon's durable arrival ledger distinguishes admission from terminal consumption. If RFCOMM disappears after an Android request is admitted but before the generation conversation can complete, an explicitly transient terminal result leaves that same stable request eligible on reconnect. Success and non-transient business failures remain consumed, while every retry receives a fresh run identity and revalidates the existing idempotent generation/ACK evidence.
Android synchronization paths share the same concurrency-guarded generation
coordinator as SyncScreen. That coordinator has one process-wide ownership
arbiter: explicit foreground intent has priority over automatic background
resumption, while a foreground service may remain alive without owning the
conversation. An automatic run yields cooperatively at safe boundaries; its
durable generation is retained for a correlated handoff rather than deleted.
A correlated desktop rejected ACK is also terminal for the Android producer:
it is retained as durable rejection evidence, then releases the conversation
lease immediately because no reciprocal desktop generation can follow that
rejection. This keeps an explicit Web request or a later automatic Bluetooth
request from being starved by an impossible post-rejection wait.
Direct-MTP publication now has an explicit Android visibility boundary.
Durable immutable generation files are submitted to MediaProvider and all scan
callbacks complete before the mutable generation reference is published; the
reference and Android ACK use the same confirmation. Bounded diagnostic logs
contain only run/generation identities, artifact names, phases and results.
The desktop worker performs lightweight local correlation checks continuously
but opens a full MTP pull no more than once every three seconds. A 90-second
individual adapter budget is distinct from the overall conversation deadline,
so an absent correlated generation reports a protocol wait timeout while an
actually blocked adapter reports transport_timeout.
The resumed private run sy_9639f06e-58ba-4bc0-ab1b-1488aefe011c received its
desktop request and archive-ACK files, captured generation
gen_532da95e-713f-4163-acc1-d838673c33bf, and published its immutable objects
and reference with manifest SHA-256
170b55ad5bf3e44501fb506107cd26ab807d0179c95a5f1bf73f8251ea1a14e8.
Filesystem and MTP exposed the same bytes. It then waited for a desktop ACK
that could not arrive because the daemon correctly refused to create another
conversation for the already-consumed request UUID. No causal or business
mutation occurred. The remaining defect was Android ownership: an automatic
resume could hold the old run while the explicit foreground attempt failed
before publishing a fresh request UUID. The arbiter and explicit run baseline
now prevent that state.
Existing preparation rows expose separate editing and Android-delivery states and an accessible send action. Draft/local advances the same preparation to a ready revision before delivery; ready/local delivers the current revision. Completed history hides the active preparation exclusively through the delivery's stable execution-session identity and retains all provenance. Starting a delivered mixed preparation preserves continuous duration targets and set/repetition/load/rest targets in the active singleton without creating performed continuous activity, performed sets, MAX results, history, or feedback before explicit user capture. The active-session editor accepts target-only continuous and set-based occurrences: opening an existing stable entry renders its prefilled form, keeps the independent target intact on save, and leaves sibling occurrences unchanged on save or cancellation. A set-based target-only occurrence can add or change equipment without fabricating a performed set. Session completion now also turns a completed target-only continuous timeline into its measured performed duration when no supplemental field is required. Program targets remain independent from facts, so a valid execution may contain fewer or more sets and different repetitions or loads. A strictly session-bound private recovery build can supply a past factual end without retiming exercise markers or immutable heart-rate samples.
The full-generation path is operational on the paired daily installation. Bluetooth Classic is the primary local byte transport, MTP remains the wired recovery transport, and the existing private Drive namespace remains separately configured for its supported mirror/fallback path. All carry the same bounded generation/ACK artifacts and persistent peer identities; cross-transport replay is idempotent and no transport carries SQLite. The Bluetooth transport does not yet ingest heart-rate sensor data.
The public Android release chain advances from v0.1.1 versionCode 2 through
v0.1.2 versionCode 3, v0.1.3 versionCode 4, v0.1.4 versionCode 5 and v0.1.5
versionCode 6 to v0.1.6 versionCode 7 under certificate SHA-256
5ef41117da107c9805ae3215c5ec823cff06216610e6e4f7542a754161c71bd2.
Higher-numbered private validation builds used a separate Android Debug
certificate and are not members of the public update-signature chain.
TRAINLOG_NATIVE_BUILD_AND_CANDIDATE_V1 closes the native warning gate. Strict
GCC 16.2.1 and Clang 22.1.8 builds now pass the same 81-test inventory, and the
Clang ASan/UBSan build passes it with leak detection. Bounded path assembly and
the Web sync accepted response reject insufficient capacity without publishing
partial output. Fresh desktop, current-Android and schema-v17 bridge candidates
were rebuilt from code commit dd8c91a946a9c836965818d8cc35b8f8bce74658.
The rollout packager now keeps the legacy request daemon and one-shot helper in
the same relocatable, hashed bundle as the Web generation coordinator, avoiding
mixed-checkout user-service execution during the controlled rollout.
Snapshot date: 2026-09-25.
TRAINLOG_CODE_READABILITY_V1 normalizes the recent generation-MTP,
generation/ACK, Android-backup, Web Dashboard serialization, tests, doubles and
packaging workflows without changing their contracts. The scoped C formatter
check is canonical for those files only; it does not claim that the historical
repository has been globally reformatted.
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 provides its embedded application shell, Dashboard, Sessions, Programmes, Exercises, factual Analyse views, and Sleep Diary workflow 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 v36; v36 makes Sleep revision payload tables append-only; v35 gives every Sleep medication intake a structured quantity (1..99), defaulting historical rows to 1 |
| Android SQLite | schema v33; v33 makes Sleep revision payload tables append-only; v32 gives every Sleep medication intake a structured quantity (1..99), defaults historical rows to 1, and records a distinct quick-publication tip |
| Mobile snapshot | V3 active; V1/V2 readable legacy inputs; explicit V4 codec staged, not selected by transport |
| Desktop terminal backend | Notcurses only |
| Trainlog product version | 0.1.7 bugfix-only development, synchronized across Android and desktop; latest stable release: v0.1.6 |
| 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 |
| Web Dashboard visualizations | WEB_DASHBOARD_VISUALIZATIONS_V1=PASS/FROZEN |
| Web Dashboard V1 | WEB_DASHBOARD_V1=PASS/FROZEN |
| Sleep Diary V1/V2 | SLEEP_DIARY_V1=PASS remains frozen and readable. The active Sleep exchange requires sleep-diary-v2 / sleep-diary-v2.json: structured per-intake quantity and quick-publishable current revisions supplement the existing causal diary model without changing V1. Distinct concurrent V2 edits with comparable user-edit instants retain the complete latest snapshot and both immutable histories; ambiguous ordering and unsafe deletion/envelope changes still reject. |
| Web Sessions V1 | TRAINLOG_WEB_SESSIONS_V1=PASS/FROZEN (controlled desktop/Android deployment validated) |
| Web Sessions deletion and Programs V1 | TRAINLOG_WEB_SESSIONS_DELETE_AND_PROGRAMS_V1=PASS (private grouped rollout validated) |
| Programs presentation, Android projection, and deletion | TRAINLOG_PROGRAMS_PRESENTATION_ANDROID_DELETE_V1=PASS (private coordinated deployment and restart/replay validated) |
| Program execution flow | TRAINLOG_PROGRAM_EXECUTION_FLOW_V1=PASS (private coordinated deployment, real execution, correlated ACK, restart, replay, and deletion validated) |
| Web history deletion incident | TRAINLOG_HISTORY_DELETE_HTTP500_FIX_V1=PASS (private rollout, correlated full-generation exchanges, restart, retained-generation replay, and non-resurrection validated) |
| Sync orchestrator/report V1 | TRAINLOG_SYNC_ORCHESTRATOR_REPORT_V1=PASS/FROZEN |
| Web sync API V1 | TRAINLOG_WEB_SYNC_API_V1=PASS/FROZEN |
| Web sync button V1 | TRAINLOG_WEB_SYNC_BUTTON_V1=PASS/FROZEN |
| Sync Web end-to-end wrapper | TRAINLOG_SYNC_WEB_END_TO_END_V1=PASS/FROZEN (isolated) |
| Private full-generation rollout | TRAINLOG_SYNC_FINALIZATION_AND_ROLLOUT_V1=PASS (authenticated Bluetooth primary transport with direct MTP recovery on one authorized phone) |
| Local Web | TRAINLOG_WEB_V1=CONTRACT_FROZEN / IMPLEMENTATION_STARTED |
| Web Exercises V1 | TRAINLOG_WEB_EXERCISES_V1=PASS |
| Cardio persistence/sync | TRAINLOG_CARDIO_PERSISTENCE_SYNC_V1=PASS: Android v27 + desktop v30, strict optional trainlog-heart-rate V1 Android→desktop companion, generation relation and correlated ACK |
| Recovered session HR tail | TRAINLOG_HR_TRUNCATE_AFTER_SESSION_END_V1=PASS: delayed Android finalization truncates BPM/RR strictly after the inclusive factual end, and the separate trainlog-heart-rate-corrections V1 companion reuses causal state without widening frozen causal-deletions V1. The paired-device recovery for se_fa845379-794d-4bb6-8cd3-48187ebbd134 retained 3,429 BPM/RR facts through 11:16; two successive full MTP exchanges received consumed ACKs, and replay of the original 4,919-sample Heart Rate V1 artifact did not resurrect the tail. |
| Cardio BLE diagnostics | TRAINLOG_CARDIO_BLE_DIAGNOSTICS_V1=PASS: real CYCPLUS H2 validated on Android; 0x180D + 0x2A37, Battery Service, approximately 1 Hz notifications and one raw RR interval per observed notification; contact and energy fields absent in the observed payloads |
| Cardio persistent acquisition | TRAINLOG_CARDIO_PERSISTENT_ACQUISITION_V1=PASS: selected sensor persists, dedicated connected-device foreground service reconnects, stale BPM is cleared, and the global Android ♥ BPM indicator is grey/orange/green by connection state; real CYCPLUS restart and Bluetooth-off/on recovery validated on private vc40 |
| Training timeline | TRAINLOG_CARDIO_TRAINING_TIMELINE_V1=PASS: real session bounds reuse canonical lifecycle timestamps; exercise start/end are explicit user actions; live BPM samples snapshot the active stable entry_id; session finalization refuses an unclosed exercise; timeline sync is Android→desktop idempotent |
| Sleep Android one-tap | TRAINLOG_SLEEP_ANDROID_ONE_TAP_V1=PASS: one-tap Couché / medication / Réveil / Levé, guarded 10 s undo, correction route, and sleep-entry-owned cardio capture remain intact. Réveil now creates a structured 30-minute long_awake window, repeated taps extend it, and Levé clamps it. The validated V2 development delta additionally creates/reuses one 18:00-to-18:00 pending entry for pre-bed medication, reuses its stable entry_id at Couché, and exposes a compact quantity control. |
| Cardio session type | TRAINLOG_CARDIO_SESSION_TYPE_V1=PASS: Android v29 + desktop v32 use canonical session_kind=cardio; frozen mobile/history and draft formats keep legacy training/max_test; dedicated trainlog-cardio-sessions V1 syncs completed cardio sessions Android→desktop idempotently |
| Cardio calibration | TRAINLOG_CARDIO_CALIBRATION_V1=PASS: reserved system Calibration cardio exercise, real measured observed peak, ≥3 min recovery with bounded +1/+2/+3 min factual samples, immutable profile and Android→desktop calibration companion |
| Cardio BPM guidance | TRAINLOG_CARDIO_BPM_GUIDANCE_V1=PASS: absolute/calibration-derived immutable BPM targets, 2 BPM hysteresis, 3 s confirmation, stale-signal suspension, durable phase/condition history, Android live guidance UI and strict Android→desktop trainlog-cardio-guidance V1 sync |
| Cardio Web visualization | TRAINLOG_CARDIO_WEB_VISUALIZATION_V1=PASS: one bounded factual heart-rate timeline read model/HTTP endpoint powers Web History and Sleep with raw BPM/RR, real session/exercise/Sleep markers, guided targets/instructions and calibration facts; no sleep-stage or medical inference |
| Sleep tonight readiness delta | TRAINLOG_SLEEP_TONIGHT_CLOSEOUT_V1=PASS: Meson 111/111, import checks 6/6, Android testDebugUnitTest plus assembleDebug, Web 191/191 plus typecheck/build, exact V2 quantity replay, private vc47 schema-v32 migration, fresh CYCPLUS BPM and non-mutating Android/Web visual review. |
| 0.1.5 validation | TRAINLOG_0_1_5_VALIDATION_V1=PASS: native 111/111; Android unit-test task and APK build; Web 191/191 plus typecheck/build; JSON/import, C-format and diff checks pass. Private vc47 preserves real data through schema v32, renders pre-bed medication quantity controls, reconnects the CYCPLUS and presents the multi-night Web Sleep agenda. |
| Tomorrow session readiness | TRAINLOG_TOMORROW_SESSION_CARDIO_READINESS_V1=PASS: the private vc46 is clean on schema v31 with fresh CYCPLUS BPM and the next Program session is unambiguous; one combined regression proves two ordered occurrences loaded from the synchronized Program, Program provenance, factual timeline/HR ownership, finalization, full generation, desktop import, replay and correlated ACK |
| 0.1.6 validation | TRAINLOG_0_1_6_VALIDATION_V1=PASS: native Meson 114/114 and Clang ASan/UBSan 114/114; Android 317 tests (312 passed, five documented optional skips), debug APK and signed release APK; Web 32 files / 209 tests plus typecheck/build; JSON/import, changed-C formatting and diff checks pass. |
| Current operational cursor | 0.1.7 stabilization is open after immutable stable v0.1.6. Only observed bug fixes, regression fixes, directly related small UI corrections, documentation corrections, robustness, and associated tests are in scope. |
| Sleep awake/selection/PDF refinement | TRAINLOG_SLEEP_AWAKE_SELECTION_PDF_V1=PASS: one temporal projection drives agenda and selected HR detail; a separate inclusive night-start date range drives preview/export from the loaded period. The agenda axis and rows share 24 exact hour columns; estimated sleep duration is consistent and remains non-persistent. |
| Sleep Réveil interval policy | Android Réveil creates a revisioned 30-minute long_awake window; repeated taps extend it and Levé clamps it. The real 2026-09-23 night is causally repaired on Android/desktop and renders two orange intervals in agenda, HR and PDF; Android 307 passed plus five optional skips, and Web 208/208 passed. |
| Sleep revision collision recovery | TRAINLOG_SLEEP_REVISION_COLLISION_RECOVERY_V1=PASS: one unpublished divergent desktop tip was re-identified without payload loss, the immutable Android identity was restored exactly, and a fresh successor retained the non-conflicting union. The original generation was consumed with a full SQLite ACK; the real 24/09 session, Sleep facts, cardio samples, timeline, feedback, and Program provenance are visible on Desktop/Web. Schema v36/v33 and importer payload checks prevent recurrence. |
| Complete synchronization gap contract | Frozen dependency contract; operational USB/Drive slices required by v0.1.2 are delivered |
| Isolated synchronization test environment | TRAINLOG_SYNC_TEST_ENV_V1=PASS/FROZEN |
| Synchronization characterization | TRAINLOG_SYNC_CHARACTERIZATION_V1=PASS/FROZEN |
| Synchronization data/lifecycle slice | TRAINLOG_SYNC_DATA_LIFECYCLE_V1=PASS/FROZEN |
| Synchronization causal deletion slice | TRAINLOG_SYNC_CAUSAL_DELETE_V1=PASS/FROZEN |
| Synchronization generation/ACK slice | TRAINLOG_SYNC_GENERATION_ACK_V1=PASS/FROZEN (explicit staged entry points; active transport remains V3) |
| Bluetooth synchronization transport | TRAINLOG_SYNC_BLUETOOTH_TRANSPORT_V1=PASS/FROZEN; independent from future heart-rate sensor ingestion |
| Generation MTP and Android backup | Software complete and retained as the authorized wired recovery path |
Desktop and Android schema numbers are independent. Neither changes the frozen Trainlog JSON V1 contract.
The active Sleep V2 delta keeps the Web agenda period-owned: every returned
night has one row on the shared 18:00-to-18:00 geometry. Selecting a row is
presentation-only and atomically drives the detail dates, editor content, and
full-width heart-rate detail; it performs no database mutation. PDF preview
and download instead share an explicit inclusive range over night start dates,
initialized to the loaded agenda bounds and independent of detail selection.
The completed-sport overlay reads factual sessions.started_at and ended_at
from desktop history through a read-only, period-bounded paginated Web endpoint.
Each row uses its one Sleep-owned 18:00 offset and 24 elapsed-hour window for
Sleep, medication, and sport in both Web and vector PDF. Valid sport intervals
intersect [start,end) and are clipped only for display; missing or invalid
ends are point markers without invented duration. The Web keeps a separate
blue lane and accessible session list. Preview and download wait for the
complete sport read and use the same selected sessions. The PDF uses a 180 pt treatment/remarks column with 7.2 pt text,
width-aware wrapping, content-driven row heights, and dated continuation pages
for exceptional notes. Each selected intake and remark is printed once without
a fixed character limit. The shorter 430 pt timeline shares one coordinate
mapping across hour ticks, grid, sleep markers, medication markers, and blue
sport bands. The PDF prints blue
outlined bands and paginated names, factual times, and durations, marking
sessions without a corresponding Sleep row as sleep not recorded. Sport
creates no Sleep event and changes no sleep total, session, schema, or sync
contract. The HR detail's rise/fall overlays are descriptive relative measured
variation only (five-minute trailing reference excluding the current 60-second
window; threshold max(10 BPM, 15%); gaps over three seconds excluded). They
are not sleep events, sleep stages, causes, readiness, or medical inference.
The detail shares one normalized time projection with declared sleep and
awakening intervals, exact Couché/Réveil/Levé markers, medication markers, and
full-hour ticks between exact visible bounds. Medication presentation retains
unit dose and quantity as separate facts. A missing declared sleep interval
uses only a labeled, non-medical Web estimate from Couché plus 45 minutes to
Levé minus 10 minutes when both bounds exist; it never changes canonical Sleep
data. Agenda, selected-night graph, and ranged PDF consume the same projection of
sleep intervals, every structured long-awake interval, point events, medication
intakes, and bounds. The agenda renders an estimated interval with distinct
hatching, never substitutes it for a factual interval, and retains the exact
shared 18:00-to-18:00 geometry, reinforced by 24 equal hour columns shared by
every row, with each hour label centered inside the cell it names. Displayed
events use one factual night offset even when revision metadata is UTC, and
French agenda headings use DD/MM/YYYY. Displayed sleep duration is the sum of factual
sleep intervals or, in their absence, the displayed estimate minus overlapping
structured awakenings. The overlays remain available without an HR capture and
do not fabricate BPM.
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.
Schema v19/v18 now persists enriched history (ended_at, causal session,
occurrence and observation notes, and observation-to-session links), stable
execution-draft identities, bounded pending drafts and finalization ledgers.
The explicit trainlog-mobile-export V4 and trainlog-execution-drafts V1
codecs are validation-stage entry points only. The active sync engine and
Android inbox/outbox still select V3 and do not move the draft artifact.
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()remains the strict legacy V3 engine shared with the TUI and compatibility tooling. When the trusted full-generation configuration is present,trainlog-syncdadmits the Android request into the existingsync_orchestrator.py/sync_peer_worker.pyconversation; configuration absence retains the legacy fallback.- The desktop imports Android snapshots, publishes catalog/profile/feedback/AI companions, and returns a receipt. Stable IDs, artifact idempotence and the few domain-specific explicit states make defined replay paths idempotent. Explicit staged generation services now provide coherent V4/companion capture, immutable manifests, whole-generation SQLite consumption and durable peer ACKs. The Android foreground trigger now publishes a complete generation by default. A trusted desktop configuration selects the bounded production generation MTP adapter; absent configuration leaves V3 as the compatibility fallback.
- 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.
The frozen complete synchronization gap contract
remains the authority for the later orchestrator. Mobile V3 still omits
ended_at, session/occurrence/body-observation notes, the body-observation to
session link and the active Android draft. Legacy imports remain transactional
per artifact. Explicit generation consumption instead validates every listed
artifact, applies all domains and its consumption record in one transaction,
and emits consumed only after commit. A legacy receipt remains distinct from
the correlated generation ACK.
Characterization now also freezes the observed preservation of local-only
session/body values on an identical replay, loss of an occurrence-local note
when V3 correction reconstructs that occurrence, delete-before-send exposure,
request replay/receipt marking, and real inter-process lock contention. These
are current-behavior proofs, not lifecycle repairs.
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;
- complete scrollable equipment selection and caller-aware creation from an active occurrence editor, with the explicit catalogue-created ID selected on return and the occurrence identity, plan, raw form and siblings retained for in-place save;
- 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
The 0.1.6 refinement adds a persistent French/English preference and a dedicated
Settings route without moving the global synchronization action. Dashboard
activity is grouped by calendar month/ISO week, its progression tile is now a
global factual synthesis, and Analyse progresses from primary BODY ZONE to
exercise to individual detail. Exercise work time is derived exclusively from
session_exercise_timeline start/end facts; missing timelines remain unknown.
Measurements first expose unit-safe relative change cards before real-unit
detail. Dashboard and Analyse reuse the same human-proportioned BODY ZONES SVG.
The Dashboard layout keeps a 12-column canonical grid but permits every card to reach full width and several useful heights; per-card minima, overlap validation, exact save/cancel/reset semantics, and keyboard resizing remain authoritative. Settings and synchronization form the rightmost Header action cluster. Program progress uses the shared success color while retaining its factual completed/total text. Responsive charts preserve their viewBox aspect ratio, and Analyse explicitly distinguishes unavailable exercise timing from partial measured coverage instead of deriving time from sets or repetitions. The shared Sleep agenda owns one label/track/facts grid. Its 25 exact hourly positions and every event, interval and medication marker use the same coordinates: 18:00 at 0%, 00:00 at 25%, 06:00 at 50%, 12:00 at 75%, and 18:00 at 100%. Ordinary desktop widths show the 13 two-hour labels, wide layouts show all hours, and narrow layouts retain the five six-hour anchors without changing the underlying geometry.
The Equipment route projects supplied and custom definitions with exercise,
history, preparation and Program reference counts. Its guarded merge accepts a
custom duplicate only, transfers relational references in one SQLite IMMEDIATE
transaction, preserves occurrence/MAX facts indirectly through occurrence
identity, and writes the existing causal deletion boundary. An immutable
execution-draft JSON reference rejects the operation rather than being edited.
Browser mutation identities use the shared UUIDv4 helper backed by
crypto.getRandomValues(); no Web mutation depends on crypto.randomUUID(),
so http://trainlog.perf remains supported.
An execution_drafts row marked active but containing no exercises or
legacy entries is an orphaned projection, not a resumable workout. Web may
delete that exact row through the existing revision-guarded causal transaction;
the durable tombstone prevents synchronization replay from resurrecting it.
An active draft with any occurrence remains protected from Web deletion.
Generation admission archives only rows backed by an exact correlated consumed ACK and retains the newest two acknowledged lineage members. Legacy terminal Android rows that predate the durable ACK ledger are neither fabricated nor deleted, but no longer consume the active admission window. Captured, published, waiting-ACK, and current acknowledged rows continue to count until safe archival, so capacity recovery never prunes unacknowledged evidence.
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 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 uses one typed Core
snapshot, a seven-tile responsive grid, factual size-adaptive tiles, an ECharts
progression series, an original BODY ZONES SVG, and private versioned layout
persistence with optimistic conflict and CSRF/Origin protection. It provides no
automatic browser launch. Sessions provides complete paged preparation,
resume and history views, stable details, optimistic manual-preparation writes,
explicit proposal derivation and generation-backed Android delivery. The
top-level /programmes route is an operational daily active-Program calendar;
Sessions → Programmes remains the technical administration/import, list,
detail, archive, and delete surface. /exercices is the operational desktop
catalogue administration surface. /analyse is implemented with Overview,
Exercises, Distribution, and Measurements sections over one bounded Core read
model. Its global 7/30/90-day/all filter is applied in the backend; Dashboard
uses the same 30-day calculations for activity, active-Program progress,
exercise progression, measurements, and BODY ZONE links.
The Analyse API validates period, exercise identity, measurement metric and page, rejects unknown or duplicate parameters, and bounds exercises and chart points. Missing facts remain null. Exercise output respects persisted tracking/load modes, explicit MAX rows are never estimated, and duration, distance, speed, external load, and external volume appear only when their source observations support them. BODY ZONES are labelled as recorded primary zone exposures/associated sets rather than physiological percentages. All fourteen stored body metrics expose period-first, period-last, and an absolute delta only with at least two points. The route and Dashboard deep links have safe invalid-query fallbacks, French/English labels, keyboard controls, and responsive no-overflow layouts. Visual inspection remains pending before any freeze marker.
Exercises uses bounded Core-owned list/detail reads, canonical name normalization, BODY ZONES taxonomy, profiled creation/update commands and causal retirement. Its deterministic optimistic token covers all editable catalogue state. Built-in identities cannot be retired, equipment associations are presented read-only, and profile edits affect future use only: occurrence snapshots, performed sets, feedback and MAX history are never rewritten. A successful mutation changes only the canonical desktop database; the existing USB-priority, Drive mirror/fallback synchronization later carries the existing catalogue/profile/BODY ZONES/causal artifacts. No Web mutation invokes sync.
The calendar uses the existing typed Core services fetchAllPrograms(active),
fetchProgram, and createPreparationFromProgram; it derives no local program
or execution state. With no active Program it shows an empty state and
navigation to Sessions administration; with one it selects it automatically;
with several it offers a non-persisted selector. Its continuous Monday–Sunday
weeks derive from Program bounds, imported planned_for dates, and the actual
sessions.started_at instant for linked completed executions, presented on the
same browser-local civil day as Web session history. The Program detail Web API
adds the nullable read-only execution_started_at projection field; the
Programs synchronization artifact and its strict fields are unchanged. A completed
session moved from its imported date shows both dates without changing history
or Program identity. Several cards may share a day; rest days contain no
invented session. A completed execution with no valid history timestamp stays
undated rather than appearing to have occurred on its planned day. Unfinished
sessions still show their imported dates because no durable current-plan or
ceded-optional-slot state exists in the stabilized Programs exchange. It shows
all five Core execution states; only todo offers Prepare. Each Prepare result
is followed by an authoritative Core reread and may expose the returned
preparation link. This calendar adds no Android delivery, start, or execution
behavior.
Desktop schema v26 owns immutable manual-preparation revisions, stable ordered occurrences, persistent HTTP idempotency keys, delivery-to-execution identity, and durable revision-bound withdrawal records. Android schema v24 stores received preparations and permanent withdrawal results separately from AI proposals and the active singleton. Pending deliveries are cancelled by an exact V2 withdrawal; started executions are preserved. An exact correlated ACK is required before delivery or withdrawal is shown as acknowledged.
Sessions and the prepared-items Dashboard projection now share descending planned-date presentation with timestamp and stable-identity tie-breaks. Web dates default to French presentation, with an installation-local versioned ISO preference outside business SQLite and synchronization. Contextual French state labels and persisted proposal provenance replace raw enums and digest-only presentation. The preparation detail exposes a protected, idempotent Delete preparation action; withdrawn rows remain technically inspectable but cannot be edited or delivered.
Sessions rows expose independent right-edge trash actions and an accessible
destructive confirmation dialog. Proposal withdrawal preserves derived
preparations and is propagated by trainlog-ai-session-drafts V2; inactive
execution drafts and completed sessions use revision-guarded causal deletion.
Active or concurrently changed drafts conflict instead of being erased.
Program V1 is desktop-owned planning data in schema v26. The responsive Sessions Programs subtab provides cards and timeline detail backed by real imported definitions, sessions, usage, and provenance; it keeps strict bounded preview/commit import and deterministic replay/conflict behavior. A discrete, accessible trash action uses confirmation, focus restoration, and Escape-safe cancel semantics. Active and archived programs may be terminally logically deleted; sources and derived preparations remain, while deleted programs cannot resurrect or reprepare and archived programs cannot prepare.
Android schema v24 contains a read-only synchronized Programs projection with
program, session, entry, and deletion tables. Its Sessions list/detail has no
program mutation actions. The optional staged controlled-generation
trainlog-programs V1 companion publishes a PC-to-Android full nondeleted
snapshot plus unacknowledged tombstones under capability programs-v1; a
durable correlated ACK records acknowledgment. It changes neither
TRAINLOG_FORMAT_V1, mobile V3, catalog exchange, nor preparations.
Android schema v25 makes those projected sessions executable through the
existing durable singleton. Stable paired Program provenance survives draft
restart and completion. The optional Android-to-desktop
trainlog-program-executions V1 companion records in_progress or completed
against desktop schema v27 without transferring ownership of Program
definitions. Web and Android derive their session state from these persisted
identities; no display-field heuristic is used.
Android is capture-first: its drawer no longer exposes Statistics, and Home is
limited to capture, recent BODY ZONES exposure, synchronization, and body
measurements. A shared compact card/button system covers Sessions, Programs,
drafts, exercise catalog/detail/editing, synchronization, Settings, and MAX
presentation. Program list/detail surfaces show completed counts and explicit
todo/in-progress/completed states; the active editor uses exclusive side-by-
side session-type controls and compact two-column set cards. These are
presentation changes only and do not alter schemas or exchange artifacts.
Web Program administration retains revision-guarded deletion and now presents
adaptive cards plus an explicit completed-session progress indicator.
The full Android lint comparison against an isolated clean main worktree is
unchanged at ten pre-existing errors: one NewApi, one
LocalContextConfigurationRead, and eight bilingual StringFormatMatches
diagnostics. This UI tranche adds no lint error and changes no lint policy.
The stable Android v0.1.6 tag uses versionName=0.1.6 and public versionCode 7.
The v0.1.7 stabilization source starts at versionName=0.1.7 and versionCode 8.
Private validation builds may still supply only a strictly increasing
versionCode as a build-time override; that does not create a public release
or change schemas and protocols.
The private Program execution rollout installed desktop schema v27 and the
signed nondebuggable Android versionCode 17/schema v25 update without
uninstalling or clearing application data. A strictly disposable Program was
synchronized to Android, started, left and resumed through the durable
singleton, and completed as session
se_6bb66f59-a6fb-4759-a75d-c1a79ea107e8. Android displayed Effectuée and
desktop/Web received the same completed provenance through the real
program-executions-v1 producer and consumer. A second exchange created no
duplicate and no second active draft. The disposable Program was then deleted
through the revision-guarded Web command; Android retained exactly one
tombstone and desktop retained exactly one acknowledged deletion ledger row.
After both stores and the Trainlog components were reopened, exact replay of
the preserved pre-deletion Android generation returned its production durable
ACK without duplicating the execution or resurrecting the Program. A final
correlated exchange remained completed with no missing capability. The real
Program remains active and unique with 24 sessions and 164 ordered entries.
Program-owned manual preparations now carry their stable Program provenance to
Android. Starting and finalizing such a delivery retains both identities, and a
strict same-delivery enrichment repairs completed sessions produced from the
earlier omission without changing workout facts. Android and Web therefore
derive the completed count and per-session state from the same execution
identity after synchronization and restart.
The historical S1 A delivery was recovered onto its original completed
session_id; Android and Web now both report one completed session out of 24.
Generation capture also accepts its valid local continuous duration plans
without projecting them as unsupported set targets.
The private Programs rollout migrated desktop schema v25 to v26 and Android
schema v23 to v24 after verified backups, then installed the signed
non-debuggable versionCode 16 APK without uninstalling or clearing data. The
real 24-session Program remained unique and readable on Web and Android. A
clearly disposable Program was imported, synchronized, cancelled once without
mutation, then logically deleted through the Web confirmation. Android consumed
the real tombstone and desktop recorded its correlated generation ACK. A first
post-restart attempt failed before generation with device_unavailable and
PTP_ERROR_IO; no success state was recorded. Releasing the stale bounded MTP
worker and restarting the local ADB server restored the same physical peer. The
subsequent correlated exchange completed in both directions, and store reopen
confirmed one durable Android tombstone, one acknowledged desktop deletion,
no duplicate Program, and no resurrection.
The controlled deployment preserved the installed Android signing identity and
advanced its private versionCode from 13 to 14 without uninstalling or
clearing data. The requested six-occurrence validation preparation was already
started on Android at preflight, so withdrawal retained its immutable
delivery and returned execution_preserved; it did not delete or complete the
reserved execution. The source proposal retained its identity, archived
state, content and publication timestamp. Two correlated post-withdrawal
generation conversations, separated by component restart, completed without
resurrection, duplicate withdrawal, performed fact, or draft mutation.
The Next Session tile no longer treats the frozen Dashboard
next_session.available placeholder as a durable inventory. A separate bounded
GET /api/v1/prepared-items Core projection distinguishes manual preparations,
imported AI proposals, and active or pending execution drafts and exposes stable
identity, state, title/date, occurrence count, and provenance. Reload and later sync
failure do not erase the last successfully read projection. Proposal targets
remain planning data and never alter Dashboard actual-work metrics.
Full-generation MTP publication now uses a private phase-owned outbox. The
request, desktop consumption ACK, and current desktop generation are published
only when their phase requires them; retained staging, inbound objects, legacy
files, prior ACKs, and causal evidence are not recursively re-uploaded. Adapter
timeouts are persisted as the stable transport_timeout status instead of a
truncated Python traceback. The browser polls through one abortable scheduler,
orders revisions per run_id, and rejects stale responses from older runs.
The reciprocal MTP read is bounded to the Android peer advertisement, current
generation reference and consumption ACK, plus the single Android generation
named by that reference. Historical generations and other retained evidence
are neither traversed nor deleted during polling. Before peer validation, MTP
mode now requires one successful current-device pull; a retained pre-upgrade
advertisement can no longer cause a false missing-capability failure.
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. At commit
14b863eb0f159d46891f4ad5cf076b3aa0a11bba on 2026-09-17, isolated validation
passed desktop compilation, 75/75 normal Meson tests and
75/75 ASan/UBSan Meson tests, Android debug assembly and 203 Android
tests (199 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 passed in that checkpoint evidence. These are historical
results for that commit, not executions performed by later documentation work.
The four Android skips were the optional historical v9, v12, v13, and v14
database-fixture migration cases. Hardware MTP, real Drive, and Android
instrumented tests were not part of that isolated run.
For TRAINLOG_SYNC_CHARACTERIZATION_V1 on 2026-09-17, the isolated JDK 17
preflight, smoke, and full modes passed. The final full run passed desktop
compilation, 75/75 normal Meson tests, 75/75 ASan/UBSan Meson tests, the
explicit production-path sync-gap characterization, both JSON/import contract
validators, the targeted Android draft lifecycle test, Android debug assembly,
and 204 Android tests (200 passed, 4 skipped, 0 failed/error). The added
Android↔desktop↔fresh-Android V3 round trip runs inside that Android total. The
four skips remain the documented optional historical v9, v12, v13, and v14
database fixtures. No hardware MTP, real Drive, adb, instrumented device test,
user database, exchange directory, or user service participated.
For the TRAINLOG_SYNC_DATA_LIFECYCLE_V1 closeout on 2026-09-17, real staged
V4 history and execution-draft entry points completed both Android/desktop
producer directions through fresh destination databases. The closeout fixed
one Android V4 import defect that validated but failed to persist occurrence
plan fields. Isolated validation passed 75/75 normal Meson tests,
75/75 ASan/UBSan Meson tests, Android debug assembly, and 207 Android
tests (203 passed, 4 skipped, 0 failed/error). The four skips remain the
optional real historical v9, v12, v13, and v14 database fixtures. The active
transport remains V3; no phone, MTP, Drive, service, user database, deployment,
or instrumented device test participated.
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.
WEB_DASHBOARD_VISUALIZATIONS_V1=PASS/FROZEN uses a lazy, modular Apache
ECharts 6.1.0 SVG line chart for medium/large Progression tiles. Every real
point remains visible, smooth=false, legacy zeroes are preserved, and only
Core-owned improved flags alter markers. A React SVG ports the exact
normalized head, neck, and 11 front/11 back BODY ZONES paths from Android
HomeScreen.kt bodyRegions() and neckPath(). Its discrete Catppuccin colour
level still depends solely on session_count; the factual text list remains
authoritative and accessible. The figure geometry changes no zone mapping or
30-day calculation.
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 is not automated. The controlled real-device rollout
validated two consecutive post-withdrawal full-generation exchanges around a
Trainlog component restart. Android retained exactly one withdrawal result as
execution_preserved, retained the linked delivery as started, and exposed
no active preparation or start action after replay. Desktop retained exactly
one acknowledged withdrawal and no active preparation. The source AI proposal
was verified with its original identity, state, entry content and publication
timestamp; no proposal-to-execution-draft conversion was performed.
Active limitations
TRAINLOG_SYNC_CAUSAL_DELETE_V1=PASS/FROZEN provides isolated Android and
desktop producers/consumers for trainlog-causal-deletions V1. All contracted
domains are durably protected; exact replay is idempotent and unprovable or
concurrent ancestry conflicts before mutation. Protected legacy snapshots are
refused before resurrection. The default automatic daemon path remains V3,
while the trusted local Web opt-in now runs the deployed full-generation path.
Its acknowledged generations can leave the active admission window only
through the verified schema-v22/schema-v21 archive ledger; pending, rejected
and ambiguous generations remain protected.
The focused causal closeout additionally proves child-data delete/update conflicts including change-and-revert, imported built-in and alias protection, active/pending/desktop draft-revision equivalence, protected companion refusal, current-view retirement and bounded pre-effect admission. The later generation slice additively advances schemas to desktop v22/Android v21 without changing default automatic V3 selection.
The residual causal evidence also proves legitimate Android and desktop producer directions separately for exercise retirement, populated body observation deletion, custom-equipment retirement, multi-revision feedback withdrawal and BODY ZONE relation removal. Production exchanges establish each replica before deletion; stored effects, current readers, stale-companion refusal and exact replay are checked after reopening the receiving store.
The isolated closeout passed 76/76 normal Meson tests, 76/76 ASan/UBSan tests, Android debug assembly, and 211 Android tests (207 passed, four optional historical-fixture skips). Strict desktop builds use Clang 22.1.8; the compared pre-existing GCC 16.2.1 Web warning gate remains documented rather than green.
TRAINLOG_WEB_EXERCISES_V1=PASS.TRAINLOG_WEB_ANALYSIS_V1is implemented on the 0.1.4 branch and awaits the requested Dashboard/Analyse visual review.APP_SHELL_V1retains a recorded legacy visual/accessibility review gate; its observations are inputs to, not decisions for, the new 0.1.3 Android contract.- 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.