[OCaml] High Intensity Training Online
docs pare interface documentation further
Core interfaces now retain only caller-visible invariants, ordering, and edge cases. Remove repeated Heavy Duty rationale and design narration; project steering and the local doctrine reference remain the source for broader context.
Changed files
lib/core/evidence.mli
@@ -1,34 +1,18 @@
1
Removed:
(** The record: what was actually done, at every scale {!Prescription} plans
2
Removed:
one.
1
Added:
(** Recorded stimuli, workouts, and history. Recording never judges. *)
3
2
4
Removed:
The only source of evidence in the system. It records; it does not interpret
5
Removed:
— what the evidence means is {!Progression}'s business, and a stimulus that
6
Removed:
should not have been performed is still recorded. *)
7
Removed:
8
Removed:
(** One stimulus: a single drive to muscular failure, and the record of what it
9
Removed:
took.
10
Removed:
11
Removed:
The unit of work. HD1 prescribes one set per exercise, so there is no set
12
Removed:
count. Reaching failure is not recorded because it is not optional — a
13
Removed:
movement here always went to failure. *)
3
Added:
(** One performed drive to failure. *)
14
4
module Stimulus : sig
15
Removed:
(** A means of continuing past positive failure. HD1 treats these as
16
Removed:
occasional: used on every exercise they lead straight to overtraining, and
17
Removed:
forced reps and negatives both need a spotter. *)
18
5
type extension = Forced_reps | Negatives | Rest_pause | Static_hold
19
6
20
Removed:
(** How the drive ended. *)
21
7
type outcome =
22
Removed:
| Positive_failure (** Unable to complete another rep unaided. *)
8
Added:
| Positive_failure
23
9
| Beyond_failure of extension * extension list
24
Removed:
(** In the order applied — HD1 stacks negatives after forced reps. Split
25
Removed:
so that "beyond failure by no means at all" cannot be written. *)
10
Added:
(** Nonempty, in application order. *)
26
11
27
12
val extensions_of_outcome : outcome -> extension list
28
13
val pp_extension : Format.formatter -> extension -> unit
29
14
30
Removed:
(** Preparation for a stimulus: enough to bring blood to the muscles and
31
Removed:
joints, no more. Carries no outcome, so a warm-up cannot reach failure. *)
15
Added:
(** Preparation; it has no failure outcome. *)
32
16
module Warm_up : sig
33
17
type t
34
18
@@ -41,7 +25,6 @@
41
25
val pp : Format.formatter -> t -> unit
42
26
end
43
27
44
Removed:
(** One movement driven to failure within a stimulus. *)
45
28
module Movement : sig
46
29
type t
47
30
@@ -60,8 +43,6 @@
60
43
val pp : Format.formatter -> t -> unit
61
44
end
62
45
63
Removed:
(** How the stimulus was delivered — the performed counterpart of
64
Removed:
{!Prescription.Stimulus.delivery}. *)
65
46
type delivery =
66
47
| Single of Movement.t
67
48
| Pre_exhaust of { isolation : Movement.t; compound : Movement.t }
@@ -74,50 +55,32 @@
74
55
val pp_error : Format.formatter -> error -> unit
75
56
76
57
val make : ?warm_ups:Warm_up.t list -> delivery -> (t, error) result
77
Removed:
(** A [Pre_exhaust] must genuinely pre-exhaust; two unrelated movements are
78
Removed:
two stimuli, not one. This refuses a mislabelled pairing, not an honest
79
Removed:
record. *)
58
Added:
(** Rejects a mislabelled pre-exhaust pairing. *)
80
59
81
60
val delivery : t -> delivery
82
61
83
62
val movements : t -> Movement.t list
84
Removed:
(** In performance order; isolation first for a pre-exhaust. *)
63
Added:
(** Performance order. *)
85
64
86
65
val warm_ups : t -> Warm_up.t list
87
66
val exercises : t -> Exercise.t list
88
Removed:
89
67
val extensions : t -> extension list
90
Removed:
(** Everything that carried this stimulus past failure, across its movements.
91
Removed:
*)
92
Removed:
93
68
val is_extended : t -> bool
94
69
val pp : Format.formatter -> t -> unit
95
70
end
96
71
97
Removed:
(** One workout being performed, or one already performed: the prescription it
98
Removed:
answers to, when it ran, and the stimuli it delivered.
99
Removed:
100
Removed:
Where plan meets record. It admits only stimuli its prescription calls for —
101
Removed:
the delivery shape must agree, and each movement must be prescribed or an
102
Removed:
allowed substitute — so a workout cannot drift into something else and still
103
Removed:
claim to be the prescribed one. *)
72
Added:
(** A performed or in-progress prescribed workout. *)
104
73
module Workout : sig
105
74
type t
106
Removed:
107
Removed:
(** Whether a stimulus was delivered as one movement or as a pre-exhaust pair.
108
Removed:
*)
109
75
type shape = As_single | As_pre_exhaust
110
76
111
77
type error =
112
78
| Not_prescribed of Exercise.id
113
Removed:
(** No prescription in this workout covers the movement. *)
114
79
| Delivery_mismatch of {
115
80
exercise : Exercise.id;
116
81
prescribed : shape;
117
82
logged : shape;
118
83
}
119
Removed:
(** The movement is prescribed, but not delivered the prescribed way — a
120
Removed:
pre-exhaust pair is not interchangeable with a lone set. *)
121
84
| Already_finished
122
85
123
86
val pp_error : Format.formatter -> error -> unit
@@ -127,47 +90,30 @@
127
90
clearance:Recovery.clearance ->
128
91
started_at:Recovery.timestamp ->
129
92
t
130
Removed:
(** Beginning a workout demands a {!Recovery.clearance}: under HD1 training
131
Removed:
before recovery completes is the primary error, so it cannot happen by
132
Removed:
accident. The clearance is kept, because how it was obtained is evidence.
133
Removed:
*)
93
Added:
(** Clearance records the basis for starting. *)
134
94
135
95
val add_stimulus : t -> Stimulus.t -> (t, error) result
136
Removed:
val finish : t -> ended_at:Recovery.timestamp -> (t, error) result
96
Added:
(** Only prescribed movements and delivery shapes are accepted. *)
137
97
138
Removed:
(** {1 Reading a workout} *)
139
Removed:
98
Added:
val finish : t -> ended_at:Recovery.timestamp -> (t, error) result
140
99
val prescription : t -> Prescription.Workout.t
141
Removed:
142
100
val clearance : t -> Recovery.clearance
143
Removed:
(** On what basis this workout was begun. *)
144
Removed:
145
101
val started_at : t -> Recovery.timestamp
146
102
val ended_at : t -> Recovery.timestamp option
147
103
val is_finished : t -> bool
148
Removed:
149
104
val duration : t -> Recovery.duration option
150
Removed:
(** [Some] once finished. HD1 reads a shortening duration on the same workout
151
Removed:
as rising intensity, so it is a progress signal. *)
152
105
153
106
val stimuli : t -> Stimulus.t list
154
Removed:
(** In the order performed. *)
107
Added:
(** Performance order. *)
155
108
156
109
val outstanding : t -> (int * Prescription.Stimulus.t) list
157
Removed:
(** Prescribed stimuli this workout has yet to answer, each with its position
158
Removed:
— a caller that offers to log one has to be able to say which. *)
110
Added:
(** Unanswered prescribed slots and their positions. *)
159
111
160
112
val unperformed : t -> Prescription.Stimulus.t list
161
Removed:
(** {!outstanding} without the positions. *)
162
Removed:
163
113
val pp : Format.formatter -> t -> unit
164
114
end
165
115
166
Removed:
(** The training diary: every workout performed, and the questions history can
167
Removed:
answer.
168
Removed:
169
Removed:
HD1 insists on keeping records — progress is knowable only from them, and
170
Removed:
"even a one rep increase is significant". *)
116
Added:
(** Workout history. *)
171
117
module Log : sig
172
118
type t
173
119
@@ -175,33 +121,25 @@
175
121
val add : t -> Workout.t -> t
176
122
177
123
val workouts : t -> Workout.t list
178
Removed:
(** Most recent first, by when each workout began. *)
124
Added:
(** Most recent first. *)
179
125
180
126
val last_prescription : t -> Prescription.Workout.t option
181
Removed:
(** What was performed most recently, which is what
182
Removed:
{!Prescription.Routine.workout_after} needs to know where the cycle
183
Removed:
stands. *)
184
127
185
128
type observation = {
186
129
exercise : Exercise.t;
187
130
movement : Stimulus.Movement.t;
188
131
performed_at : Recovery.timestamp;
189
132
}
190
Removed:
(** One movement as it was performed, on the day it was performed. Dated
191
Removed:
because a stall is defined by progress ceasing *for two weeks*, so
192
Removed:
evidence without time cannot answer the question. *)
193
133
194
134
val observations : t -> Exercise.t -> observation list
195
Removed:
(** Every recorded performance of that movement, oldest first. *)
135
Added:
(** Oldest first. *)
196
136
197
137
val readiness :
198
138
t ->
199
139
now:Recovery.timestamp ->
200
140
recommended:Recovery.duration ->
201
141
Recovery.readiness
202
Removed:
(** Measured from the end of the last finished workout. [Ready] when nothing
203
Removed:
has been logged yet, or when the last workout is still unfinished — there
204
Removed:
is no completed effort to recover from. *)
142
Added:
(** [Ready] for an empty log or no finished workout. *)
205
143
206
144
val pp : Format.formatter -> t -> unit
207
145
end
lib/core/exercise.mli
@@ -1,10 +1,7 @@
1
Removed:
(** Curated exercise catalog with author-specified substitution whitelists.
1
Added:
(** Curated exercises, mechanics, and allowed substitutions. *)
2
2
3
Removed:
Users do not log arbitrary movements: every exercise comes from {!catalog}.
4
Removed:
Substitutions are limited to each exercise's author-specified whitelist. *)
5
Removed:
6
3
type t
7
Removed:
(** Abstract catalog exercise; only obtainable via {!catalog} / {!find}. *)
4
Added:
(** Only obtainable from {!catalog} or {!find}. *)
8
5
9
6
type id = private string
10
7
@@ -12,38 +9,25 @@
12
9
val name : t -> string
13
10
val equal : t -> t -> bool
14
11
val pp : Format.formatter -> t -> unit
15
Removed:
16
Removed:
(** {1 Catalog} *)
17
Removed:
18
12
val catalog : t list
19
Removed:
(** The complete curated catalog; the only source of {!t} values. *)
20
13
21
14
val find : string -> t option
22
15
(** By {!id}. *)
23
16
24
Removed:
(** {1 Mechanics} *)
17
Added:
type mechanic = Isolation | Compound
25
18
26
Removed:
(** Whether a movement works one muscle or several. *)
27
Removed:
type mechanic =
28
Removed:
| Isolation
29
Removed:
| Compound (** Involves assisting muscles, one of which is the weak link. *)
30
Removed:
31
19
val mechanic : t -> mechanic
32
20
33
21
val muscles : t -> Muscle.t list
34
Removed:
(** Isolation: exactly one. Compound: two or more, strongest first. *)
22
Added:
(** One for an isolation; at least two for a compound. *)
35
23
36
24
val may_pre_exhaust : isolation:t -> compound:t -> bool
37
Removed:
(** Whether the pair forms a valid pre-exhaustion: [isolation] isolates a muscle
38
Removed:
that [compound] also works, and [compound] involves at least one further
39
Removed:
muscle able to serve it once the target is pre-exhausted. *)
25
Added:
(** [isolation] targets a muscle that [compound] also works. *)
40
26
41
Removed:
(** {1 Substitutions} *)
42
Removed:
43
27
type error = Not_permitted of { original : id; candidate : id }
44
28
45
29
val permitted_substitutes : t -> t list
46
30
val may_substitute : original:t -> candidate:t -> bool
47
31
48
32
val substitute : original:t -> candidate:t -> (t, error) result
49
Removed:
(** [Ok candidate] iff [candidate] is on [original]'s whitelist. *)
33
Added:
(** [Ok candidate] iff it is whitelisted for [original]. *)
lib/core/muscle.mli
@@ -1,8 +1,4 @@
1
Removed:
(** The muscles HD1 names as training targets.
2
Removed:
3
Removed:
Deliberately minimal: muscles exist here only so a pre-exhaust pairing can
4
Removed:
be validated — an isolation movement must feed a compound that works the
5
Removed:
same muscle alongside others able to assist it. *)
1
Added:
(** Training targets used to validate pre-exhaust pairings. *)
6
2
7
3
type t =
8
4
| Pecs
lib/core/prescription.mli
@@ -1,73 +1,43 @@
1
Removed:
(** The plan: what to do, at every scale HD1 prescribes one.
1
Added:
(** Plans for stimuli, workouts, and routines. *)
2
2
3
Removed:
A stimulus is one drive to failure, a workout is a sequence of them, and a
4
Removed:
routine is the cycle of workouts. Nothing here observes anything — the
5
Removed:
performed counterpart is {!Evidence}, and judging one against the other is
6
Removed:
{!Progression}'s work. *)
7
Removed:
8
Removed:
(** One prescribed stimulus: how a single drive to failure is to be delivered,
9
Removed:
and the rep window that calibrates its load.
10
Removed:
11
Removed:
Heavy Duty prescribes one working set, so that is implicit and not
12
Removed:
configurable. *)
3
Added:
(** One prescribed drive to failure. *)
13
4
module Stimulus : sig
14
5
type t
15
6
16
Removed:
(** How the stimulus is delivered. HD1 knows only these two shapes: a single
17
Removed:
movement, or an isolation carried straight into a compound. There is no
18
Removed:
antagonist superset — "superset" in HD1 always means pre-exhaustion. *)
19
7
type delivery =
20
8
| Single of Exercise.t
21
9
| Pre_exhaust of { isolation : Exercise.t; compound : Exercise.t }
22
Removed:
(** Performed with no pause: even a three-second delay lets the target
23
Removed:
recover and restores the weak link. *)
10
Added:
(** No pause between movements. *)
24
11
25
12
type error =
26
13
| Not_a_pre_exhaust of { isolation : Exercise.id; compound : Exercise.id }
27
Removed:
(** The pair cannot pre-exhaust; see {!Exercise.may_pre_exhaust}. *)
28
Removed:
| Reps_outside_limits (** The rep window escapes {!rep_limits}. *)
14
Added:
| Reps_outside_limits
29
15
| Substitute_not_permitted of Exercise.id
30
Removed:
(** A substitute is on no delivery movement's catalog whitelist. *)
31
16
32
17
val pp_error : Format.formatter -> error -> unit
33
18
34
19
val rep_limits : Units.Rep_range.t
35
Removed:
(** HD1's stimulus window, 6-12: fewer than six does not tax the reserves
36
Removed:
sufficiently, and beyond twelve the set ends in cardiorespiratory
37
Removed:
insufficiency before the muscle reaches failure. A prescribed range must
38
Removed:
lie within it. *)
20
Added:
(** 6-12; every prescribed range must lie within it. *)
39
21
40
22
val make :
41
23
delivery:delivery ->
42
24
rep_range:Units.Rep_range.t ->
43
25
allowed_substitutes:Exercise.t list ->
44
26
(t, error) result
45
Removed:
(** Each substitute must be permitted for one of the delivery's movements, so
46
Removed:
a prescription may only narrow the curated set. *)
27
Added:
(** Substitutions may only narrow catalog whitelists. *)
47
28
48
29
val delivery : t -> delivery
49
Removed:
50
30
val rep_range : t -> Units.Rep_range.t
51
Removed:
(** Calibrates load selection only. Reps are an outcome: a set ends at
52
Removed:
failure, never because a number was reached. *)
53
Removed:
54
31
val allowed_substitutes : t -> Exercise.t list
55
32
56
33
val exercises : t -> Exercise.t list
57
Removed:
(** The delivery's movements, in performance order. *)
34
Added:
(** Performance order. *)
58
35
59
36
val permits : t -> Exercise.t -> bool
60
Removed:
(** Whether the movement may be logged against this prescription — one of its
61
Removed:
own, or an allowed substitute. *)
62
Removed:
63
37
val pp : Format.formatter -> t -> unit
64
38
end
65
39
66
Removed:
(** One prescribed workout, such as HD1's Day 1: an ordered sequence of
67
Removed:
prescribed stimuli.
68
Removed:
69
Removed:
Each stimulus is exactly one drive to failure, so the workout's volume is
70
Removed:
its length — HD1's "least amount required" is structural here. *)
40
Added:
(** Ordered prescribed stimuli. *)
71
41
module Workout : sig
72
42
type t
73
43
type id = private string
@@ -75,57 +45,44 @@
75
45
76
46
val make :
77
47
id:string -> name:string -> stimuli:Stimulus.t list -> (t, error) result
78
Removed:
(** [Error Empty_workout] if [stimuli] is empty. *)
48
Added:
(** Rejects an empty workout. *)
79
49
80
50
val id : t -> id
81
51
val name : t -> string
82
Removed:
83
52
val stimuli : t -> Stimulus.t list
84
Removed:
(** In performance order. *)
85
53
86
54
val equal : t -> t -> bool
87
Removed:
(** By {!id}, which is what lets a routine find its place in the cycle. *)
55
Added:
(** By [id]. *)
88
56
89
57
val pp : Format.formatter -> t -> unit
90
58
end
91
59
92
Removed:
(** The cycle of workouts, and how long to rest between them. *)
60
Added:
(** A workout cycle and its recovery intervals. *)
93
61
module Routine : sig
94
62
type t
95
63
type error = Empty_routine
96
64
97
65
val make : name:string -> workouts:Workout.t list -> (t, error) result
98
Removed:
(** [Error Empty_routine] if [workouts] is empty. *)
66
Added:
(** Rejects an empty routine. *)
99
67
100
68
val name : t -> string
101
69
102
70
val workouts : t -> Workout.t list
103
Removed:
(** In cycle order. *)
71
Added:
(** Cycle order. *)
104
72
105
73
val workout_after : t -> Workout.t -> Workout.t
106
Removed:
(** The next workout in the cycle, wrapping at the end. Falls back to the
107
Removed:
first workout when [t] does not contain the one given. *)
74
Added:
(** Wraps; unknown workouts fall back to the first. *)
108
75
109
76
val pp : Format.formatter -> t -> unit
110
77
111
Removed:
(** {1 Rest between workouts}
112
Removed:
113
Removed:
HD1 prescribes training every other day, then two full days off at the
114
Removed:
conclusion of each cycle — so the recommended rest depends on where in the
115
Removed:
cycle you are, and is not one flat interval. *)
116
Removed:
117
78
val training_interval : Recovery.duration
118
Removed:
(** 48h: every other day, within a cycle. *)
79
Added:
(** 48h. *)
119
80
120
81
val cycle_rest : Recovery.duration
121
Removed:
(** 72h: the two days off once the cycle completes. *)
82
Added:
(** 72h after the final workout. *)
122
83
123
84
val recovery_after : t -> Workout.t -> Recovery.duration
124
Removed:
(** How long to rest having performed that workout. *)
125
85
126
Removed:
(** {1 Presets} *)
127
Removed:
128
86
val ideal : t
129
Removed:
(** HD1's Ideal Routine, three workouts: pecs/delts/triceps, then
130
Removed:
lats/traps/erectors/biceps, then legs/abs. *)
87
Added:
(** HD1's three-day routine. *)
131
88
end
lib/core/progression.mli
@@ -1,23 +1,10 @@
1
Removed:
(** Assessment: what the record says, and what follows from it.
1
Added:
(** Interprets recorded training against Heavy Duty rules. *)
2
2
3
Removed:
The only module that judges. {!Prescription} states what to do, {!Evidence}
4
Removed:
states what happened, and this decides what that means.
5
Removed:
6
Removed:
Its central asymmetry is Mentzer's: when progress halts, the answer is never
7
Removed:
more work. HD1 is explicit that the urge to raise volume and frequency on a
8
Removed:
stall "must be kept in check and avoided at all costs", so no remedy here
9
Removed:
can add either — there is one remedy, and it subtracts. *)
10
Removed:
11
Removed:
(** {1 Progress} *)
12
Removed:
13
3
val beats :
14
4
previous:Evidence.Stimulus.Movement.t ->
15
5
current:Evidence.Stimulus.Movement.t ->
16
6
bool
17
Removed:
(** Whether the later performance is an advance: more load, or the same load for
18
Removed:
more reps. HD1 counts "an increase in reps, weight or both", and holds that
19
Removed:
even a single extra rep is significant. Fewer reps at a heavier load still
20
Removed:
counts — that is exactly what raising the load is meant to produce. *)
7
Added:
(** More load, or equal load and more reps. *)
21
8
22
9
type assessment = Progressing | Stalled
23
10
type error = Insufficient_data
@@ -26,72 +13,44 @@
26
13
val pp_error : Format.formatter -> error -> unit
27
14
28
15
val stall_window : Recovery.duration
29
Removed:
(** Two weeks. Progress must have ceased *entirely* for this long before the
30
Removed:
routine is judged to be overtraining. *)
16
Added:
(** 14 days. *)
31
17
32
18
val assess : Evidence.Log.observation list -> (assessment, error) result
33
Removed:
(** Oldest first, and all of one exercise — {!Evidence.Log.observations} returns
34
Removed:
exactly that. Mixing exercises compares unrelated movements and means
35
Removed:
nothing. [Error Insufficient_data] while the record is too short or too
36
Removed:
recent to distinguish a stall from an ordinary gap between advances. *)
19
Added:
(** Oldest first, for one exercise only. *)
37
20
38
Removed:
(** {1 The one sanctioned response to a stall} *)
39
Removed:
40
21
type remedy =
41
22
| Lay_off_then_reduce of {
42
Removed:
lay_off : Recovery.duration; (** One week, to replenish reserves. *)
23
Added:
lay_off : Recovery.duration;
43
24
drop_stimuli_per_workout : int;
44
Removed:
(** Eliminate one set from each workout. *)
45
25
extra_rest : Recovery.duration;
46
Removed:
(** An extra day off between workouts thereafter. *)
47
26
}
48
27
49
28
val remedy : assessment -> remedy option
50
Removed:
(** [Some] only when stalled. There is no remedy that adds work. *)
29
Added:
(** [Some] only for [Stalled]; it never adds work. *)
51
30
52
31
val pp_remedy : Format.formatter -> remedy -> unit
53
32
54
Removed:
(** {1 Whether the load still calibrates the window} *)
55
Removed:
56
33
val load_increase_trigger : Units.Reps.t
57
Removed:
(** Twelve reps, and absolute: HD1 raises the load on reaching twelve, whatever
58
Removed:
window was prescribed, because beyond twelve the set ends in
59
Removed:
cardiorespiratory failure before the muscle does. *)
34
Added:
(** 12 reps, regardless of the prescribed range. *)
60
35
61
36
val load_increase : current:Units.Weight.t -> Units.Weight.t * Units.Weight.t
62
Removed:
(** The 10-20% window to move into. A window, not a figure: HD1 says "or any
63
Removed:
amount necessary" to be forced back into the rep range. *)
37
Added:
(** 10-20% increase window. *)
64
38
65
39
type load_verdict =
66
Removed:
| Hold (** The load still places failure inside the window. *)
40
Added:
| Hold
67
41
| Increase of Units.Weight.t * Units.Weight.t
68
Removed:
(** Twelve reps reached: move into this window. *)
69
Removed:
| Too_heavy (** Failure arrived below the window's floor. *)
42
Added:
| Too_heavy
70
43
71
44
val judge_load :
72
45
rep_range:Units.Rep_range.t -> Evidence.Stimulus.Movement.t -> load_verdict
73
Removed:
(** Only [rep_range]'s floor gates the verdict. Its ceiling does not: exceeding
74
Removed:
the prescribed window is the slack HD1 allows — a 6-10 band is not breached
75
Removed:
at eleven — and the load rises at {!load_increase_trigger} regardless of
76
Removed:
where the ceiling sits. *)
46
Added:
(** Only the range floor matters: below it is [Too_heavy]; at twelve reps the
47
Added:
verdict is [Increase]. *)
77
48
78
49
val pp_load_verdict : Format.formatter -> load_verdict -> unit
79
50
80
Removed:
(** {1 Diagnostics}
81
Removed:
82
Removed:
Habits that HD1 identifies as causes of overtraining. These are observations
83
Removed:
about the record, never constraints on it — the log's job is to say what
84
Removed:
happened, so these can only be read back out of it afterwards. *)
85
Removed:
86
51
type diagnostic =
87
52
| Extensions_on_every_stimulus of int
88
Removed:
(** Workouts in which every stimulus went beyond failure. HD1 uses
89
Removed:
extensions occasionally and "never with every exercise of a workout".
90
Removed:
*)
91
53
| Trained_under_recovered of int
92
Removed:
(** Workouts begun on an overridden clearance. *)
93
54
94
55
val diagnose : Evidence.Workout.t list -> diagnostic list
95
Removed:
(** Only the habits actually present. *)
96
Removed:
97
56
val pp_diagnostic : Format.formatter -> diagnostic -> unit
lib/core/recovery.mli
@@ -1,12 +1,5 @@
1
Removed:
(** Recovery: the elapsed time between two workouts, judged against a
2
Removed:
recommended window, and the permission to train that follows from it.
1
Added:
(** Recovery timing and explicit permission to train. *)
3
2
4
Removed:
HD1 treats recovery as a precondition of growth: training before the body
5
Removed:
has replenished its reserves is the primary error, and its effects are
6
Removed:
systemic, not local to the muscles worked. So starting a workout requires a
7
Removed:
{!clearance}, either earned by resting or taken deliberately and on the
8
Removed:
record. *)
9
Removed:
10
3
type timestamp = private int
11
4
12
5
val timestamp_of_unix_seconds : int -> timestamp
@@ -19,29 +12,21 @@
19
12
val duration_to_seconds : duration -> int
20
13
21
14
val elapsed : since:timestamp -> now:timestamp -> duration
22
Removed:
(** Zero if [now] precedes [since]: rest cannot be negative. *)
15
Added:
(** Zero when [now] precedes [since]. *)
23
16
24
17
val pp_duration : Format.formatter -> duration -> unit
25
18
26
Removed:
(** {1 Readiness} *)
27
Removed:
28
19
type readiness =
29
20
| Ready
30
21
| Recovering of { rested : duration; recommended : duration }
31
Removed:
(** [rested] of [recommended] has passed. *)
32
22
33
23
val evaluate_readiness : elapsed:duration -> recommended:duration -> readiness
34
24
val is_ready : readiness -> bool
35
25
val pp_readiness : Format.formatter -> readiness -> unit
36
26
37
Removed:
(** {1 Clearance to train} *)
38
Removed:
39
27
type clearance
40
Removed:
(** Permission to begin a workout. Unforgeable: obtainable only by having
41
Removed:
recovered, or by {!override}. *)
28
Added:
(** Unforgeable permission: earned by recovery or explicitly overridden. *)
42
29
43
Removed:
(** Why training was permitted. Recorded, so that an unrecovered workout remains
44
Removed:
visible to {!Progression} when diagnosing a stall. *)
45
30
type basis =
46
31
| Recovered
47
32
| Overridden of { rested : duration; recommended : duration; reason : string }
@@ -50,7 +35,6 @@
50
35
(** [Some] iff recovery is complete. *)
51
36
52
37
val override : readiness -> reason:string -> clearance
53
Removed:
(** Train regardless, on the record. Under HD1 this is an error, not a shortcut
54
Removed:
— the reason exists so the decision can be weighed later. *)
38
Added:
(** Records training before recovery completes. *)
55
39
56
40
val basis : clearance -> basis
lib/core/units.mli
@@ -1,16 +1,13 @@
1
Removed:
(** Physical quantities recorded during training.
1
Added:
(** Validated training quantities. *)
2
2
3
Removed:
Every type here is abstract and constructible only through a smart
4
Removed:
constructor, so an invalid measurement cannot exist. *)
5
Removed:
6
3
type error =
7
Removed:
| Negative (** A quantity that must be >= 0 was negative, or not finite. *)
8
Removed:
| Not_positive (** A quantity that must be > 0 was <= 0. *)
9
Removed:
| Inverted_range (** A range's lower bound exceeded its upper bound. *)
4
Added:
| Negative (** Negative or non-finite value. *)
5
Added:
| Not_positive (** Non-positive value. *)
6
Added:
| Inverted_range (** Lower bound exceeds upper bound. *)
10
7
11
8
val pp_error : Format.formatter -> error -> unit
12
9
13
Removed:
(** Load in kilograms. Nonnegative: body-weight movements are [zero]. *)
10
Added:
(** Nonnegative kilograms; [zero] is valid for body-weight movements. *)
14
11
module Weight : sig
15
12
type t
16
13
@@ -22,7 +19,7 @@
22
19
val pp : Format.formatter -> t -> unit
23
20
end
24
21
25
Removed:
(** A completed repetition count. Strictly positive. *)
22
Added:
(** Strictly positive completed repetitions. *)
26
23
module Reps : sig
27
24
type t
28
25
@@ -33,9 +30,7 @@
33
30
val pp : Format.formatter -> t -> unit
34
31
end
35
32
36
Removed:
(** An inclusive rep band. Calibrates load selection: HD1's guideline is 6-10.
37
Removed:
Reps are an outcome, never a target — a set ends at failure, not at a
38
Removed:
number. *)
33
Added:
(** Inclusive load-calibration range. *)
39
34
module Rep_range : sig
40
35
type t
41
36