# Trainlog Web Sessions V1 contract Status: implementation contract for `TRAINLOG_WEB_SESSIONS_V1`. ## Scope and domain boundaries The Sessions route has four independent views: - Preparation lists manual preparations and immutable imported AI proposals. - Resume lists lifecycle-backed execution drafts that are not finalized or causally deleted. - History lists completed sessions. A missing `ended_at` is rendered as an unknown end time; it does not make a historical row an active draft. - Programs lists durable planning definitions and can explicitly derive a manual preparation. An AI proposal is never mutated by viewing it or by deriving a manual preparation. Derivation is an explicit command which creates a new `sp_` preparation and records the proposal ID and payload fingerprint used. A manual preparation is not an execution draft or completed session. ## Manual preparation persistence Desktop schema v23 adds: - `session_preparations`, the mutable head and delivery state; - `session_preparation_revisions`, immutable revision metadata; - `session_preparation_entries`, immutable ordered occurrence snapshots; - `session_preparation_requests`, durable HTTP idempotency results; - `session_preparation_deliveries`, the preparation-revision to execution identity relation. Preparation IDs use `sp_`, occurrence IDs use `spe_`, revision IDs use `spr_`, and execution IDs use the existing `se_` namespace. Revision content is immutable. Updating a preparation inserts a complete successor revision and atomically advances the head. Occurrence IDs survive reordering and compatible edits. Two occurrences of one exercise remain distinct. `editing_state` (`draft` or `ready`) and `delivery_state` (`local`, `pending`, `acknowledged`, `remote_unknown`, or `cancelled`) are independent. Marking a complete revision ready changes no Android state. Preparing it for Android creates one durable delivery and deterministic execution identity per explicit command. Retrying the command with its idempotency key returns that same identity. Later preparation edits never alter a published revision or execution. ## Validation Titles and notes are UTF-8 and bounded by the existing name/note limits. A preparation may be saved with no occurrences while it is a draft. Ready revisions require a non-empty title and at least one occurrence. Every occurrence resolves a non-retired exercise and a compatible equipment choice at commit time. `SETS/REPS`, `SETS/DURATION`, and `CONTINUOUS/DURATION` are the only legal profiles. Continuous work has a duration target and never a target set. Assistance, external load, and no load remain distinct. JSON `null`, zero, and absence retain distinct meanings; non-finite numbers are rejected by the JSON parser and Core validation. Every update supplies the expected revision and is checked in the write transaction. A mismatch returns a conflict without partial mutation. Request idempotency is persistent, so a lost HTTP response can be replayed without creating another preparation. ## Read API Lists use bounded offset pages with deterministic stable-ID tie breaking. The response returns a snapshot revision. If a write changes that revision between page requests, the client discards its accumulated pages and explicitly reloads. Search matches the title or an exercise display name. Dates mean planned calendar dates for preparations and occurrence dates for history. Zones are offered only where the persisted exercise relations provide them. Stable details are addressed by kind and identity under `/api/v1/sessions/...`. Unknown API routes remain JSON 404 responses; recognized non-API paths use the embedded SPA fallback. ## Synchronization and Android Ready deliveries use a separate `trainlog-session-preparations` V1 generation participant. It does not change `TRAINLOG_FORMAT_V1`, mobile V3/V4, or execution-drafts V1. The artifact contains complete immutable revision snapshots and explicit cancellation state. Android consumes a delivery into a pending prepared-session store. Starting it is an explicit Android action: an occupied active-draft singleton is never overwritten. Consumption and start are idempotent by delivery, preparation, revision, execution, and occurrence IDs. Delivery is shown as acknowledged only when the correlated generation ACK proves that the exact artifact containing that revision was consumed. Publication time or a global successful sync is not sufficient evidence. Old peers which do not advertise this participant are rejected before a generation containing it is published. ## Explicit exclusions Program V1 and its import boundary are specified separately in [`program_format_v1.md`](../program_format_v1.md). They do not turn a program into a template, proposal, draft or completed session. This V1 does not implement Analysis or the standalone Exercises route. It does not add live Web workout capture, historical correction, automatic training prescriptions, proposal acceptance, or automatic proposal-to-execution conversion.