Refine domain interfaces from philosophy review

- Exercise is a property of an individual set, not of a set group: a group may span exercises (superset, pre-exhaust), so validation and performance reporting are keyed per set. - Drop Working_sets from set_scheme entirely. One working set per exercise is nominal and not configurable; deviation exists only at log time as acknowledged extra volume. - Warm-ups become a ramp: a list rather than at most one. - Anything prescribed is derived from logged evidence and carries it: 'a Progression.prescribed = { value; evidence; status }. Both exercise targets (Progression.prescribe) and rest windows (Recovery.prescribe) follow this shape. Recovery base now belongs to the routine. - Workout prescription takes a lookup function returning past logged workouts, from which targets are calculated. - Sessions record an end timestamp, giving workout duration. - Volume (load x reps) tracked per exercise and per workout as a diagnostic; under Heavy Duty rising volume is a warning, not progress. Still deferred pending a decision: the intensity factor metric. Verified: dune build, @check, @fmt, and runtest all green.

Commit
dbf07a96109d24beb029c64c1257efec8ff1b351
Author
Marius Peter <dev@marius-peter.com>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
lib/core/progression.ml
index cd8a2caf..fdbbc993 100644..100644
@@ -11,6 +11,9 @@
11 11 let evaluate ~history:_ = failwith "TODO"
12 12 let beats ~previous:_ ~current:_ = failwith "TODO"
13 13
14 Added: type 'a prescribed = { value : 'a; evidence : sample list; status : t }
15 Added: [@@warning "-69"]
16 Added:
14 17 type band = Below_range | In_range | Above_range
15 18
16 19 let classify ~target_reps:_ _ = failwith "TODO"
@@ -19,4 +22,5 @@
19 22 | Add_reps of { load : Units.Weight.t; min_reps : Units.Reps.t }
20 23 | Add_load of { min_load : Units.Weight.t; reps : Units.Reps.t }
21 24
22 Removed: let next_target ~target_reps:_ ~previous:_ = failwith "TODO"
25 Added: let prescribe ~target_reps:_ ~evidence:_ = failwith "TODO"
26 Added: let volume _ = failwith "TODO"
lib/core/progression.mli
index f331caac..e075c266 100644..100644
@@ -1,7 +1,9 @@
1 Removed: (** Progression: an observation about past working-set performance, distinct
2 Removed: from {!Hito_core.Routine.Prescription}. Encodes the HD imperative — beat the
3 Removed: last session; add reps within the prescribed band, then add load. *)
1 Added: (** Progression: what the evidence says about past performance, and what it
2 Added: prescribes next. Distinct from {!Hito_core.Routine.Prescription} (the plan).
4 3
4 Added: Encodes the HD imperative — beat the last session; add reps within the
5 Added: prescribed band, then add load. *)
6 Added:
5 7 type t = Progressing | Stalled
6 8
7 9 val equal : t -> t -> bool
@@ -16,6 +18,17 @@
16 18 val beats : previous:sample -> current:sample -> bool
17 19 (** Progressive overload: heavier, or equal load for more reps. *)
18 20
21 Added: (** {1 Prescription from evidence}
22 Added:
23 Added: Anything prescribed is derived from logged evidence and carries both the
24 Added: evidence and the status computed from it. *)
25 Added:
26 Added: type 'a prescribed = {
27 Added: value : 'a;
28 Added: evidence : sample list; (** Oldest-first history the value came from. *)
29 Added: status : t; (** What that evidence showed. *)
30 Added: }
31 Added:
19 32 (** Where a performance fell relative to the prescribed band. *)
20 33 type band =
21 34 | Below_range (** Load too heavy. *)
@@ -30,4 +43,12 @@
30 43 | Add_load of { min_load : Units.Weight.t; reps : Units.Reps.t }
31 44 (** Band exceeded: raise load, reset to the band's bottom. *)
32 45
33 Removed: val next_target : target_reps:Units.Rep_range.t -> previous:sample -> target
46 Added: val prescribe :
47 Added: target_reps:Units.Rep_range.t -> evidence:sample list -> target prescribed
48 Added: (** The next target, justified by the evidence it was computed from. *)
49 Added:
50 Added: (** {1 Metrics} *)
51 Added:
52 Added: val volume : sample list -> float
53 Added: (** Σ (load × reps), in kilogram-reps. Tracked as a diagnostic: under Heavy Duty
54 Added: rising volume is a warning, not an achievement. *)
lib/core/recovery.ml
index d07628bf..c19bcbef 100644..100644
@@ -9,12 +9,14 @@
9 9
10 10 let hours _ = failwith "TODO"
11 11 let days _ = failwith "TODO"
12 Removed: let recommended_recovery ~base:_ ~progression:_ = failwith "TODO"
12 Added: let duration_to_seconds _ = failwith "TODO"
13 13
14 14 module type CLOCK = sig
15 15 val now : unit -> timestamp
16 16 end
17 17
18 Added: let prescribe ~base:_ ~evidence:_ = failwith "TODO"
19 Added:
18 20 type readiness =
19 21 | Ready
20 22 | Recovering of { elapsed : duration; recommended : duration }
@@ -32,6 +34,9 @@
32 34 ~acknowledged:_ =
33 35 failwith "TODO"
34 36
37 Added: let end_session _ _ = failwith "TODO"
35 38 let started_at _ = failwith "TODO"
39 Added: let ended_at _ = failwith "TODO"
40 Added: let elapsed _ = failwith "TODO"
36 41 let overridden_recovery _ = failwith "TODO"
37 42 let pp_session _ _ = failwith "TODO"
lib/core/recovery.mli
index 062a5f58..fe79b16b 100644..100644
@@ -1,10 +1,9 @@
1 Removed: (** The recovery model (invariant #2).
1 Added: (** Recovery: systemic and time-based — training is a whole-body stressor, so a
2 Added: workout gates the next one regardless of what it targeted.
2 3
3 Removed: Recovery is systemic and time-based: training is a whole-body stressor, so a
4 Removed: heavy workout gates the next one regardless of which movements it targeted.
5 Removed: Gating is advisory, not inviolable — {!start_session} warns when the window
6 Removed: has not elapsed, and only {!start_session_overriding_recovery} proceeds
7 Removed: anyway, recording the override. Time is injected via {!CLOCK}. *)
4 Added: Gating is advisory, not inviolable: {!start_session} refuses when the window
5 Added: has not elapsed, and only {!start_session_overriding_recovery} proceeds,
6 Added: recording the override. Time is injected via {!CLOCK}. *)
8 7
9 8 (** {1 Time} *)
10 9
@@ -17,15 +16,24 @@
17 16
18 17 val hours : int -> duration
19 18 val days : int -> duration
19 Added: val duration_to_seconds : duration -> int
20 20
21 Removed: val recommended_recovery :
22 Removed: base:duration -> progression:Progression.t -> duration
23 Removed: (** Adaptive window: a stall lengthens rest (fuller recovery, not more work). *)
24 Removed:
25 21 module type CLOCK = sig
26 22 val now : unit -> timestamp
27 23 end
28 24
25 Added: (** {1 Prescribed recovery}
26 Added:
27 Added: Like exercise prescription, the rest window is derived from logged evidence
28 Added: and carries the justification for the figure. *)
29 Added:
30 Added: val prescribe :
31 Added: base:duration ->
32 Added: evidence:Progression.sample list ->
33 Added: duration Progression.prescribed
34 Added: (** [base] is the routine's nominal window; a stall lengthens it — fuller
35 Added: recovery rather than more work. *)
36 Added:
29 37 (** {1 Readiness} *)
30 38
31 39 type readiness =
@@ -48,8 +56,7 @@
48 56 last_workout:timestamp option ->
49 57 recommended:duration ->
50 58 (session, error) result
51 Removed: (** [Ok] iff recovered; [last_workout] is [None] for the very first workout
52 Removed: (always ready). *)
59 Added: (** [last_workout] is [None] for the first workout. *)
53 60
54 61 val start_session_overriding_recovery :
55 62 (module CLOCK) ->
@@ -59,9 +66,16 @@
59 66 session
60 67 (** Always succeeds; records an {!override_reason}. *)
61 68
69 Added: val end_session : (module CLOCK) -> session -> session
70 Added: (** Stamp the session's end, fixing its {!elapsed} duration. *)
71 Added:
62 72 val started_at : session -> timestamp
73 Added: val ended_at : session -> timestamp option
63 74
75 Added: val elapsed : session -> duration option
76 Added: (** Wall-clock duration, once ended. Feeds the intensity metric. *)
77 Added:
64 78 val overridden_recovery : session -> override_reason option
65 Removed: (** [Some _] iff the session was started early. *)
79 Added: (** [Some _] iff started early. *)
66 80
67 81 val pp_session : Format.formatter -> session -> unit
lib/core/routine.ml
index 4f690702..f3622e5c 100644..100644
@@ -1,28 +1,12 @@
1 1 (* Minimal stubs only; implementation deferred until after the review gate. *)
2 2
3 Removed: type set_scheme = Single_working_set | Working_sets of int
4 Removed:
5 Removed: let is_high_intensity_compliant _ = failwith "TODO"
6 Removed:
7 3 module Prescription = struct
8 4 type t = unit
9 5
10 Removed: let make ~exercise:_ ~target_reps:_ ~set_scheme:_ ~allowed_substitutes:_ =
11 Removed: failwith "TODO"
12 Removed:
6 Added: let make ~exercise:_ ~target_reps:_ ~allowed_substitutes:_ = failwith "TODO"
13 7 let exercise _ = failwith "TODO"
14 8 let target_reps _ = failwith "TODO"
15 Removed: let set_scheme _ = failwith "TODO"
16 9 let allowed_substitutes _ = failwith "TODO"
17 Removed:
18 Removed: type guidance = {
19 Removed: band : Progression.band;
20 Removed: next : Progression.target;
21 Removed: compliant : bool;
22 Removed: }
23 Removed: [@@warning "-69"]
24 Removed:
25 Removed: let evaluate _ ~performance:_ ~compliant:_ = failwith "TODO"
26 10 let pp _ _ = failwith "TODO"
27 11 end
28 12
@@ -32,6 +16,7 @@
32 16 let make ~name:_ ~prescriptions:_ = failwith "TODO"
33 17 let name _ = failwith "TODO"
34 18 let prescriptions _ = failwith "TODO"
19 Added: let recovery_base _ = failwith "TODO"
35 20 let pp _ _ = failwith "TODO"
36 21 let ideal_routine = ()
37 22 let consolidation_routine = ()
lib/core/routine.mli
index abd8b8c1..40f99b1b 100644..100644
@@ -1,45 +1,22 @@
1 1 (** Routines and prescriptions.
2 2
3 Removed: A prescription is the plan for one exercise (movement, target reps, set
4 Removed: scheme, allowed substitutes); a routine is an ordered list of them. Kept
5 Removed: separate from {!Hito_core.Workout} (plan vs performed) and
6 Removed: {!Hito_core.Progression} (plan vs observation). Substitutes must be on the
7 Removed: exercise's catalog whitelist, so a routine can only narrow the curated set.
8 Removed: *)
3 Added: A prescription is the plan for one exercise; a routine is an ordered list of
4 Added: them. Heavy Duty prescribes exactly one working set per exercise — that is
5 Added: nominal and not configurable. Deviation exists only at log time, as
6 Added: acknowledged extra volume. *)
9 7
10 Removed: type set_scheme = Single_working_set | Working_sets of int
11 Removed:
12 Removed: val is_high_intensity_compliant : set_scheme -> bool
13 Removed: (** [true] only for [Single_working_set]: Heavy Duty holds that volume beyond
14 Removed: the minimum interferes with recovery, so [Working_sets n] is an explicit,
15 Removed: visible deviation. *)
16 Removed:
17 8 module Prescription : sig
18 9 type t
19 10
20 11 val make :
21 12 exercise:Exercise.t ->
22 13 target_reps:Units.Rep_range.t ->
23 Removed: set_scheme:set_scheme ->
24 14 allowed_substitutes:Exercise.t list ->
25 15 (t, Exercise.error) result
26 16
27 17 val exercise : t -> Exercise.t
28 18 val target_reps : t -> Units.Rep_range.t
29 Removed: val set_scheme : t -> set_scheme
30 19 val allowed_substitutes : t -> Exercise.t list
31 Removed:
32 Removed: type guidance = {
33 Removed: band : Progression.band;
34 Removed: next : Progression.target;
35 Removed: compliant : bool; (** Whether prescribed volume was respected. *)
36 Removed: }
37 Removed: (** Guidance from comparing a performance to this prescription. *)
38 Removed:
39 Removed: val evaluate :
40 Removed: t -> performance:Progression.sample -> compliant:bool -> guidance
41 Removed: (** Judge a performed working set against the plan. *)
42 Removed:
43 20 val pp : Format.formatter -> t -> unit
44 21 end
45 22
@@ -51,6 +28,11 @@
51 28 val make : name:string -> prescriptions:Prescription.t list -> (t, error) result
52 29 val name : t -> string
53 30 val prescriptions : t -> Prescription.t list
31 Added:
32 Added: val recovery_base : t -> Recovery.duration
33 Added: (** The routine's nominal rest between sessions; Consolidation rests longer than
34 Added: Ideal. Evidence adjusts it (see {!Hito_core.Recovery.prescribe}). *)
35 Added:
54 36 val pp : Format.formatter -> t -> unit
55 37
56 38 (** {1 Heavy Duty presets} *)
lib/core/set_group.ml
index 8c9eae8a..ae5c3737 100644..100644
@@ -3,22 +3,26 @@
3 3 type t = unit
4 4 type extra_volume = { sets : Set.Working.t list; acknowledged : string }
5 5
6 Removed: let straight ?warm_up:_ ?extra:_ ~working:_ () = failwith "TODO"
7 Removed: let superset ~first:_ ~second:_ ?rest:_ () = failwith "TODO"
8 Removed: let pre_exhaust ~isolation:_ ~compound:_ = failwith "TODO"
6 Added: let straight ?warm_ups:_ ?extra:_ ~working:_ () = failwith "TODO"
7 Added: let superset ?warm_ups:_ ~first:_ ~second:_ ?rest:_ () = failwith "TODO"
8 Added: let pre_exhaust ?warm_ups:_ ~isolation:_ ~compound:_ () = failwith "TODO"
9 9
10 10 type view =
11 11 | Straight of {
12 Removed: warm_up : Set.Warm_up.t option;
12 Added: warm_ups : Set.Warm_up.t list;
13 13 working : Set.Working.t;
14 14 extra : extra_volume option;
15 15 }
16 Removed: | Superset of Set.Working.t list
17 Removed: | Pre_exhaust of { isolation : Set.Working.t; compound : Set.Working.t }
16 Added: | Superset of { warm_ups : Set.Warm_up.t list; sets : Set.Working.t list }
17 Added: | Pre_exhaust of {
18 Added: warm_ups : Set.Warm_up.t list;
19 Added: isolation : Set.Working.t;
20 Added: compound : Set.Working.t;
21 Added: }
18 22
19 23 let view _ = failwith "TODO"
20 24 let working_sets _ = failwith "TODO"
21 Removed: let exercises _ = failwith "TODO"
25 Added: let warm_ups _ = failwith "TODO"
22 26 let extra_volume _ = failwith "TODO"
23 27 let is_high_intensity_compliant _ = failwith "TODO"
24 28 let pp _ _ = failwith "TODO"
lib/core/set_group.mli
index 91c04473..affb2f98 100644..100644
@@ -1,4 +1,7 @@
1 Removed: (** How working sets are grouped and sequenced within a workout. Each shape is
1 Added: (** How working sets are grouped and sequenced within a workout.
2 Added:
3 Added: A group may span several exercises (superset, pre-exhaust), so the exercise
4 Added: is a property of each individual set, never of the group. Each shape is
2 5 enforced by construction, so every constructor returns a plain group. *)
3 6
4 7 type t
@@ -8,14 +11,15 @@
8 11 never silent — they must be acknowledged, as an early workout must be. *)
9 12
10 13 val straight :
11 Removed: ?warm_up:Set.Warm_up.t ->
14 Added: ?warm_ups:Set.Warm_up.t list ->
12 15 ?extra:extra_volume ->
13 16 working:Set.Working.t ->
14 17 unit ->
15 18 t
16 Removed: (** One exercise: the working set, optionally warmed up and extended. *)
19 Added: (** One exercise: the working set, optionally preceded by a warm-up ramp. *)
17 20
18 21 val superset :
22 Added: ?warm_ups:Set.Warm_up.t list ->
19 23 first:Set.Working.t ->
20 24 second:Set.Working.t ->
21 25 ?rest:Set.Working.t list ->
@@ -23,7 +27,12 @@
23 27 t
24 28 (** Working sets across exercises, back-to-back. *)
25 29
26 Removed: val pre_exhaust : isolation:Set.Working.t -> compound:Set.Working.t -> t
30 Added: val pre_exhaust :
31 Added: ?warm_ups:Set.Warm_up.t list ->
32 Added: isolation:Set.Working.t ->
33 Added: compound:Set.Working.t ->
34 Added: unit ->
35 Added: t
27 36 (** Isolation immediately followed by a compound — the signature HD technique.
28 37 *)
29 38
@@ -31,19 +40,23 @@
31 40
32 41 type view =
33 42 | Straight of {
34 Removed: warm_up : Set.Warm_up.t option;
43 Added: warm_ups : Set.Warm_up.t list;
35 44 working : Set.Working.t;
36 45 extra : extra_volume option;
37 46 }
38 Removed: | Superset of Set.Working.t list
39 Removed: | Pre_exhaust of { isolation : Set.Working.t; compound : Set.Working.t }
47 Added: | Superset of { warm_ups : Set.Warm_up.t list; sets : Set.Working.t list }
48 Added: | Pre_exhaust of {
49 Added: warm_ups : Set.Warm_up.t list;
50 Added: isolation : Set.Working.t;
51 Added: compound : Set.Working.t;
52 Added: }
40 53
41 54 val view : t -> view
42 55
43 56 val working_sets : t -> Set.Working.t list
44 Removed: (** Every working set, in order. *)
57 Added: (** Every working set, in order. Each carries its own exercise. *)
45 58
46 Removed: val exercises : t -> Exercise.t list
59 Added: val warm_ups : t -> Set.Warm_up.t list
47 60 val extra_volume : t -> extra_volume option
48 61
49 62 val is_high_intensity_compliant : t -> bool
lib/core/workout.ml
index ef4f398f..ba9875fa 100644..100644
@@ -1,35 +1,38 @@
1 1 (* Minimal stubs only; implementation deferred until after the review gate. *)
2 2
3 Added: module Logged = struct
4 Added: type t = unit
5 Added: type error = Set_exercise_not_prescribed of Exercise.id | Already_finished
6 Added:
7 Added: let add_group _ _ = failwith "TODO"
8 Added: let finish _ _ = failwith "TODO"
9 Added: let is_finished _ = failwith "TODO"
10 Added: let session _ = failwith "TODO"
11 Added: let groups _ = failwith "TODO"
12 Added: let working_sets _ = failwith "TODO"
13 Added: let performances _ = failwith "TODO"
14 Added: let unperformed _ = failwith "TODO"
15 Added: let volume _ = failwith "TODO"
16 Added: let duration _ = failwith "TODO"
17 Added: let pp _ _ = failwith "TODO"
18 Added: end
19 Added:
3 20 module Prescribed = struct
4 21 type t = unit
5 22
6 23 type item = {
7 24 prescription : Routine.Prescription.t;
8 25 exercise : Exercise.t;
9 Removed: target : Progression.target option;
26 Added: target : Progression.target Progression.prescribed option;
10 27 }
11 28 [@@warning "-69"]
12 29
13 30 type error = Not_substitutable of Exercise.error
14 31
15 Removed: let create ~routine:_ ~substitutions:_ ~history:_ = failwith "TODO"
32 Added: let create ~routine:_ ~substitutions:_ ~logs:_ = failwith "TODO"
16 33 let routine _ = failwith "TODO"
17 34 let items _ = failwith "TODO"
18 Removed: let pp _ _ = failwith "TODO"
19 Removed: end
20 Removed:
21 Removed: module Logged = struct
22 Removed: type t = unit
23 Removed: type error = Exercise_not_prescribed of Exercise.id | Already_finished
24 Removed:
25 Removed: let start ~prescribed:_ ~session:_ = failwith "TODO"
26 Removed: let add_group _ _ = failwith "TODO"
27 Removed: let finish _ = failwith "TODO"
28 Removed: let is_finished _ = failwith "TODO"
29 Removed: let prescribed _ = failwith "TODO"
30 Removed: let session _ = failwith "TODO"
31 Removed: let groups _ = failwith "TODO"
32 Removed: let guidance _ = failwith "TODO"
33 Removed: let unperformed _ = failwith "TODO"
35 Added: let recovery _ = failwith "TODO"
36 Added: let start _ _ _ = failwith "TODO"
34 37 let pp _ _ = failwith "TODO"
35 38 end
lib/core/workout.mli
index d0d613db..e9793670 100644..100644
@@ -2,7 +2,50 @@
2 2 {!Logged} (what happened). Distinct types with a one-way transition, so a
3 3 plan can never be mistaken for a record. *)
4 4
5 Removed: (** This session's plan: a routine instantiated with concrete targets. *)
5 Added: (** The record of a performed session. Defined first because a prescription is
6 Added: derived from past logs. *)
7 Added: module Logged : sig
8 Added: type t
9 Added:
10 Added: type error =
11 Added: | Set_exercise_not_prescribed of Exercise.id
12 Added: (** A set's exercise is neither prescribed nor a permitted substitute.
13 Added: *)
14 Added: | Already_finished
15 Added:
16 Added: val add_group : t -> Set_group.t -> (t, error) result
17 Added: (** Append a performed group. Every working set's exercise is validated
18 Added: individually, since a group may span exercises. *)
19 Added:
20 Added: val finish : (module Recovery.CLOCK) -> t -> t
21 Added: (** Complete the workout and stamp the session's end. *)
22 Added:
23 Added: val is_finished : t -> bool
24 Added: val session : t -> Recovery.session
25 Added: val groups : t -> Set_group.t list
26 Added:
27 Added: val working_sets : t -> Set.Working.t list
28 Added: (** Every working set performed, in order. *)
29 Added:
30 Added: val performances : t -> (Exercise.id * Progression.sample) list
31 Added: (** Each working set's performance, keyed by its own exercise. *)
32 Added:
33 Added: val unperformed : t -> Exercise.t list
34 Added: (** Prescribed exercises with no logged working set. *)
35 Added:
36 Added: (** {1 Workout-level metrics} *)
37 Added:
38 Added: val volume : t -> float
39 Added: (** Σ (load × reps) across all working sets. Diagnostic, not a target. *)
40 Added:
41 Added: val duration : t -> Recovery.duration option
42 Added: (** Wall-clock time, once finished. *)
43 Added:
44 Added: val pp : Format.formatter -> t -> unit
45 Added: end
46 Added:
47 Added: (** This session's plan: a routine instantiated with targets derived from logs.
48 Added: *)
6 49 module Prescribed : sig
7 50 type t
8 51
@@ -10,7 +53,8 @@
10 53 prescription : Routine.Prescription.t;
11 54 exercise : Exercise.t;
12 55 (** The prescribed movement, or a chosen substitute. *)
13 Removed: target : Progression.target option; (** [None] with nothing to beat yet. *)
56 Added: target : Progression.target Progression.prescribed option;
57 Added: (** [None] with no prior evidence. *)
14 58 }
15 59 (** One exercise's plan for this session. *)
16 60
@@ -19,39 +63,19 @@
19 63 val create :
20 64 routine:Routine.t ->
21 65 substitutions:(Exercise.id * Exercise.t) list ->
22 Removed: history:(Exercise.id * Progression.sample) list ->
66 Added: logs:(Exercise.id -> Logged.t list) ->
23 67 (t, error) result
24 Removed: (** Instantiate [routine] for this session, deriving targets from [history].
25 Removed: *)
68 Added: (** Instantiate [routine] for this session. [logs] yields the past logged
69 Added: workouts for an exercise, from which its target is calculated. *)
26 70
27 71 val routine : t -> Routine.t
28 72 val items : t -> item list
29 Removed: val pp : Format.formatter -> t -> unit
30 Removed: end
31 73
32 Removed: (** The record of a performed session. *)
33 Removed: module Logged : sig
34 Removed: type t
35 Removed: type error = Exercise_not_prescribed of Exercise.id | Already_finished
74 Added: val recovery : t -> Recovery.duration Progression.prescribed
75 Added: (** The rest window prescribed before the next session. *)
36 76
37 Removed: val start : prescribed:Prescribed.t -> session:Recovery.session -> t
38 Removed:
39 Removed: val add_group : t -> Set_group.t -> (t, error) result
40 Removed: (** Append a performed set group. *)
41 Removed:
42 Removed: val finish : t -> t
43 Removed: (** Complete the workout; further groups are rejected. *)
44 Removed:
45 Removed: val is_finished : t -> bool
46 Removed: val prescribed : t -> Prescribed.t
47 Removed: val session : t -> Recovery.session
48 Removed: val groups : t -> Set_group.t list
49 Removed:
50 Removed: val guidance : t -> (Exercise.t * Routine.Prescription.guidance) list
51 Removed: (** What was performed, judged against the plan. *)
52 Removed:
53 Removed: val unperformed : t -> Exercise.t list
54 Removed: (** Prescribed exercises with no logged set group. *)
77 Added: val start : (module Recovery.CLOCK) -> t -> Recovery.session -> Logged.t
78 Added: (** Begin logging against this plan. *)
55 79
56 80 val pp : Format.formatter -> t -> unit
57 81 end