1371 lines
83 KiB
Markdown
1371 lines
83 KiB
Markdown
# Changelog
|
||
|
||
## Unreleased — 0.1.7
|
||
|
||
The isolated `trainlog-program-recalage-v1` candidate adds an explicit
|
||
preview-and-confirm cascade for unfinished Program sessions. It retains source
|
||
and actual dates, stores absolute current dates and ceded-slot state, and
|
||
selects a separate Programs V2 Android projection by capability. This candidate
|
||
is not merged into the stable installation or deployed to Android.
|
||
Rollout packaging now rejects a native build without the embedded Web frontend.
|
||
|
||
Development opened after the stable v0.1.6 release. This line is restricted to
|
||
observed bug fixes, regression fixes, directly related small UI corrections,
|
||
documentation corrections, robustness, and associated tests. It does not admit
|
||
new features, modules, protocols, or speculative refactors.
|
||
|
||
- Corrected the Web Program calendar's completed-session placement using the
|
||
linked session's actual start date in the browser's history timezone. A
|
||
changed day displays both actual and imported dates, and concurrent cards
|
||
remain distinct. The Program detail Web API gains a nullable read-only
|
||
timestamp field; this changes no history, schema, Android behavior, or sync
|
||
artifact.
|
||
Durable ordered rescheduling remains outside the stabilized Programs V1
|
||
exchange: its strict snapshot has no current date or ceded-slot state.
|
||
- Fixed automatic Bluetooth synchronization recovery when RFCOMM disconnects
|
||
after `trainlog-syncd` admits Android's arrival request but before the
|
||
generation conversation can start. Requests whose durable terminal result
|
||
is explicitly transient (`device_unavailable`, `transport_timeout`,
|
||
`sync_in_progress`, or interruption) remain eligible after reconnect;
|
||
completed requests and business failures remain consumed. Generation, ACK,
|
||
causal, schema, MTP, Drive, and manual-sync contracts are unchanged.
|
||
- Fixed Android generation coordination after a durable desktop rejection.
|
||
The Android producer now retains and reports the correlated `rejected` ACK
|
||
but immediately releases its conversation lease instead of waiting for a
|
||
reciprocal desktop generation that the rejecting worker cannot publish.
|
||
This prevents a rejected stale revision from starving a subsequent Web or
|
||
automatic Bluetooth request; rejection, generation, ACK, causal, schema,
|
||
and transport contracts are unchanged.
|
||
- Preserved the desktop consumer's known Sleep revision rejection diagnostic
|
||
through the full-generation worker and classified it as `data_conflict` in
|
||
Web run state. A synthetic divergent-final-wake regression keeps the true
|
||
conflict rejected; this reporting fix does not reconcile real Sleep data or
|
||
turn a rejected generation into a successful exchange.
|
||
- Resolved safely comparable concurrent Sleep V2 edits by the last actual
|
||
user-edit instant, regardless of device or the event times being recorded.
|
||
Complete winning snapshots and both original immutable revisions are kept;
|
||
a local winner gains a fresh causal successor for peer convergence. Equal
|
||
timestamps, changed entry envelopes, and deletion transitions still reject
|
||
instead of guessing. Existing rejected generation ACKs are not rewritten.
|
||
|
||
## 0.1.6 — 2026-09-25
|
||
|
||
- Corrected delayed session finalization so a heart-rate capture cannot extend
|
||
beyond the explicit factual session end. Android now transactionally removes
|
||
strict post-end BPM/RR tails while retaining an exact-cutoff sample. For an
|
||
already acknowledged capture, the separately versioned
|
||
`trainlog-heart-rate-corrections` V1 companion carries an immutable
|
||
`capture_id|cutoff` correction through the existing causal ledger without
|
||
widening frozen causal-deletions V1. Old Heart Rate V1 generation replay
|
||
applies that cutoff before identity comparison and cannot resurrect removed
|
||
measurements. A guarded dry-run recovery tool reports before/after counts and
|
||
statistics without rewriting published manifests or ACKs.
|
||
- Completed the paired-device recovery for session
|
||
`se_fa845379-794d-4bb6-8cd3-48187ebbd134`: Android and desktop now retain
|
||
3,429 BPM samples and 3,429 RR values through the inclusive 11:16 cutoff,
|
||
and two successive full MTP generation exchanges completed with durable
|
||
consumed ACKs. Replaying the original 4,919-sample artifact cannot restore
|
||
the removed tail. Generation parent selection now excludes archived or
|
||
legacy acknowledgement rows lacking durable ACK evidence, while consumers
|
||
accept the producer's declared parent when it is one of multiple retained
|
||
current tips. Android Sleep V2 persistence also names medication-intake
|
||
columns explicitly, preserving `quantity`, note, and creation time across
|
||
the additive v33 layout.
|
||
|
||
- Recovered a real divergent Sleep revision identity without choosing an
|
||
arbitrary winner. The unpublished desktop branch was re-identified with its
|
||
exact content, the immutable Android revision retained its published ID and
|
||
parent, and a fresh successor preserved the non-conflicting qualities,
|
||
events and medication occurrences. The original immutable generation now
|
||
has a `consumed` / `sqlite-commit-full` ACK and the repaired 24 September
|
||
session is available through Desktop and Web with its timeline, feedback,
|
||
cardio and Program provenance.
|
||
- Added Desktop schema v36 and Android schema v33 append-only guards for Sleep
|
||
revision payloads. Both importers now reject a known historical revision ID
|
||
whose parent or canonical content differs, even when that revision is below
|
||
the current tip. A dedicated transactional recovery utility and regressions
|
||
cover exact replay, parent/content collisions, medication quantities,
|
||
rollback, immutable generation retry, and long UUID/parent chains.
|
||
|
||
- Fixed Android finalization of Program-derived sessions containing a completed
|
||
target-only continuous occurrence. The repository now materializes the
|
||
performed duration from the persisted exercise timeline, including preserved
|
||
drafts closed by an older build, while keeping planned set counts independent
|
||
from valid actual sets, repetitions and loads. A strictly identity-bound
|
||
private recovery build may supply the factual session end; strict late
|
||
heart-rate BPM/RR tails are now removed transactionally at that boundary.
|
||
- Hardened desktop Sleep generation consumption when an identical durable
|
||
revision has no local publication row. Content comparison now reads the
|
||
durable revision directly, acknowledges an exact match, and reports a real
|
||
revision-identity conflict instead of an empty rejection diagnostic when the
|
||
same ID carries different content.
|
||
|
||
Development opened after the stable v0.1.5 release. The Web refinement tranche
|
||
adds persistent French/English settings, denser shared surfaces, ISO-week
|
||
Dashboard activity, factual exercise-count overview charts, measured-timeline
|
||
muscle-group drill-down, normalized measurement summaries, one shared refined
|
||
BODY ZONES silhouette, and a compact Program header. A new Equipment workspace
|
||
lists factual references and transactionally absorbs a custom duplicate into a
|
||
canonical identity while retaining history/MAX context and recording a causal
|
||
deletion marker; immutable embedded drafts cause an explicit conflict.
|
||
The post-review correction keeps acknowledged-generation capacity recoverable
|
||
for legacy Android rows without ACK-ledger evidence, proves two successive
|
||
Sleep-only generation/ACK exchanges, and never evicts an unacknowledged
|
||
generation. Web can now causally remove only an orphaned zero-occurrence active
|
||
draft while retaining protection for real active drafts. Mutation UUIDs use
|
||
`crypto.getRandomValues()` on loopback HTTP origins. Sleep timeline geometry,
|
||
Dashboard sizing, Program progress contrast, chart proportions, duration
|
||
coverage messaging, and the right-aligned Settings/Sync action cluster are
|
||
also refined.
|
||
|
||
- Restored automatic Sleep-only Bluetooth synchronization after a real-night
|
||
trace exposed several restart and first-import gaps. The user-service
|
||
installer now removes only its obsolete `syncd` ExecStart override and
|
||
installs the RFCOMM agent;
|
||
Android resumes the same unsuperseded immutable generation across a new
|
||
conversation run and accepts its exact generation/digest ACK even though
|
||
the immutable ACK retains the original run identity. Ledger-proven
|
||
superseded branches remain retained without exhausting admission. Desktop
|
||
progress validation accepts the existing ACK-recovery phase, and a fresh
|
||
desktop can seed a non-root Sleep V2 current snapshot when its validated
|
||
ancestry is present. Regression
|
||
coverage carries medication quantity, Couché/Réveil/Levé and Sleep BPM/RR
|
||
through import, ACK, replay and a second Sleep-only generation with no
|
||
Android workout session.
|
||
- Enriched the selected Sleep night's heart-rate chart with declared sleep
|
||
ranges, explicit awakening ranges and point events, medication markers that
|
||
preserve unit dose and quantity, exact start/end bounds, and every
|
||
intervening hourly tick. When no declared sleep interval exists, the Web
|
||
presentation alone shows the conservative bedtime +45 minutes to final
|
||
get-up -10 minutes estimate, labels it as estimated/non-medical, and never
|
||
writes it to Sleep data. Nights without synchronized HR retain these factual
|
||
and estimated timeline overlays without inventing BPM samples. The private
|
||
`trainlog.perf` deployment and read-only Firefox smoke validate the latest
|
||
real HR night and the latest real night containing medications from code
|
||
commit `2ce458d`.
|
||
- Reused that same read-only fallback projection in the multi-night Sleep
|
||
agenda, with a visibly estimated hatched interval and no Sleep write. The
|
||
agenda now derives an exact 18:00-to-18:00 hourly grid, presents at least
|
||
two-hour labels on ordinary desktop widths, expands to every hour when wide,
|
||
and reduces to six-hour anchors on narrow screens. A read-only real-device
|
||
investigation of the 2026-09-23 night found no medication intake in any
|
||
retained local revision and established that later synchronization only
|
||
published the already-empty current revision. Android regression coverage
|
||
now proves two pre-bed intakes, including quantity two, through repeated
|
||
repository reopen, bedtime, wake, final get-up, generation, desktop ACK,
|
||
replay, stale-ancestor input and a subsequent revision. The private service
|
||
serves Web code commit `a60e1aa`; a non-mutating Firefox smoke on the real
|
||
night confirms the identical 22:50–04:04 agenda/detail projection and the
|
||
responsive 13/25/5-label axis densities.
|
||
- Unified the Web Sleep agenda, selected-night HR detail, and vector PDF on one
|
||
temporal projection. Every structured long-awake interval remains a distinct
|
||
band, row selection updates the detail dates and content without persistence,
|
||
and preview/download export exactly the active night with observations
|
||
recomputed for that subset. Sleep duration now consistently sums factual
|
||
sleep intervals or, only when none exist, uses the displayed Couché +45 min
|
||
to Levé -10 min estimate minus structured awakenings; the estimate is never
|
||
written to SQLite.
|
||
- Changed future Android one-tap Réveil capture from punctual `night_get_up`
|
||
facts to structured `long_awake` windows under the user-approved 30-minute
|
||
default. A repeated tap inside the window extends its end to 30 minutes after
|
||
the latest tap, while Levé clamps it to the factual final-get-up timestamp.
|
||
The policy is revisioned, undoable, and independent of BPM/RR inference.
|
||
- Centered the Sleep agenda's hour labels inside a shared 24-column visual grid
|
||
and added an inclusive night-start date range for PDF preview and export.
|
||
The duplicate terminal `18` is removed; detail/HR night selection remains
|
||
independent from the report range, whose date fields now use a grouped
|
||
Trainlog form treatment.
|
||
- Fixed a real Sleep agenda offset bug when revision metadata used UTC `Z` but
|
||
factual events used the user's local offset: the row now anchors its complete
|
||
18:00 axis to one factual night offset. Agenda night headings use French
|
||
`DD/MM/YYYY` rather than persistence-oriented ISO dates in the French UI.
|
||
|
||
## 0.1.5 — 2026-09-23
|
||
|
||
- Completed the Sleep Tonight readiness delta and its non-destructive private
|
||
vc47 rollout. Pre-bed medication now creates or
|
||
reuses one durable pending 18:00-to-18:00 Sleep entry; Couché appends bedtime
|
||
to that same stable identity, while Réveil/Levé remain unavailable before
|
||
bedtime. Pending quick facts are publishable through a distinct marker and
|
||
are not day validation.
|
||
- Added structured per-intake medication quantity (`1..99`) in Android schema
|
||
v32 and desktop schema v35. The active `trainlog-sleep-diary` V2 companion
|
||
(`sleep-diary-v2.json`) carries quantity; frozen V1 remains readable and
|
||
interprets missing quantity as one. Per-unit dose/unit remain separate from
|
||
quantity, which is rendered in Android, Web and PDF as appropriate (for
|
||
example `75 mg ×2`).
|
||
- Kept sleep HR capture factual and sample-driven: pre-bed medication alone
|
||
creates no capture; the first real post-Couché sample opens/reuses the
|
||
entry-owned capture at bedtime; Réveil does not split it; and Levé closes it
|
||
exactly at final get-up. A no-sensor night fabricates neither capture nor
|
||
sample.
|
||
- Updated the Web Sleep agenda to render every returned night in the selected
|
||
period on one shared 18:00-to-18:00 axis. Row selection is navigation only
|
||
and shows the selected entry’s full-width HR detail. Relative measured HR
|
||
rises/falls use a trailing five-minute reference excluding the current
|
||
60-second window, thresholds of `max(10 BPM, 15%)`, and ignore gaps over
|
||
three seconds; labels remain descriptive and make no sleep-stage, medical,
|
||
or causal inference.
|
||
|
||
- Added the Cardio V1 persistence/synchronization foundation. Android schema
|
||
v27 owns durable timestamped heart-rate captures, samples and raw RR values;
|
||
desktop schema v30 imports the optional `trainlog-heart-rate` V1 companion
|
||
transactionally. Exact generation membership is retained until a correlated
|
||
consumed ACK, after which those stopped captures remain local history but are
|
||
excluded from ordinary re-publication. Desktop/Web remain sensor consumers
|
||
only; Bluetooth Classic Trainlog synchronization is unchanged.
|
||
- Added the Android Heart Rate Service diagnostic foundation. The independent
|
||
`0x2A37` parser covers 8/16-bit BPM, contact, energy and raw RR flags with
|
||
strict malformed-payload rejection. A settings diagnostic provides bounded
|
||
HRS-filtered and expanded BLE scans, GATT service discovery and notification
|
||
subscription without turning desktop/Web into sensor clients. Android 12+
|
||
scan/connect permissions and the Android 11-and-older scan-location boundary
|
||
are explicit. Real CYCPLUS H2 characterization then confirmed the standard
|
||
service/measurement path, Battery Service, ~1 Hz notifications and raw RR.
|
||
- Added persistent Android heart-rate acquisition and the global `♥ BPM`
|
||
indicator. A validated sensor is remembered, a dedicated connected-device
|
||
foreground service reconnects across app restarts and Bluetooth loss, stale
|
||
measurements are cleared instead of displayed indefinitely, and the heart
|
||
uses grey/orange/green for disconnected/reconnecting/fresh states. The real
|
||
CYCPLUS H2 was validated through force-stop/restart and Bluetooth off/on
|
||
recovery on the private 0.1.5 versionCode 40 installation.
|
||
- Added the training execution timeline used for cardio correlation. Android
|
||
schema v28 records explicit start/end actions for stable exercise occurrences
|
||
while preserving the session lifecycle `started_at`/`ended_at` as canonical
|
||
bounds. Only one exercise can be active; session finalization refuses an
|
||
unclosed occurrence. Live heart-rate samples snapshot the active `entry_id`,
|
||
rest intervals remain unowned, and the optional `trainlog-session-timeline`
|
||
V1 companion imports idempotently into desktop schema v31.
|
||
- Added Android one-tap Sleep capture on top of the existing Sleep Diary V1:
|
||
Couché, active medication buttons, point Réveil events and Levé each record
|
||
the current timestamp in one action. A guarded short-lived Annuler creates a
|
||
causal compensating revision, while Corriger la nuit retains the complete
|
||
editor. Heart-rate acquisition links directly to the stable sleep `entry_id`
|
||
and closes at Levé; no return-to-sleep or sleep-stage inference is added.
|
||
- Added the true `cardio` session type without widening frozen session
|
||
codecs. Android schema v29 and desktop schema v32 introduce canonical
|
||
`session_kind=training|max_test|cardio` while the historical
|
||
`session_type` compatibility column remains `training|max_test`.
|
||
Completed cardio sessions are excluded from `history-v4` and move through
|
||
the separate optional `trainlog-cardio-sessions` V1 generation companion;
|
||
exact replay is idempotent and identity collision with non-cardio history is
|
||
rejected.
|
||
|
||
- Added the first versioned Cardio calibration workflow. Android schema v30 creates one reserved system exercise outside the normal exercise catalogue, starts a real cardio session and HR capture, records only measured observed peak BPM, and requires at least three minutes of recovery. +1/+2/+3 minute recovery facts accept only real samples within a bounded ten-second window; missing signal therefore remains missing instead of being backfilled from a later reconnect. Completed immutable profiles synchronize Android→desktop through `trainlog-cardio-calibrations` V1 into desktop schema v33, where the importer proves peak and recovery points against the synchronized raw HR capture before accepting them.
|
||
|
||
|
||
- Added fresh-signal BPM-guided cardio phases. Android schema v31 stores
|
||
ordered phase runs against the active cardio occurrence, immutable resolved
|
||
BPM targets, optional exact calibration provenance, exit conditions and
|
||
instruction changes. The engine uses a 2 BPM hysteresis band and a 3-second
|
||
confirmation interval to avoid boundary oscillation; stale signal suspends
|
||
guidance immediately and never reuses an old BPM. Android exposes live
|
||
Accélère / Maintiens / Ralentis guidance during the active cardio exercise.
|
||
Completed runs synchronize once through `trainlog-cardio-guidance` V1 into
|
||
desktop schema v34. Desktop verifies cardio-session ownership, exercise
|
||
timeline, calibration provenance and exact raw HR evidence for instruction
|
||
events carrying BPM before accepting them.
|
||
|
||
- Fixed live Cardio guidance after changing an already-started manual draft
|
||
from Training to Cardio. Draft persistence now atomically reconciles the
|
||
same active heart-rate capture from `session` to `cardio` without replacing
|
||
its identity or losing existing BPM/RR samples and sequence. A transition
|
||
away from Cardio remains possible before Cardio-only facts exist, but is
|
||
rejected once durable guidance or calibration facts would make it
|
||
ambiguous. Repository coverage reproduces the real ordering through an
|
||
active exercise and guidance event. The private vc46 re-smoke retained the
|
||
original capture and more than 31 existing samples across the transition,
|
||
then displayed a measured 92 BPM and `ACCÉLÈRE`; the Sommeil and Calibration
|
||
cardio screens also rendered without creating persistent data.
|
||
|
||
- Added one end-to-end tomorrow-session readiness regression. A synchronized
|
||
Program session retains its stable session and Program identities through
|
||
edits, two ordered Program-derived occurrence intervals,
|
||
pre-exercise/inter-exercise/active heart-rate ownership, finalization,
|
||
full-generation publication, desktop import, replay and correlated ACK. Raw
|
||
observation timestamps, BPM, RR, nullable stable exercise ownership and
|
||
capture/session bounds are compared on both platforms without inferring
|
||
ownership from time overlap.
|
||
|
||
- Added factual synchronized heart-rate timelines to the local Web. One bounded C17 read model and loopback GET endpoint now project raw BPM/RR measurements with canonical workout exercise intervals or Sleep Diary/medication markers. Cardio history additionally presents resolved phase targets, instruction changes and calibration peak/recovery facts. History and Sleep reuse one responsive SVG component; full-sample min/max/mean statistics remain exact while only very large chart projections retain bounded bucket extrema. No sleep stage, HRV, readiness or medical inference is added.
|
||
|
||
Development opened after stable v0.1.4 release.
|
||
|
||
## 0.1.4 — 2026-09-22
|
||
|
||
- Added the frozen Bluetooth Classic RFCOMM synchronization transport without
|
||
changing full-generation business semantics. The paired deployment selects
|
||
Bluetooth before MTP, authenticates the configured bonded Android peer with
|
||
the persisted Trainlog peer identity, rate-limits reconnect noise, and keeps
|
||
MTP as the wired recovery transport. This transport is for Trainlog data
|
||
synchronization only; heart-rate sensor ingestion remains future 0.1.5 work.
|
||
- Refreshed the Web next-session projection after synchronization and added
|
||
factual body-measurement trend charts through the existing bounded analysis
|
||
read model without introducing health interpretation or estimated metrics.
|
||
- Fixed Program progress for sessions started from a delivered manual
|
||
preparation. The preparation companion now carries its stable Program and
|
||
Program-session provenance through Android start, finalization, restart and
|
||
the existing execution companion; legacy stored deliveries are safely
|
||
enriched only when every pre-existing field and execution identity matches.
|
||
Android and Web consequently present the completed session and progress from
|
||
the same persisted identity without fabricating history.
|
||
Historical acknowledged deliveries now complete that recovery on the
|
||
original session even when the preparation contained planned continuous
|
||
activities, and current sleep snapshots can initialize a fresh peer from a
|
||
non-root revision without discarding causal identity.
|
||
- Aligned the Sleep Diary Agenda ticks, interval bands and point markers on one
|
||
exact 18:00-to-18:00 timestamp projection. Selecting another night now clears
|
||
the previous entry immediately, adopts only an exact-date result and rejects
|
||
stale out-of-order reads; an absent night remains unpersisted and empty until
|
||
the first real edit. The editor presents local completion as Draft,
|
||
Day validated or Modified without exposing synchronization transport state.
|
||
- Fully localized the French Sleep Diary PDF without changing its canonical
|
||
data source or event semantics. Column headings, timeline labels, legend,
|
||
factual summary, draft warning, dates and plurals are now French, accented
|
||
text uses the PDF WinAnsi encoding, and durations use human-readable units.
|
||
Long awakenings remain proportional intervals between independent sleep
|
||
ranges, while medication intake snapshots retain localized dose and unit.
|
||
The English report keeps an independent English vocabulary.
|
||
- Made the Sleep Diary Agenda a live projection of the latest locally
|
||
persisted entry revision. Event and intake mutations now re-read and adopt
|
||
the canonical Core snapshot, serialized autosaves carry the returned
|
||
revision forward, and stale asynchronous reads cannot regress the visible
|
||
state. The Agenda shows factual bedtime, final get-up, declared-sleep and
|
||
time-in-bed durations, long awakenings, naps, sleepiness and grouped
|
||
medication markers without requiring reload or publication. Medication
|
||
catalog entries and selectors now include their usual localized dose and
|
||
unit, keep same-name/different-dose records distinct, and prefill editable
|
||
intake doses. Schemas, domain semantics, synchronization and PDF generation
|
||
are unchanged.
|
||
- Fixed the Sleep Diary Web workspace becoming entirely blank after adding an
|
||
event or medication intake on the loopback-routed HTTP origin. Sleep event
|
||
and intake UUIDv4 identities now use secure random bytes without depending
|
||
on the secure-context-only `crypto.randomUUID()` API, and a section-local
|
||
error boundary preserves the Trainlog shell if an unrelated render failure
|
||
occurs. The capture workspace now reuses Trainlog cards, controls, status,
|
||
primary/secondary/danger actions and responsive spacing for a structured
|
||
night header, appreciations, event timeline, medication catalog and intake
|
||
editor. Domain data, schemas, revisions, synchronization and PDF semantics
|
||
are unchanged.
|
||
- Fixed equipment creation from the Android active-session exercise editor.
|
||
The selector now exposes the complete catalogue in a bounded scrollable
|
||
list, reuses the catalogue creation route, returns to the same stable
|
||
occurrence with all draft fields intact, and selects the explicitly created
|
||
equipment. Target-only prepared occurrences can save that equipment in
|
||
place without fabricating performed sets or appending a duplicate occurrence.
|
||
- Fixed the Android active-session exercise editor for target-only continuous
|
||
preparation entries. Opening an occurrence now renders its prefilled form,
|
||
preserves its independent plan while editing performed values, updates only
|
||
the selected stable occurrence, and reports persistence failures instead of
|
||
displaying a false editor-opened confirmation.
|
||
- Fixed Android activation of mixed session preparations containing continuous
|
||
duration targets and set-based exercises. Continuous target metadata now
|
||
remains planning-only, SQL `NULL` set counts round-trip correctly, and no
|
||
performed continuous activity or set is created before user capture.
|
||
- Added Sleep Diary V1 across desktop schema v29, Android schema v26, Analyse,
|
||
full-generation synchronization and a deterministic local vector PDF agenda.
|
||
Entries retain causal revisions, absolute timestamped events, the five-value
|
||
appreciation scale and user-authored notes; no medical interpretation or
|
||
heart-rate data is introduced. Sleep Diary also includes a revisioned local
|
||
medication catalog and timestamped intake snapshots with optional positive
|
||
dose/unit, synchronized and rendered factually in the agenda and PDF without
|
||
efficacy, interaction, causality, dosage, or clinical advice.
|
||
Progressive daily capture now persists every edit locally while keeping
|
||
draft, ready, synchronized, and post-sync modified states distinct. Explicit
|
||
validation publishes only the guarded current revision through the existing
|
||
full-generation/ACK path; validation never makes a day immutable.
|
||
|
||
Development opened after stable v0.1.3 release.
|
||
|
||
- Implemented the loopback-only Web Analyse V1 workspace and shared bounded
|
||
Core read model. The 7/30/90-day and all-history filters, factual activity,
|
||
active-Program progress, compatible exercise metrics, explicit persisted
|
||
MAX results, primary BODY ZONE exposures, and fourteen body measurements are
|
||
calculated by the C17 backend. Dashboard summaries consume the same model
|
||
while preserving all existing tile identities and layout behavior. Deep
|
||
links, safe query fallbacks, null/empty states, French/English presentation,
|
||
keyboard focus, and responsive charts are covered without estimating 1RM,
|
||
readiness, fatigue, recovery, body fat, or performance.
|
||
- Refined the Analyse V1 and Dashboard presentation without changing their
|
||
read models or API contracts. Period controls now share the section toolbar;
|
||
durations use the shared human-readable formatter; incompatible exercise
|
||
metrics remain hidden; activity, exercise, and measurement charts expose
|
||
chronological dates, units, and factual tooltips; BODY ZONE silhouettes and
|
||
exposure comparisons are more legible; and active-Program summaries use a
|
||
compact structured progression layout. Persisted Dashboard tile identities
|
||
and layout behavior remain unchanged.
|
||
|
||
## 0.1.3 — 2026-09-20
|
||
|
||
- Decoupled the Android full-generation request from the strict legacy V3
|
||
compatibility signal. One explicit intent now publishes the dedicated
|
||
`trainlog-sync-full-generation-request-v1.json` channel first; the legacy
|
||
request is published with the same identity only after a fresh V3 snapshot
|
||
succeeds. The desktop daemon prioritizes this channel and durably
|
||
deduplicates a bounded set of request identities across both channels.
|
||
|
||
Development opened after the stable v0.1.2 release.
|
||
|
||
- Made explicit Android synchronization intent authoritative over automatic
|
||
background resumption. A process-wide conversation arbiter now yields an
|
||
older background wait before the foreground publishes its fresh request
|
||
UUID, and `NEW_EXPLICIT` ignores the request/run that existed before the
|
||
click. Background USB and Drive workers classify new requests, new
|
||
correlated remote evidence, legitimate handoff, and stale resumable state;
|
||
terminal runs are no longer retried every five seconds without new proof.
|
||
Durable generations are retained across yield and handoff, and desktop
|
||
request-ID deduplication remains strict. No schema, protocol, causal rule or
|
||
exchange format changed.
|
||
|
||
- Hardened direct-MTP full-generation conversations after a private Android
|
||
run was frozen before generation capture. Android now emits bounded
|
||
run/phase metadata, refreshes the user-enabled background listener before a
|
||
foreground request, and confirms MediaProvider/MTP visibility for immutable
|
||
generation objects before publishing their reference. Desktop MTP pulls are
|
||
throttled to one complete refresh every three seconds, keep a separate
|
||
30-second operation budget, and report expiration of the conversation as a
|
||
correlated protocol timeout instead of a misleading final one-second
|
||
transport timeout. Explicit requests continue to receive fresh UUIDs.
|
||
Mensurations now retains two compact columns at the deployed phone's 312 dp
|
||
content width, with a narrow/large-font fallback. Schemas, causal semantics,
|
||
generation formats, ACK formats and standalone V3 strictness are unchanged.
|
||
|
||
- Routed Android foreground and daemon-triggered daily synchronization through
|
||
the existing full-generation orchestrator whenever its trusted local
|
||
configuration is present. The standalone mobile V3 importer remains strict
|
||
and still rejects causally protected live replay; complete generations apply
|
||
tombstones before filtering dominated snapshot facts. No schema, exchange
|
||
format, causal rule, or synchronization protocol changed. Android backup
|
||
manifests now obtain `product_version` from installed package metadata
|
||
instead of retaining the historical `0.1.2` literal.
|
||
|
||
- Unified the Android capture interface around compact dark cards, action
|
||
tiles, restrained-radius button variants, wrapping selection grids, and
|
||
two-column performed-set entry. Home now focuses on session capture, recent
|
||
BODY ZONES exposure, synchronization, and measurements; mobile Statistics
|
||
navigation was removed without changing stored data or exchange contracts.
|
||
Programs now show compact session metadata, completed progress, and explicit
|
||
start/resume/completed states using the existing schema-v25 durable Program
|
||
execution provenance. Web Program administration gained adaptive cards, a
|
||
visible progress bar, and green completed-session treatment while retaining
|
||
its revision-guarded trash confirmation and causal deletion behavior.
|
||
Android full lint remains at the exact ten-error `main` baseline (one
|
||
`NewApi`, one `LocalContextConfigurationRead`, and eight bilingual
|
||
`StringFormatMatches` diagnostics); this lot adds no lint error and disables
|
||
no rule. Private daily candidates retain development `versionName=0.1.3` and
|
||
may override only an increasing `versionCode` at build time.
|
||
|
||
- Added the loopback-only `/exercices` desktop catalogue administration
|
||
surface with bounded search/profile/BODY ZONES filtering, detail and
|
||
read-only equipment presentation, Core-owned creation and editing, complete
|
||
optimistic concurrency, and protected causal retirement. Profile changes
|
||
preserve stable exercise IDs and all historical occurrence snapshots.
|
||
Mutations remain desktop-local until the existing USB-priority, Drive
|
||
mirror/fallback synchronization publishes the existing catalogue companions;
|
||
no Android code, schema, exchange format, or automatic synchronization was
|
||
added.
|
||
|
||
## 0.1.2 — 2026-09-20
|
||
|
||
- Added USB-priority full-generation synchronization with a separately
|
||
configured private Drive mirror/fallback transport, verified manifest-last
|
||
publication, shared multi-transport identities/ACKs, and explicit per-
|
||
transport Web status without ever transporting SQLite.
|
||
- Added an Android user-enabled foreground USB listener, private Drive folder
|
||
connection with bounded WorkManager checks, and one shared concurrency-
|
||
guarded generation coordinator for UI and background triggers.
|
||
- Added an accessible preparation-list send action with separate editing and
|
||
delivery states, durable retry behavior, duplicate-delivery prevention and
|
||
stable execution-identity transition from Preparation to History/Program
|
||
completion.
|
||
|
||
- Implemented `TRAINLOG_PROGRAM_CALENDAR_V1` as the operational top-level
|
||
`/programmes` daily active-Program calendar. It consumes typed Core reads and
|
||
preparation creation, derives Monday–Sunday weeks from Program bounds and
|
||
real planned dates without inventing rest days, keeps undated sessions
|
||
separate, and rereads Core state after Prepare. Sessions → Programmes remains
|
||
the administration/import/list/detail/archive/delete surface; this adds no
|
||
Core, API, schema, format, synchronization, or Android changes.
|
||
|
||
- Fixed Program-to-preparation creation for Program V1 target weights written
|
||
as integer JSON numbers. Imports now preserve both integer and real number
|
||
spellings instead of persisting integer weights as zero. Existing affected
|
||
Programs remain unchanged; when deriving an editable draft, an impossible
|
||
legacy zero weight is represented as an unspecified target rather than
|
||
blocking the entire preparation. Mixed continuous-duration, unloaded-reps,
|
||
and externally loaded reps coverage verifies order, targets, provenance,
|
||
zero delivery/execution side effects, readable detail, and request replay.
|
||
|
||
- Fixed the Web history deletion failure for Program-origin completed
|
||
sessions. The history detail query now reads explicit MAX results from
|
||
`max_results`; mobile history import seeds a deterministic causal live
|
||
revision when one is missing; and desktop schema v28 gives durable Program
|
||
execution provenance an explicit terminal `deleted` state. Deletion remains
|
||
revision-guarded, atomic and replay-safe. Retained Program-execution
|
||
generations cannot resurrect a causally deleted session, and Web errors now
|
||
distinguish stale, absent, invalid and internal failures without exposing
|
||
database details. The private rollout additionally fixed complete-generation
|
||
dominance for occurrence equipment companions and made bounded ACK recovery
|
||
prioritize recent terminal evidence. Two correlated direct-MTP exchanges,
|
||
component restart and exact replay of a retained pre-deletion generation
|
||
preserved the single tombstone without duplication or resurrection.
|
||
|
||
- Added the Program execution flow. Android schema v25 can start or resume one
|
||
Program session through the existing durable singleton, preserves stable
|
||
Program provenance on completion, and presents explicit `À faire`, `En cours`
|
||
and `Effectuée` states. Desktop schema v27 stores the corresponding unique
|
||
execution link. The optional `trainlog-program-executions` V1 full-generation
|
||
companion advances Web Program sessions from persisted facts without changing
|
||
mobile export V3, `programs-v1`, or `TRAINLOG_FORMAT_V1`. Web also exposes
|
||
`À faire`, `Préparée`, `En cours`, and `Effectuée` session states, while the
|
||
existing logical Program deletion and confirmation semantics remain intact.
|
||
The coordinated private deployment advanced the daily Android installation
|
||
from versionCode 16/schema v24 to versionCode 17/schema v25 and desktop from
|
||
schema v26 to v27 without uninstalling, clearing, or losing user data. A
|
||
disposable Program session was started, resumed, completed, synchronized and
|
||
displayed as completed on Android and Web. Correlated ACKs, a second
|
||
idempotence exchange, store/component restart, exact old-generation replay,
|
||
causal Program deletion, tombstone acknowledgement and non-resurrection all
|
||
passed while the real 24-session/164-entry Program remained unchanged.
|
||
|
||
- Completed the private coordinated deployment of
|
||
`TRAINLOG_PROGRAMS_PRESENTATION_ANDROID_DELETE_V1`. Desktop schema v26 adds
|
||
terminal logical Program deletion with
|
||
request/deleted revisions, durable response replay, generation linkage and
|
||
acknowledgment state; source definitions and derived preparations remain,
|
||
while deleted Programs cannot resurrect or prepare. The responsive Sessions
|
||
Programs cards/timeline now use imported/session/usage/provenance data and
|
||
protect a discrete accessible trash confirmation with focus restoration and
|
||
Escape/Cancel no-op behavior. Android schema v24 adds the read-only synced
|
||
Programs list/detail projection. The optional staged controlled-generation
|
||
`trainlog-programs` V1 (`programs-v1.json`) publishes nondeleted Programs and
|
||
unacknowledged tombstones under capability `programs-v1`; it changes neither
|
||
`TRAINLOG_FORMAT_V1`, mobile V3, catalog exchange, nor preparations. Real
|
||
Firefox Programs screenshots and real rollout evidence are recorded in
|
||
`docs/reviews/programs_presentation_android_delete_v1_evidence.md`. The
|
||
signed private Android update advanced versionCode 15 to 16 without
|
||
uninstall or data clearing. A real disposable Program tombstone was consumed
|
||
and acknowledged, and a final correlated exchange after component restart
|
||
proved persistence, idempotence, and non-resurrection.
|
||
|
||
- Completed the private grouped rollout of Web Sessions deletion and Program
|
||
V1 from desktop source `a0fc48f082b76dba2ae3a56fceb492169de89f89`.
|
||
Desktop migrated from schema v24 to v25 after backup, restoration, and
|
||
copy-migration verification. Android was updated in place to private
|
||
versionCode 15 with no uninstall or data clearing; the installed APK is
|
||
non-debuggable and retains the daily-installation certificate. Exact
|
||
pre/post-update logical comparison preserved all 46 Android tables and 1,023
|
||
rows. A preparation created explicitly as disposable was withdrawn through
|
||
the real 390×844 confirmation UI. Two full-generation exchanges around a
|
||
Trainlog-only restart retained exactly one Android withdrawal result, no
|
||
matching delivery or performed session, and no resurrection or duplication.
|
||
|
||
- Completed Web Sessions deletion and Program V1 on desktop schema v25. Separate
|
||
revision-guarded Core commands now withdraw manual preparations and AI
|
||
proposals or causally delete inactive execution drafts and selected completed
|
||
sessions. The accessible trash confirmation preserves derived preparations,
|
||
active/concurrent drafts and unrelated performed history; proposal withdrawals
|
||
use the bounded `trainlog-ai-session-drafts` V2 tombstone extension to prevent
|
||
legacy replay resurrection on Android.
|
||
|
||
- Added Programs as the fourth Sessions subtab with complete paged listing,
|
||
search/state filtering, stable detail links, archival, strict bounded
|
||
`trainlog-program` V1 import preview and transactional commit. An explicit
|
||
program-session action creates a distinct provenance-bearing manual
|
||
preparation without automatic Android delivery or performed data.
|
||
|
||
- Completed the controlled Web Sessions presentation/withdrawal rollout on the
|
||
paired private installation. Desktop migrated from schema v23 to v24 and
|
||
Android from v22 to v23 without clearing application data. The requested
|
||
validation preparation was withdrawn once; Android reported
|
||
`execution_preserved` because its delivery had already started. Two
|
||
post-withdrawal direct-MTP generations around component restart proved no
|
||
resurrection or duplication while preserving the source proposal and all
|
||
actual workout data.
|
||
|
||
- Fixed a rollout-discovered stale peer-advertisement failure in the
|
||
full-generation MTP worker. Each MTP run now requires one successful pull
|
||
from the expected phone before validating peer identity and capabilities, so
|
||
a retained pre-upgrade advertisement cannot reject a compatible upgraded
|
||
Android peer.
|
||
|
||
- Corrected Web Sessions presentation with one descending cross-type order,
|
||
strict civil-date and zoned-timestamp formatting, contextual French states,
|
||
readable persisted proposal provenance, and an installation-local versioned
|
||
French/ISO date preference. The Dashboard prepared-item list, Footer, charts
|
||
and synchronization timestamps use the same presentation helpers without
|
||
changing machine values.
|
||
|
||
- Added revision-guarded, idempotent **Delete preparation** through the Core
|
||
service and protected loopback API. Desktop schema v24 retains an immutable
|
||
withdrawal ledger and all preparation/delivery evidence. The separate
|
||
`trainlog-session-preparations` V2 generation participant propagates exact
|
||
withdrawals; Android schema v23 cancels only pending deliveries, preserves
|
||
started executions and permanently prevents older delivery replay from
|
||
resurrecting a withdrawn preparation. V1 remains readable and
|
||
`TRAINLOG_FORMAT_V1` is unchanged.
|
||
|
||
- Implemented `TRAINLOG_WEB_SESSIONS_V1` with paged preparation, resume and
|
||
history views, stable details, optimistic/idempotent manual preparation,
|
||
explicit proposal derivation, desktop schema v23, Android schema v22 and the
|
||
separate `trainlog-session-preparations` V1 generation participant.
|
||
|
||
- Completed the controlled Sessions V1 deployment and delivered a six-entry
|
||
validation preparation to Android without starting it or replacing an active
|
||
draft. Foreground generation retries now emit a fresh daemon request and
|
||
resume the exact interrupted generation until both peer halves are durable,
|
||
preventing false transport timeouts and duplicate recapture.
|
||
|
||
- Added compatible non-destructive generation archival on desktop schema v22
|
||
and Android schema v21. Only exactly acknowledged generations older than the
|
||
two active recovery tips leave admission after a verified durable payload
|
||
copy and audit record; all identities, manifests, ACKs, lineage and causal
|
||
evidence remain stored. Older Android stores can recover exact missing
|
||
producer-side ACK rows from the desktop consumer's durable ledger, with
|
||
strict run, peer, generation and manifest revalidation. A correlated Android
|
||
capacity error now reaches the Web without waiting for a transport timeout,
|
||
and the prepared-items tile can inspect every proposal rather than only its
|
||
first compact summary.
|
||
|
||
- Completed the controlled schema-v22/schema-v21 rollout without uninstalling
|
||
or clearing Android data. The production Android archive uses a supported
|
||
post-rename file durability barrier on emulated external storage, and the
|
||
desktop publishes each complete MTP generation before its correlated
|
||
reference. Two real post-migration bidirectional exchanges, separated by a
|
||
Trainlog-service restart, completed with durable ACKs and no session
|
||
duplication. The expected AI proposal retained its identity, six entries,
|
||
and `pending` state on Android and remained independently visible in Web.
|
||
|
||
- Fixed a production full-generation timeout caused by recursively uploading
|
||
retained staging and unrelated transport history on every MTP push. Each
|
||
phase now publishes a private bounded outbox containing only its request,
|
||
ACK, and current referenced generation, while preserving every retained
|
||
generation, tombstone, and causal proof. Transport expiry has a stable
|
||
browser-facing code and action instead of a truncated traceback.
|
||
The reciprocal pull now reads only current coordination objects and the
|
||
exactly referenced Android generation instead of recursively mirroring
|
||
retained Android and desktop history.
|
||
|
||
- Replaced the Web Next Session placeholder with a separate read-only Core
|
||
projection that distinguishes AI proposals from active/pending execution
|
||
drafts without redefining the frozen Dashboard field or counting targets as
|
||
performed work. The browser preserves the last successful durable view
|
||
across refresh failures and uses one abortable, per-run ordered sync poller.
|
||
|
||
- Completed the authorized private full-generation rollout over production
|
||
direct MTP: verified Android and desktop backups, signing-preserving Android
|
||
updates, schema migrations, persistent peer pairing, bidirectional durable
|
||
ACKs, restart and idempotent replay. This did not publish a release or modify
|
||
v0.1.1.
|
||
|
||
- Fixed rollout-discovered feedback idempotence across SQLite row modes,
|
||
packaged the complete generation exporter closure, ignored stale Android
|
||
coordination objects until their run/generation correlation matches, and
|
||
made the Android screen report completed generation conversations instead of
|
||
waiting for a legacy receipt.
|
||
|
||
- Packaged `trainlog-sync-once` and `trainlog-syncd` with the relocatable sync
|
||
candidate so user services cannot mix a versioned install with live-checkout
|
||
helpers during rollout.
|
||
|
||
- Added a bounded Android package-version override and made the schema-v17
|
||
backup bridge produce a signed release APK, allowing a strictly increasing
|
||
private update chain without changing Trainlog schemas or protocols.
|
||
|
||
- Generalized bridge restore/migration validation to preserve every historical
|
||
SQLite value whether a real backup contains an active draft or legitimately
|
||
contains none.
|
||
|
||
- Made relocatable launchers resolve stable user-bin symlinks to their physical
|
||
versioned bundle before loading matching binaries and helpers.
|
||
|
||
- Made the Web sync button generate cryptographic UUIDv4 request IDs on the
|
||
loopback HTTP hostname where `crypto.randomUUID()` is unavailable.
|
||
|
||
- Included the exercise-name and training-knowledge modules required by the
|
||
packaged generation worker, with an isolated runtime-import regression.
|
||
|
||
- Closed the native candidate warning gate with checked path and HTTP response
|
||
bounds, strict GCC and Clang builds, full Clang ASan/UBSan validation, and a
|
||
stable concurrent object-I/O MTP double. Rebuilt the desktop, current Android
|
||
and non-installed schema-v17 bridge candidates with recorded digests; no
|
||
service, device, user database, signing secret or deployment was touched.
|
||
|
||
- Normalized the recent synchronization, generation-MTP, Android backup,
|
||
Web Dashboard serialization, tests, I/O doubles and packaging code for human
|
||
readability. Added scoped C formatting rules and review guidance without
|
||
changing synchronization protocols, assertions, deployment state or runtime
|
||
behavior.
|
||
|
||
- Added the production libudev/libmtp generation adapter with bounded peer
|
||
selection, object transfer and manifest-last publication; wired the trusted
|
||
orchestrator mode and proved the full Firefox/Android/desktop conversation
|
||
with an I/O-boundary object double. Added complete versioned Android
|
||
backup/verify/restore and a reproducible, non-installed schema-v17 bridge
|
||
candidate with v17 round-trip and v17-to-v20 migration tests. Physical MTP,
|
||
signing, device installation, user-data operations and rollout remain
|
||
pending.
|
||
|
||
- Added opt-in foreground generation coordination, peer-evidenced capabilities,
|
||
truthful bounded Web progress, descendant cleanup, an integrated Android ↔
|
||
desktop Firefox proof, and synthetic candidate/SQLite recovery tooling on the
|
||
development branch. Physical MTP and deployment remain pending.
|
||
|
||
- Completed the grouped `TRAINLOG_SYNC_WEB_END_TO_END_V1` mission: the opt-in
|
||
full-generation orchestrator, protected asynchronous Web API, global sync
|
||
control, durable reconnect reporting, Dashboard refresh and read-only draft
|
||
summary pass isolated C, Python, Android, frontend and Firefox validation.
|
||
Default V3, physical MTP, Drive and deployment remain unchanged.
|
||
|
||
- Completed `TRAINLOG_SYNC_GENERATION_ACK_V1` with desktop schema v21 and
|
||
Android schema v20. Added coherent per-platform capture, strict bounded
|
||
manifest V1, immutable manifest-last publication, whole-generation SQLite
|
||
consumption, pair-scoped lineage, durable consumed/rejected ACK V1 replay,
|
||
and a separate causal-operation publication ledger. Real isolated Android →
|
||
desktop and desktop → Android chains use production entry points and retain
|
||
operation identity across generations. Automatic V3/MTP selection and all
|
||
operational services remain unchanged.
|
||
|
||
- Completed the residual causal-deletion evidence with real Android and
|
||
desktop producers for exercise, body-observation, custom-equipment, feedback
|
||
and BODY ZONE relation targets, including production replica exchange,
|
||
retained-history/current-reader checks, reopen/replay and stale-companion
|
||
refusal.
|
||
|
||
- Closed the causal-deletion correctness review: deletion predecessors now
|
||
cover affected session children, measurements, links, notes and immutable
|
||
feedback revisions; supported corrections preserve an intervening mutation
|
||
marker even after a content revert. Imported operations share built-in
|
||
authorization with local deletion, execution drafts use their stable
|
||
cross-platform revision identity, protected legacy companions refuse unsafe
|
||
replay, and causal artifact reads/exports enforce count and byte bounds
|
||
before destructive effects.
|
||
|
||
- Completed `TRAINLOG_SYNC_CAUSAL_DELETE_V1` with desktop schema v20 and
|
||
Android schema v19. Added a strict bounded staged causal-deletion artifact,
|
||
durable operation/state records, domain-specific deletion effects, causal
|
||
conflict and replay handling, and legacy snapshot non-resurrection gates.
|
||
Android and desktop both produce and consume the artifact in isolated tests;
|
||
automatic transport, generation acknowledgement and deployment remain
|
||
inactive.
|
||
|
||
- Completed `TRAINLOG_SYNC_DATA_LIFECYCLE_V1` with desktop schema v19 and
|
||
Android schema v18. Added explicit staged V4 enriched-history codecs,
|
||
causal notes, body-observation session links, stable execution-draft
|
||
identities, bounded pending drafts, explicit activation and atomic,
|
||
idempotent finalization with stale-replay protection. Active synchronization
|
||
remains V3; no service, user database, phone, tag or release artifact was
|
||
changed or deployed.
|
||
|
||
- Closed the lifecycle validation evidence with real Android/desktop V4
|
||
history and execution-draft round trips in both producer directions. Fixed
|
||
Android V4 import so validated target, load, and rest fields are persisted,
|
||
reconciled the 73/75 native count to the two `web=auto` frontend tests, and
|
||
documented identical pre-existing GCC 16 `-Wmisleading-indentation`
|
||
failures on baseline and branch while retaining Clang 22 strict green
|
||
builds. V4 remains staged and inactive.
|
||
|
||
- Completed `TRAINLOG_SYNC_CHARACTERIZATION_V1` without changing production
|
||
synchronization, schemas, or formats. Added a real Android V3 exporter →
|
||
desktop importer/exporter → fresh Android importer round trip, and completed
|
||
current-behavior evidence for stable identities, occurrence/set ordering,
|
||
exact replay versus correction, local-only field handling, inter-artifact and
|
||
delete-before-send partial failure, request/receipt replay and marking, and
|
||
contention on the real private-XDG synchronization lock. V4, draft transport,
|
||
general tombstones, coherent generations, causal merge, and durable peer
|
||
consumption acknowledgement remain future work.
|
||
|
||
- Reconciled canonical documentation with the implemented 0.1.2 development
|
||
state, kept v0.1.1 and future synchronization scope explicit, established
|
||
English as the repository documentation/release-note language, and added a
|
||
reusable tag-scoped English source for the v0.1.1 public notes. No production
|
||
behavior, schema, format, service, tag, or release asset changed.
|
||
|
||
- Completed `TRAINLOG_SYNC_TEST_ENV_V1` without changing production behavior,
|
||
schemas or formats. `tools/validate_sync_isolated.py` now validates JDK 17 and
|
||
the effective Gradle JVMs, creates unique private HOME/XDG/native/JVM tmp,
|
||
exchange, database and report paths, runs bounded preflight/smoke/full suites,
|
||
counts Android XML results, propagates failures and interruptions, and cleans
|
||
only its owned successful run. Unit and Robolectric coverage proves bounded
|
||
cleanup, distinct runs, process termination, no default real transport and
|
||
effective `java.io.tmpdir` propagation.
|
||
|
||
- Froze `TRAINLOG_SYNC_GAP_CONTRACT_V1` without changing production sync,
|
||
schemas or published formats. The contract distinguishes current evidence
|
||
from future behavior and defines domain ownership, active-draft lifecycle,
|
||
lost fields, causal deletion, conflicts, coherent generations, verified
|
||
consumption/acknowledgement, compatibility, reporting, a future Web service
|
||
boundary and dependency-ordered implementation lots. Added isolated
|
||
production-path characterization of V3 field loss, snapshot resurrection and
|
||
per-artifact rollback; existing Android coverage remains the proof of draft
|
||
exclusion followed by finalized-session export.
|
||
|
||
- Development opened after the stable `v0.1.1` release. The complete Web
|
||
Dashboard is now `WEB_DASHBOARD_V1=PASS/FROZEN`; Analyse, Programmes,
|
||
Sessions, and Exercises remain placeholders. The current operational cursor
|
||
is `TRAINLOG_SYNC_CHARACTERIZATION_V1`; its future protocol work has not
|
||
started.
|
||
|
||
## 0.1.1 — 2026-09-16
|
||
|
||
- Completed `TRAINLOG_ANDROID_FIELD_INPUT_REFINEMENT_V1`: active and completed
|
||
occurrence handles now keep one stable `entry_id`-keyed pointer gesture alive,
|
||
accumulate total drag distance, jump directly across multiple positions, show
|
||
residual pointer-following motion, restore the origin on cancellation, and
|
||
commit only once at completion where persistence applies. Decimal distance,
|
||
speed, MAX, target-load, and set-load editors use decimal keyboards, accept
|
||
both `.` and `,`, preserve incomplete typing states, and parse finite
|
||
locale-independent values only at commit. Units, schemas, formats, identities,
|
||
active/completed ownership, and version 0.1.1 remain unchanged.
|
||
|
||
- Completed `TRAINLOG_ANDROID_COMPLETED_SESSION_REORDER_V1`: the Android
|
||
completed-session correction form reuses the dedicated localized right-side
|
||
drag handle and accessibility move actions. Reordering remains transient until
|
||
Save; Cancel/Back writes nothing, while Save atomically replaces positions and
|
||
any factual corrections under the same session/entry/exercise identities.
|
||
Stable Compose keys keep editor state attached to `entry_id`; equipment,
|
||
targets, actuals, MAX, feedback revisions, and J+1 ownership survive. Existing
|
||
V3 synchronization reconciles the same desktop session without duplication.
|
||
No schema, exchange format, active-session behavior, or version changed.
|
||
|
||
- Completed `TRAINLOG_ANDROID_FIELD_WORKFLOW_REFINEMENT_V1`: Android now uses a
|
||
full-width semantic-success **Add to session** action, provides a dedicated
|
||
accessible right-side drag handle for durable active-draft reordering, and
|
||
supports atomic completed-session factual correction. Reorder and correction
|
||
retain stable session, occurrence, exercise, equipment, plan, actual, feedback,
|
||
and follow-up ownership; corrected facts continue through the existing V3
|
||
synchronization identity. Continuous values reject non-finite input and show
|
||
explicit km, km/h, and seconds units. No SQLite schema, exchange format,
|
||
desktop/TUI behavior, or product version changed.
|
||
|
||
- Documented stable-release distribution through GitHub and Forgejo 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. The Android artifact is built with the
|
||
durable Trainlog release identity and is verified before publication.
|
||
|
||
- Completed `TRAINLOG_I18N_V0_1_1`: Trainlog 0.1.1 is one synchronized Android
|
||
and desktop product version, with French as the default interface language
|
||
and English selectable through **Settings → Language** on both surfaces.
|
||
The preference is local presentation state (dedicated Android
|
||
SharedPreferences; desktop XDG `trainlog/presentation.conf`) and successful
|
||
selection updates the interface immediately. Localized Trainlog-owned text,
|
||
BODY ZONE labels selected by stable IDs, and visible number/date formatting
|
||
do not change training data, user exercise/catalogue names, IDs, SQLite,
|
||
schemas, exchange/protocol artifacts, AI, MAX, or feedback. Desktop and
|
||
Android synchronization views render local typed status/counters; raw
|
||
core/receipt/history summaries remain opaque protocol/operational bytes and
|
||
are never injected as cross-device French text. Final validation passed
|
||
60/60 normal and 60/60 ASan/UBSan desktop tests, Android 202 total tests
|
||
(198 passed, 4 skipped, 0 failed), both validators, source-derived
|
||
`TRANSLATABLE_UI=0`, and Android resource parity. Real device/manual visual
|
||
switching remains an explicit smoke validation.
|
||
|
||
- 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
|
||
draft and feedback imports. Regression coverage rebuilds several mappings in
|
||
one inbox pass, resolves a retired exercise ID only through its durable alias,
|
||
preserves the one-sync AI draft, and proves idempotent replay without identity
|
||
mutation or duplicate zone rows.
|
||
|
||
- Redesigned the Android Home, Sessions, Exercise Catalogue, active-session
|
||
and completed-session-detail action layouts with balanced icon tiles,
|
||
bounded internal catalogue scrolling, and prominent accessible buttons,
|
||
plus uniform full-width icon-only destructive actions with contextual
|
||
TalkBack labels, without changing confirmation, navigation callbacks, or
|
||
domain/storage/sync behavior.
|
||
|
||
- Added an Android confirmation dialog before deleting an imported AI session
|
||
draft. Cancel, Back and outside dismissal are non-mutating; only the
|
||
destructive confirmation invokes the existing deleted-tombstone operation.
|
||
|
||
- Replaced Android SAF folder grants with user-enabled
|
||
`MANAGE_EXTERNAL_STORAGE` access to the single fixed path
|
||
`/storage/emulated/0/Documents/Trainlog`. Android opens the system all-files
|
||
permission screen, writes canonical artifacts through fsync plus
|
||
same-directory replacement, reads PC artifacts directly, and removes stale
|
||
tree-URI preferences. Desktop publication remains `Documents/Trainlog`; the
|
||
historical Download tree and recovery backup remain untouched.
|
||
|
||
- Added `TRAINLOG_AI_SESSION_DRAFT_V1` as a separate strict proposal path:
|
||
desktop schema v18 imports one Drive source with `aid_` identity/digest
|
||
idempotence and post-commit archive bookkeeping, then publishes the bounded
|
||
`trainlog-ai-session-drafts` V1 Android companion in durable deterministic
|
||
batches, marking only successful MTP publications. Entry notes are rejected;
|
||
only draft-level notes belong to the source contract. Inbound helper outcomes
|
||
remain visible without turning Drive/archive/fetched-invalid results into a
|
||
failed device sync. Android schema v17 keeps
|
||
those proposals separate from its singleton active capture draft and retains
|
||
start/delete tombstones against replay. Automated contract coverage exists;
|
||
the required real Drive and Android-triggered bidirectional smoke validation
|
||
remains pending.
|
||
|
||
- Fixed automatic Android→PC exercise-alias imports when the desktop binary is
|
||
installed outside the repository build tree. Python sync helpers now resolve
|
||
from Meson's authoritative tools directory, stale result files are truncated
|
||
before resolution, and bounded child stderr/exit diagnostics reach sync
|
||
history instead of collapsing to a generic import failure.
|
||
- Added `TRAINLOG_AI_EXPORT_V1`, a deterministic local JSON history export for
|
||
manual external analysis. It opens desktop SQLite explicitly read-only,
|
||
preserves occurrence-owned immediate feedback and session-owned follow-ups,
|
||
and emits no inferred recommendations or progression.
|
||
- Added the shared desktop post-sync publication: successful TUI and
|
||
Android-requested sync runs regenerate the AI export and invoke external
|
||
`rclone copyto` for Google Drive. Export/Drive failures remain visible but do
|
||
not invalidate an already successful Trainlog synchronization.
|
||
|
||
- Fixed Android-triggered synchronization so the complete current Android→PC
|
||
companion bundle is published before the request signal, including Training
|
||
Feedback V2 and Exercise Profile State V1. Desktop orchestration now refuses
|
||
stale temporary profile-state reuse and reports a specific missing causal
|
||
companion when a modern same-ID profile mismatch requires it.
|
||
- Made Android exchange-file reuse exact and directory-scoped: pending,
|
||
trashed, unrelated, and conflict-numbered MediaStore rows no longer enter
|
||
canonical selection, while genuine duplicate exact names fail closed.
|
||
- Hardened the shared Android SAF publisher so every outbound companion and
|
||
sync request rewrites an existing exact canonical document with truncation,
|
||
never selects historical `(N)` copies, and reports
|
||
`SAF_CANONICAL_NAME_CONFLICT` before writing when a provider renames a newly
|
||
created document.
|
||
- Added an exact-document fallback for Samsung Android 16
|
||
`ExternalStorageProvider`, whose child query can omit ownerless MTP files even
|
||
though creation detects their names. Canonical rows are reconstructed only
|
||
beneath the granted tree and verified by exact provider display name;
|
||
historical suffixes remain untouched.
|
||
|
||
## Unreleased — Desktop historical tracking snapshot
|
||
|
||
- Added desktop schema v17 / Android schema v16 causal current-profile state,
|
||
bounded 32-revision transitive ancestry, deterministic bidirectional
|
||
convergence, and explicit concurrent-edit conflicts; legacy feedback without
|
||
`ended_at` now shows approximate H+ from
|
||
valid `started_at` instead of a misleading during-session label.
|
||
- Added desktop schema v16 with an atomic v15 backfill of occurrence-owned
|
||
`session_exercises.tracking_mode`, preserving identities and all child facts.
|
||
- Switched historical readers and V3 exchange to the occurrence snapshot while
|
||
retaining catalogue profile modes as future-entry defaults.
|
||
- Enabled explicitly confirmed future-only tracking/profile edits in the TUI
|
||
without rewriting completed sessions.
|
||
|
||
## Unreleased — Training feedback UX and safety
|
||
|
||
- Added additive schema v15 immutable feedback revisions and Training Feedback
|
||
V2 with V1 import compatibility.
|
||
- Made saved exercise feedback and session follow-ups correctable on Android
|
||
while preserving root identity, observation time, H+ placement and history.
|
||
- Preserved occurrence `entry_id` and feedback through draft edit,
|
||
reconstruction, finalization and completed-session correction.
|
||
- Added explicit destructive confirmation to the reachable Android and TUI
|
||
session removal/abandon paths.
|
||
|
||
## Unreleased — MACHINE_EXERCISE_MODEL_V1
|
||
|
||
- Add desktop and Android schema v13 for machine-specific exercise metadata.
|
||
- Preserve stable IDs for pure renames and introduce the five approved UUIDv4
|
||
identities for Plate Loaded Leg Press, Treadmill, Pec Fly, Chin Assist, and
|
||
Dip Assist.
|
||
- Make exact manifest splits transactional and idempotent while preserving all
|
||
occurrence child facts and unresolved provenance.
|
||
- Remove Equipment from normal Android and TUI navigation while retaining its
|
||
Phase 1 storage and sync compatibility roles.
|
||
|
||
- Added `PERCENT_MAX_INPUT_V1` as a transient user calculator in TUI planning
|
||
and both generator previews: exact exercise/equipment external-load context,
|
||
integer 1..100, `MAX × percentage / 100`, no recommendation, and only the
|
||
resulting target kg persisted. Automatic generator policy V1 is unchanged.
|
||
- Repaired TUI `/` through the stable action registry, deduplicated actions by
|
||
stable ID, strengthened Lavender plus textual selection states, compacted
|
||
Android generator choices into localized chips, and made generator duration,
|
||
shortfall, warm-up and cool-down limitations explicit.
|
||
|
||
All notable changes to Trainlog are documented here.
|
||
|
||
Detailed implementation chronology remains available in Git history and
|
||
`docs/reviews`. This file summarizes the current unreleased product baseline.
|
||
|
||
## Unreleased
|
||
|
||
### Added
|
||
|
||
- `TRAINLOG_TUI_STATISTICS_CALENDAR_BUCKETS_V1=PASS`: Training `7j` now means
|
||
the current Monday–Sunday calendar week and compares calendar weeks; `30j`
|
||
means the current Gregorian month and compares calendar months. Membership
|
||
follows the civil date persisted in each timestamp, empty intermediate
|
||
periods remain zero bars, localized labels expose the calendar boundaries,
|
||
and exact month endpoints cover ordinary and leap-year February.
|
||
|
||
- `TRAINLOG_TUI_STATISTICS_PERIOD_BUCKET_SIZE_FIX=PASS`: the selected Training
|
||
period now controls both summary depth and comparison-bucket size. `7j` uses
|
||
exact consecutive 7-day buckets, `30j` uses exact consecutive 30-day buckets
|
||
anchored on the current local date, and `Tout` selects one stable weekly or
|
||
calendar-month scale from total historical duration. Empty intervals remain
|
||
explicit zero bars and boundary observations are counted once.
|
||
|
||
- `TRAINLOG_TUI_STATISTICS_PERIOD_BUCKETING_V1=PASS`: Training summaries keep
|
||
their rolling 7-day/30-day facts while charts compare consecutive exact
|
||
Monday–Sunday buckets. The 7-day view shows up to four available weeks, the
|
||
30-day view shows all intersecting weeks, empty periods remain zero bars, and
|
||
complete history adapts from weekly to monthly totals beyond 128 active
|
||
weeks without sampling away totals.
|
||
|
||
- `TRAINLOG_TUI_STATISTICS_REFINEMENT_V1=PASS`: finite statistics windows now
|
||
retain their complete time domain; weekly totals use local Monday buckets,
|
||
explicit empty weeks, zero baselines and discrete Notcurses bars. Wide
|
||
training summaries are grouped into semantic panels, zone bars expose raw
|
||
counts on one shared scale, exercise lists show factual summaries, and MAX
|
||
defaults to exercises with an explicit recorded result while preserving an
|
||
opt-in all-compatible view and prefix search.
|
||
|
||
- `TRAINLOG_TUI_STATISTICS_V1=PASS`: Statistiques is now the desktop analysis
|
||
center for body history, factual global training activity, canonical
|
||
exercise histories, persisted primary/secondary body-zone activity and
|
||
explicit MAX history. Read-only C17 aggregations feed responsive Notcurses
|
||
views and the shared Braille chart; valid loaded volume, planned/actual and
|
||
feedback ownership rules deliberately exclude unsupported inference. No
|
||
Android, database-schema, synchronization or exchange-format behavior changed.
|
||
|
||
- `TRAINLOG_TUI_MEASUREMENTS_GRAPH_V1=PASS`: Statistiques / Mensurations now
|
||
uses a reusable Notcurses chart with true elapsed-time spacing, labelled
|
||
padded value scales, a 2x4 Unicode Braille line raster, distinct accent
|
||
markers for stored observations, responsive sparse-profile layout, and
|
||
terminal-free geometry/raster regressions. No database, measurement, Android,
|
||
or synchronization semantics changed.
|
||
|
||
- `APP_SHELL_V1=IMPLEMENTED_AWAITING_VISUAL_REVIEW_2`: a shared seven-root
|
||
application shell—Accueil, Séances, Exercices, Équipements, Statistiques,
|
||
Synchronisation and Paramètres—on the Notcurses TUI and Android Material 3
|
||
drawer. Séances now contains the existing generator, current/manual session
|
||
entry and completed history; existing body and MAX views are reached from
|
||
Statistiques. The TUI adds its run-scoped multi-plane shell, one event loop,
|
||
stable-ID list/focus restoration, bounded UTF-8 search/forms, F6 Navigation,
|
||
F7 shared actions, compact/sidebar thresholds, and explicit transient leave
|
||
guards. Android adds typed controller-owned routes, local vectors, 48 dp
|
||
actions and guarded navigation. The change adds no statistics, schema,
|
||
synchronization artifact or exercise-domain semantics. Automated validation
|
||
passed. A second automated repair review covered root search/action dispatch,
|
||
F6/F7 focus/selection restoration, shell hubs/catalogues and Android compact
|
||
presentation/latest-MAX semantics; human visual/accessibility review remains
|
||
pending.
|
||
|
||
- `SESSION_GENERATOR_V1=PASS`: one frozen shared policy; deterministic bounded previews for
|
||
11 BODY ZONES and four goals; explicit incomplete coverage and recorded-dose
|
||
recency; observed exact-equipment 28-day load anchors without MAX-derived
|
||
numeric fallback; Android normal-draft and TUI normal-editor acceptance; an
|
||
additive Android v10 -> v11 plan migration; and separate strict V3 mobile
|
||
exchange preserving plans with actual occurrence data. V1/V2 remain readable.
|
||
|
||
- `TRAINING_KNOWLEDGE_V1` read-only scientific knowledge infrastructure:
|
||
six authored, versioned JSON catalogs with cited references; deterministic C
|
||
generation; Android immutable asset loading; stable-ID catalog queries; and
|
||
desktop/Android composition of persisted exercise zones, compatible
|
||
equipment, explicit MAX and bounded occurrence/set history. The feature
|
||
introduces no schema migration, database seeding, synchronization artifact,
|
||
runtime prescription or generated UUID association. Scientific review,
|
||
independent temporal review, final engineering review, repair verification,
|
||
and final executable validation passed. The initial audit's four findings
|
||
were closed by one bounded repair chain. See
|
||
`docs/reviews/training_knowledge_v1_temporal_contract.md` and
|
||
`docs/domain/knowledge_system.md`.
|
||
|
||
- `BODY_ZONES_V1`: the canonical `catalog/body-zones-v1.json` taxonomy with
|
||
stable IDs, French display metadata, hierarchy, deterministic sort order and
|
||
exact stable-exercise-ID migration evidence;
|
||
- one primary plus multiple distinct secondary body-zone relations on desktop
|
||
and Android, with explicit unclassified history, transactional creation/edit,
|
||
exercise detail summaries, parent/descendant filters, prefix-search
|
||
composition, and custom-exercise support;
|
||
- one strict bidirectional `trainlog-exercise-body-zones` v1 companion carrying
|
||
`exercise_id`, nullable primary ID and ordered secondary IDs; replay is
|
||
idempotent, one-sided edits reconcile, simultaneous divergence conflicts,
|
||
secondary lists are never unioned automatically, and the publishing peer
|
||
records the exact published snapshot as its common baseline;
|
||
- generator-ready read composition for descendant and primary-only exercise
|
||
selection, direct zone relations, existing performance history and explicit
|
||
MAX history without duplicating historical or MAX data;
|
||
- taxonomy, schema migration, relation constraint, filtering, identity-merge,
|
||
reopen, companion replay/update/conflict and Android repository regressions;
|
||
|
||
- explicit MAX result mode for `max_test` sessions: exercise, optional
|
||
equipment context and positive `max_weight_kg`, with no synthetic set or
|
||
repetition;
|
||
- Android and TUI max-only entry/edit/detail flows, Android latest max per
|
||
exercise, and stable-ID continuation of a completed Test max;
|
||
- V2 round-trip of explicit max results in both directions, including bounded
|
||
reconciliation of an appended or corrected continuation of the same
|
||
max-test session;
|
||
- desktop and Android schema v9 migrations that convert only an unambiguous
|
||
sole `1 rep × positive load` legacy result and preserve ambiguous attempts;
|
||
- explicit-max persistence, migration, sync and same-machine/different-movement
|
||
regression coverage;
|
||
|
||
- desktop equipment v8: a supplied catalogue generated from
|
||
`catalog/equipment-v1.json`, browse/search/detail views, and local custom
|
||
equipment creation/selection; occurrence links resolve supplied or local
|
||
definitions and show unknown historic references explicitly;
|
||
|
||
- multi-occurrence session V2: stable per-occurrence `entry_id`, repeated
|
||
catalogue exercises in one session, per-set actual weights, and occurrence
|
||
equipment associations across Android, desktop, import and export;
|
||
- structured Android and Notcurses per-set row editing: independent actual
|
||
repetitions and nullable Charge/Assistance values, ordered add/delete/edit
|
||
operations, and ordered history/detail presentation without target-value
|
||
substitution;
|
||
- shared versioned equipment catalogue, Android machine selection/search,
|
||
Android-local custom equipment creation, and explicit rejection of unknown
|
||
equipment identities rather than silent association loss;
|
||
|
||
- `trainlog-equipment-definitions` v1, with directional Android-to-PC and
|
||
PC-to-Android filenames, strict stable definition fields, additive
|
||
reconciliation, reserved supplied-manifest IDs, and explicit divergence
|
||
conflicts;
|
||
- explicit TUI/shared-engine synchronization actions: `a` Android -> PC, `p`
|
||
PC -> Android, and `b` inbound then outbound bidirectional synchronization;
|
||
each opens one direction-specific confirmation, `Enter` runs it once, `Esc`
|
||
cancels without an operation, `r` only refreshes device status, and the
|
||
former `s` shortcut is inert;
|
||
- bounded V2 exercise reconciliation for distinct IDs with equal normalized
|
||
names: modes and represented invariants must match, field masks must be
|
||
comparable, desktop identity stays canonical, and the richer bit-mask union
|
||
is retained without changing historical occurrence snapshots;
|
||
- regression coverage for identical/different-ID profiles, compatible
|
||
subset/superset masks, incompatible collisions, the real Marche identity
|
||
pair, full Android -> PC import and stable PC ↔ Android replay;
|
||
|
||
- Android `EXERCISE_EDIT_V1`: visible catalog editing, stable-ID name rename,
|
||
explicit invalid/conflict/profile/database results, and profile locking once
|
||
completed history or an active draft references the exercise;
|
||
- `ANDROID_BANNER_PARITY_V1`: the earlier Android `◆ TRAINLOG ◆` header
|
||
component matched the compact Notcurses banner's accent and muted context
|
||
rhythm. APP_SHELL_V1 supersedes that per-page presentation with the fixed
|
||
Material 3 `AndroidAppShell` top bar;
|
||
|
||
- one durable Android active-session draft with Home resume, raw form restore,
|
||
confirmed discard and draft-only exercise removal;
|
||
|
||
- native Kotlin/Compose Android capture client;
|
||
- Android local exercise, session, continuous-activity, and body persistence;
|
||
- C17/Notcurses desktop TUI with direct session entry and durable SQLite history;
|
||
- profile-aware exercise model using recording mode, tracking mode, and
|
||
supplemental fields;
|
||
- continuous activity persistence without synthetic sets;
|
||
- explicit table-based desktop actual-set entry, with independently added rows
|
||
and no compact performed-repetition input;
|
||
- persisted desktop session editing and exercise removal;
|
||
- Android current-session draft exercise removal;
|
||
- body-observation history, editing, graphs, and normalized overlays;
|
||
- exercise performance history;
|
||
- direct physical Android USB/MTP discovery with libudev/libmtp;
|
||
- direct MTP read/write/list/delete support without filesystem mounts;
|
||
- Android full mobile snapshot export;
|
||
- strict idempotent desktop mobile importer;
|
||
- PC canonical exercise-catalog publication to Android;
|
||
- automatic Android snapshot maintenance;
|
||
- Android `Synchroniser maintenant` request flow;
|
||
- shared C bidirectional synchronization engine;
|
||
- `trainlog-syncd` user-session synchronization agent;
|
||
- request/receipt synchronization protocol;
|
||
- stable `sy_<uuid-v4>` synchronization identities;
|
||
- structured synchronization history with selectable TUI list/detail views.
|
||
|
||
### Changed
|
||
|
||
- desktop schema v11 additively introduces `exercise_body_zones` and its
|
||
internal sync-baseline table; Android schema v10 introduces the equivalent
|
||
relations. Both migrations seed only manifest mappings proven by stable
|
||
`exercise_id`, leave uncertain exercises unclassified, and preserve all
|
||
session, occurrence, set, MAX, equipment and body-observation identities;
|
||
- Android and TUI exercise catalog workflows now select translated manifest
|
||
values, derive group labels, exclude a primary from secondary selection and
|
||
combine hierarchy-aware zone filtering with normalized prefix search;
|
||
|
||
- desktop schema v10 losslessly rebuilds only `performed_sets` to accept an
|
||
explicit zero actual `weight_kg`; historic NULL and positive actual loads
|
||
remain unchanged, while planned targets and explicit MAX results stay
|
||
strictly positive;
|
||
- desktop and Android schema v9 add one-to-one completed/draft max-result rows;
|
||
`TRAINLOG_FORMAT_V1` remains frozen and V1 export refuses explicit MAX data
|
||
rather than losing or fabricating it;
|
||
- desktop and Android schema v8 preserve existing equipment references while
|
||
permitting custom definitions with `load_semantics = none`; Android's v7 ->
|
||
v8 migration is non-destructive;
|
||
- custom definitions reconcile before V2 mobile/association artifacts in each
|
||
direction. The V2 mobile and association shapes are unchanged;
|
||
|
||
- desktop SQLite schema v7 and Android SQLite schema v7 preserve historic rows
|
||
while adding durable occurrence identities and occurrence-level equipment;
|
||
- the then-active Android↔PC completed-session exchange was V2; frozen V1
|
||
artifacts remain readable as historical formats and are not redefined for
|
||
repeated occurrences; the current active artifact is separately versioned V3;
|
||
- synchronization invokes each local helper with the explicit XDG-resolved
|
||
desktop database path and records the concrete equipment-import failure;
|
||
|
||
- same-ID Android ↔ PC catalog reconciliation updates display-name metadata in
|
||
place. Compatible different-ID normalized-name collisions now merge through
|
||
the explicit V2 policy; incompatible collisions still reject atomically;
|
||
|
||
- Android local SQLite v3 -> v4 additive migration for structured active drafts;
|
||
- completed-session insertion and draft clearing are atomic; drafts remain
|
||
excluded from completed history and frozen mobile export;
|
||
|
||
- desktop SQLite schema evolved to v5;
|
||
- schema v5 permits targetless set-session rows for actual-only mobile data;
|
||
- heterogeneous performed sets are preserved without inventing a uniform target;
|
||
- Android/desktop synchronization uses dedicated versioned artifacts instead of
|
||
modifying frozen Trainlog JSON v1;
|
||
- PC and TUI synchronization paths now share one engine;
|
||
- Android PC-created artifact access uses a persistent SAF grant for
|
||
`Download/Trainlog`;
|
||
- the Android data package is no longer accidentally hidden by a broad
|
||
repository `data/` ignore rule;
|
||
- user-facing session history timestamps use `DD/MM/YYYY HH:MM` while canonical
|
||
storage remains RFC3339.
|
||
|
||
### Fixed
|
||
|
||
- a newly published custom-exercise zone state now establishes the publisher's
|
||
comparison baseline as well as the receiver's; a later peer-only edit no
|
||
longer produces a false simultaneous-conflict result;
|
||
- secondary-only body-zone states are rejected consistently by C, Kotlin and
|
||
Python boundaries instead of being persisted but hidden by exercise detail;
|
||
- touched migration/custom-equipment/body-metric/TUI C regressions now return
|
||
a failing process status from `main()`; the repaired workflow fixture uses a
|
||
real in-memory database instead of passing an invalid null handle;
|
||
- synchronization summaries no longer add exercise reconciliations to the
|
||
`exercices ajoutés` value. A compatible different-ID lookup that makes no
|
||
persistent change is reported as an idempotent skip, while real insertions
|
||
and real reconciliation mutations retain distinct counters. A production
|
||
PC-exporter/Android-importer regression proves zero additions and exact
|
||
business-table stability on the second and third imports;
|
||
- equipment companion import previously omitted its required `--database`
|
||
argument and blocked synchronization after a successful session import;
|
||
- PC catalogue/mobile export paths now accept schema v7 and preserve catalogue
|
||
tracking metadata; Android completed-session equipment editing now targets
|
||
the stable occurrence `entry_id`, not an ambiguous catalogue exercise ID;
|
||
- Android scoped-storage suffix selection now covers equipment associations as
|
||
well as mobile/definition artifacts; a historic V1 snapshot cannot consume a
|
||
neighboring V2 equipment companion;
|
||
- desktop-generated session occurrences now receive `sxe_<uuid-v4>` rather
|
||
than the synchronization-run `sy_` prefix; public generator capacity and C17
|
||
regression coverage include the three-character occurrence prefix;
|
||
- TUI footer help now advertises every active direct function key through F5;
|
||
|
||
- in-progress Android workout loss when leaving the foreground or recreating
|
||
the Activity/process;
|
||
- missing selected-exercise recovery preserves raw partial input and reports a
|
||
specific warning; draft write/finalization failures return explicit errors;
|
||
|
||
- stale schema-v4 importer call after desktop schema v5 migration;
|
||
- stale schema-v4 guard in the PC catalog exporter;
|
||
- missing `sy` prefix support in the UUID creator;
|
||
- synchronization failures that previously surfaced only as `error=unknown`;
|
||
- Android folder-selection UX so a wrong SAF folder can be changed without
|
||
clearing application data;
|
||
- libmtp terminal output leaking into terminal rendering.
|
||
|
||
### Validation
|
||
|
||
Current validated baseline:
|
||
|
||
```text
|
||
TRAINLOG_FORMAT_V1=FROZEN
|
||
|
||
DESKTOP_SCHEMA_V11=PASS
|
||
DESKTOP_TESTS=39/39 PASS
|
||
|
||
ANDROID_BUILD=PASS
|
||
ANDROID_LOCAL_WORKFLOWS=PASS
|
||
ANDROID_LOCAL_DATABASE_V10=PASS
|
||
ANDROID_TEST_DEBUG_UNIT=44/44 PASS (real v9 fixture enabled)
|
||
ANDROID_SESSION_DRAFT_V1=PASS
|
||
ANDROID_MAX_V9_REAL_DATA_MIGRATION=PASS
|
||
ANDROID_MAX_V9_INSTALL_ADB=PASS
|
||
|
||
USB_MTP_DETECTION=PASS
|
||
MTP_HARDWARE_ROUNDTRIP=HISTORICAL_PASS
|
||
REAL_ANDROID_ARTIFACT_COPY_ROUNDTRIP=HISTORICAL_PASS
|
||
BODY_ZONES_DESKTOP_REAL_DATABASE=PASS
|
||
BODY_ZONES_ANDROID_DEVICE=PASS
|
||
|
||
ANDROID_TO_PC_MTP=HISTORICAL_PASS
|
||
PC_TO_ANDROID_MTP_PUBLISH=HISTORICAL_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
|
||
BODY_ZONES_V1=PASS
|
||
BODY_ZONE_SYNC_V1=PASS
|
||
BODY_ZONES_DESKTOP_REAL_MIGRATION=PASS
|
||
BODY_ZONES_ANDROID_DEVICE_VALIDATION=PASS
|
||
```
|
||
|
||
For Body Zones V1, the real desktop database was backed up coherently and
|
||
migrated v10 -> v11 through the production binary. All eight pre-existing
|
||
tables compare equal row-for-row with the backup; integrity/FK checks pass and
|
||
the migration adds 32 direct relations for 20 of 23 exercises. On the Samsung
|
||
SM-G990B, the matching signed APK was installed with `adb install -r`; the real
|
||
Android database migrated v9 -> v10 with every pre-existing application row
|
||
unchanged, 32 relations for the same 20 exercises and the expected three
|
||
unclassified exercises. The Android zone/detail/filter/edit-cancel matrix and
|
||
two live PC <-> Android MTP passes completed successfully. The second pass
|
||
reported no additions or reconciliations and left every Android application
|
||
table and the semantic Body Zones companion unchanged. Scoped storage had
|
||
published the requests as exact `(N).json` collision siblings; the shared
|
||
engine now selects the newest request with the same deterministic helper used
|
||
for other Android-originated artifacts.
|
||
|
||
### Measured max v1
|
||
|
||
Added:
|
||
|
||
- explicit measured-max derivation from `max_test` sessions only;
|
||
- newest successful measured result and same-mode historical record;
|
||
- dedicated TUI measured-max history and graph;
|
||
- external working-load calculations at 60/70/80/90%;
|
||
- selectable 0.5/1/2.5/5.0 kg working-load rounding;
|
||
- direction-aware assistance measured-max semantics;
|
||
- Android `Entraînement` / `Test max` session selection;
|
||
- Android history/detail max-test identification;
|
||
- measured-max regression coverage.
|
||
|
||
No estimated 1RM, schema v6, or frozen Trainlog JSON v1 change was introduced.
|
||
|
||
### Body analytics v1
|
||
|
||
Added:
|
||
|
||
- desktop-only body analytics view;
|
||
- local height/formula estimation profile;
|
||
- circumference-based body-fat estimate;
|
||
- estimated fat and lean mass when real weight is available;
|
||
- waist/hip, shoulder/waist, and chest/waist ratios;
|
||
- arm, forearm, thigh, and calf left/right asymmetry percentages;
|
||
- weight, waist, and estimated-body-fat trend deltas;
|
||
- body analytics regression test.
|
||
|
||
Estimated analytics remain derived display values and are never persisted as
|
||
direct measurements. Android remains capture-only for this feature.
|
||
|
||
- Hid `SESSION_GENERATOR_V1` from normal UI pending V2; manual `%MAX` entry is unchanged.
|
||
- Added versioned canonical exercise display names, stale-peer-name convergence,
|
||
and the STATS_V1 query-contract preparation (no analytics implementation).
|
||
# Unreleased
|
||
|
||
- Add `TRAINING_FEEDBACK_V1`: schema v14 append-only exercise observations and
|
||
session follow-ups, Android French voice/manual capture with no audio storage,
|
||
bidirectional strict companion sync, H+ timelines, and TUI read-only display.
|