trainlog/docs/program_format_v1.md

99 lines
5.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Trainlog Program format V1
`trainlog-program` V1 is a strict desktop import format for planning data. It
does not change `TRAINLOG_FORMAT_V1` and is not an Android synchronization
artifact.
## Identity and ownership
A program, each ordered session definition and each ordered exercise occurrence
has a non-empty stable import identity of at most 128 UTF-8 bytes. The `pg_`,
`pgs_`, and `pge_` UUIDv4 forms are recommended creator forms, while imported
identities remain opaque. Display titles are not identities. A program is not a
reusable session template, AI proposal, manual preparation, execution draft or
completed session.
Desktop schema v26 owns the imported program and its exact source SHA-256.
Exact same-ID content replay is idempotent. The same ID with a different byte
payload is an explicit conflict. A different ID may reuse a title because titles
have no identity semantics.
## Document shape
The root has exactly `format`, `version`, and `program`, with format
`trainlog-program` and integer version `1`. The program object has exactly:
- `program_id`, `title`, nullable `note`, `state`, nullable `start_date`,
nullable `end_date`, and `sessions`;
- state `active` on import;
- 1–64 ordered sessions;
- title length 1–200 UTF-8 bytes and note length at most 4,000;
- canonical `YYYY-MM-DD` civil dates, with the end not before the start.
Each session has exactly `program_session_id`, `title`, `session_type`, nullable
`planned_for`, nullable `note`, and `occurrences`. Session type is `training` or
`max_test`; each session contains 1–64 occurrences.
Each occurrence has exactly `entry_id`, `exercise_id`, nullable `equipment_id`,
`load_mode`, `rest_seconds`, nullable `target_sets`, nullable `target_reps`,
nullable `target_duration_seconds`, nullable `target_weight_kg`, and nullable
`notes`. Exercise and equipment identities must already resolve in the desktop
catalog. Recording/tracking profiles and target/load combinations are validated
by the same Core rules used for manual preparations. No actual set, MAX result,
completion timestamp or other performed field is accepted.
The complete UTF-8 JSON document is limited to 512 KiB. Duplicate object keys,
unknown keys, non-finite numbers, invalid UTF-8, duplicate identities, excessive
collections and incompatible profiles are rejected before any row is written.
## Preview, commit and lifecycle
The Web file picker sends bytes to the Core validation endpoint first. Its
preview reports identity, title, dates, session count, unknown-exercise count
and warnings while leaving the database unchanged. Import occurs only after the
user confirms and commits all program/session/occurrence/source rows in one
transaction.
Archive is a revision-guarded lifecycle transition. It hides no derived data
and retains the source definition and digest. Creating a preparation from one
session is a separate idempotent command that copies the ordered plan and stores
program/session provenance on a new `sp_<uuid-v4>` manual preparation. It does
not create a delivery, Android object, execution draft, completed session or
performed measurement.
Deletion is a separate terminal logical lifecycle transition. It is allowed
from active or archived state, records request/deleted revisions and durable
response replay in the desktop `program_deletions` ledger, and retains the
source definition and derived preparations. A deleted program cannot be
resurrected or prepared; an archived program cannot be prepared. The optional
`trainlog-programs` V1 synchronization companion is a separate PC-to-Android
projection and does not alter this import format.
## Explicit ordered rescheduling in the audited development line
The `trainlog-program-recalage-v1` line adds a separate planning
state. `planned_for` remains the imported date. `current_for` is an absolute
current target for an active, unfinished session; `ceded` releases one selected
future slot without completing or deleting its session identity. Completed
cards still use the linked session's actual start timestamp. Positions from the
imported Program determine the cascade order; titles never determine priority.
The Web action selects a first and last unfinished session, a resumption date,
and the exact session identities whose slots are ceded. Its available days are
the dated original Program slots in that interval on or after resumption.
The preview lists original, prior current and proposed dates. It rejects a
missing slot, a date beyond the Program end, a completed/in-progress/prepared
session, or a stale revision. It does not invent rest-day or post-end slots.
An explicitly ceded session keeps its identity and remains visible as ceded.
Unchanged sessions in the selected range are displayed in the preview but need
no planning row. Other sessions and Programs are not moved. Multiple actual or
independent sessions may still share one civil day.
Confirmation binds the preview fingerprint to the current Program projection
and writes absolute dates, ceded states, the Program revision and a durable
operation response in one transaction. Exact operation replay returns that
response; changed content under the same operation ID conflicts. A failed
write rolls back every row. The development implementation requires a recent acknowledged
Programs V2 generation for every previously contacted Android peer. A newly
started offline Android Program draft remains protected by Android's V2 import
rejection; the sync run then reports a conflict for explicit resolution.