[OCaml] High Intensity Training Online
docs Document workout import and promotion
Document canonical observations, the provisional import lifecycle, strict Hevy adapter, whole-workout and partial-batch promotion, immutable source and provenance, persistence independence, merged Progression insights, recovery gating, routes, and layered test coverage.
ARCHITECTURE.org
@@ -227,6 +227,12 @@
227
227
oldest first, and =readiness= computed from the last finished workout. Evidence
228
228
is dated because a stall is *defined* by two weeks of nothing.
229
229
230
Added:
=Observation= is the canonical insight input: a catalogued exercise, a confirmed
231
Added:
effort, and a performance time. Native workouts produce observations through
232
Added:
=Log=. A cleaned import can produce the same type without pretending that it had
233
Added:
a prescription or clearance. =Progression= judges observations and therefore
234
Added:
does not know their provenance.
235
Added:
230
236
=Feedback= is a typed vocabulary for reported signals — sleep, appetite,
231
237
readiness, motivation, difficulty, pain, injury, insufficient preparation — with
232
238
duplicate categories rejected. Leveled signals carry a five-point score, 1 (very
@@ -333,6 +339,37 @@
333
339
destination. =Handlers.error_handler=, wired into =Dream.run=, covers the rest:
334
340
=5xx= responses and uncaught exceptions.
335
341
342
Added:
** Workout import
343
Added:
344
Added:
Native Hevy CSV import is an application use case, not a core entity. The
345
Added:
=Hevy_csv= web adapter parses the strict 14-column native format and retains the
346
Added:
complete source text. The upload supplies an explicit UTC offset because Hevy
347
Added:
exports local wall time without a timezone.
348
Added:
349
Added:
A =Workout_import.batch= owns provisional workouts, ordered warnings, confirmed
350
Added:
exercise mappings, workout-level acknowledgements, revisions, and prior
351
Added:
promotion state. Warm-ups and unsupported rows create warnings but no
352
Added:
provisional sets. A drop set blocks its complete workout. A normal set requires
353
Added:
one explicit acknowledgement for the workout. Every exercise mapping requires
354
Added:
user confirmation.
355
Added:
356
Added:
Promotion is atomic for one workout and partial for a batch. Eligible workouts
357
Added:
promote while blocked workouts remain provisional for later review. Each
358
Added:
promoted set becomes one confirmed =Evidence.Observation=. The promoted record
359
Added:
retains batch identity, workout identity, source rows, acknowledgement, and
360
Added:
revision. Re-promotion after an edit replaces the prior observations instead of
361
Added:
adding duplicates.
362
Added:
363
Added:
Provisional batches and promoted records have independent lifecycles. Deleting
364
Added:
a batch never deletes promoted evidence. The original CSV remains immutable so
365
Added:
a later importer can reprocess rows that the current version dropped.
366
Added:
367
Added:
Promoted observations feed =Progression= with native observations. Provenance
368
Added:
does not change judgment. The latest promoted workout also gates recovery with
369
Added:
the routine's 48-hour training interval when it is newer than native evidence.
370
Added:
Imports never advance routine rotation, and diagnostics remain native-only
371
Added:
because imports do not carry prescription volume or clearance structure.
372
Added:
336
373
* The cycle
337
374
338
375
#+begin_src mermaid
@@ -399,6 +436,12 @@
399
436
| =/profile= | GET | Account profile: rename and change password |
400
437
| =/profile/username= | POST | Change the username |
401
438
| =/profile/password= | POST | Change the password (verifies the current one) |
439
Added:
| =/profile/import= | POST | Upload a native Hevy CSV export |
440
Added:
| =/profile/import/:id= | GET | Review one provisional import batch |
441
Added:
| =/profile/import/:id/workouts/:workout/map= | POST | Confirm one exercise mapping |
442
Added:
| =/profile/import/:id/workouts/:workout/confirm= | POST | Confirm all normal sets in a workout |
443
Added:
| =/profile/import/:id/workouts/:workout/promote= | POST | Promote one eligible workout |
444
Added:
| =/profile/import/:id/promote= | POST | Promote every eligible workout in a batch |
402
445
| =/assets/hito.css= | GET | Stylesheet (embedded at build time) |
403
446
| =/assets/workout-client.js= | GET | Enhancement client (embedded at build time) |
404
447
@@ -511,6 +554,15 @@
511
554
- =test_bcrypt_hash= — the hashing adapter satisfies the =Password_hash.S=
512
555
port: a hash verifies against itself, a wrong password fails, and a malformed
513
556
stored hash is rejected rather than raised.
557
Added:
- =test_workout_import= — provisional cleaning, blockers, whole-workout
558
Added:
promotion, partial batches, provenance, revision replacement, and idempotence.
559
Added:
- =test_hevy_csv= — the native schema, RFC4180 fields, explicit timezone offset,
560
Added:
grouping, warm-up and unsupported-row warnings, and immutable source retention.
561
Added:
- =test_import_codec=, =test_import_repo=, and =test_import_sqlite= — safe
562
Added:
round-trip storage, reconnects, trainee isolation, replacement, and independent
563
Added:
batch and promoted-record lifecycles.
564
Added:
- =test_import_service= — duplicate override, cleaning persistence, partial
565
Added:
promotion, merged insights, recovery gating, and native-only routine rotation.
514
566
- =test_codec= — a stored workout round-trips faithfully, and
515
567
malformed or incomplete text is *reported*, not raised.
516
568
- =test_sqlite_repo= — state survives a reconnect, trainees stay