refactor Key exercises structurally

Key opaque catalog entries by equipment, movement, and variation. Keep stable string IDs only for serialization and boundary lookup while using structured keys for relationships and supplied routines.

Commit
962e10be8b81772266ce05bac76304be4938e5b8
Author
Marius Peter <dev@marius-peter.com>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
ARCHITECTURE.md
index 8a26895b..29aee9d4 100644..100644
@@ -83,9 +83,11 @@
83 83 anatomically; both are here because a compound must have something able to
84 84 serve the muscle it pre-exhausts. Deliberately minimal otherwise: nothing but
85 85 pre-exhaust validation consults it.
86 Removed: - **Exercise** — the curated catalog, each movement carrying a mechanic
87 Removed: (isolation or compound) and the muscles it works. Substitutions come from HD1's
88 Removed: own "or" lists, grouped so symmetry is structural.
86 Added: - **Exercise** — the curated catalog. Each opaque entry is keyed by
87 Added: equipment × movement × variation, while a stable string ID serves only
88 Added: external serialization. Each entry carries a mechanic and worked muscles.
89 Added: Substitutions come from HD1's own "or" lists, grouped so symmetry is
90 Added: structural.
89 91
90 92 ### Normative — the plan
91 93
lib/core/exercise.ml
index 06bd6529..a5f7bfdf 100644..100644
@@ -17,55 +17,190 @@
17 17 let equal = ( = )
18 18 end
19 19
20 Added: type equipment =
21 Added: | Barbell
22 Added: | Cable
23 Added: | Dumbbell
24 Added: | Machine
25 Added: | Bodyweight
26 Added: | Unspecified
27 Added:
28 Added: type movement =
29 Added: | Fly
30 Added: | Crossover
31 Added: | Pec_deck
32 Added: | Press
33 Added: | Lateral_raise
34 Added: | French_press
35 Added: | Pressdown
36 Added: | Dip
37 Added: | Pullover
38 Added: | Pulldown
39 Added: | Row
40 Added: | Chin
41 Added: | Shrug
42 Added: | Hyperextension
43 Added: | Deadlift
44 Added: | Curl
45 Added: | Leg_extension
46 Added: | Leg_press
47 Added: | Squat
48 Added: | Leg_curl
49 Added: | Calf_raise
50 Added: | Sit_up
51 Added:
52 Added: type variation =
53 Added: | Standard
54 Added: | Incline
55 Added: | Bent_over
56 Added: | Rear_delt
57 Added: | Lying
58 Added: | Triceps
59 Added: | Close_grip_palms_up
60 Added: | Straight_arm
61 Added: | Preacher
62 Added:
63 Added: type key = { equipment : equipment; movement : movement; variation : variation }
20 64 type id = string
21 65 type mechanic = Isolation | Compound
22 66
23 67 type t = {
68 Added: key : key;
24 69 id : id;
25 70 name : string;
26 71 mechanic : mechanic;
27 72 muscles : Muscle.t list;
28 73 }
29 74
75 Added: let make_key ~equipment ~movement ~variation =
76 Added: { equipment; movement; variation }
77 Added:
78 Added: let key_equal = ( = )
79 Added: let key t = t.key
30 80 let id t = t.id
31 81 let name t = t.name
32 Removed: let equal a b = String.equal a.id b.id
82 Added: let equal a b = key_equal a.key b.key
33 83 let pp ppf t = Format.pp_print_string ppf t.name
34 84
35 Removed: let iso id name muscle =
36 Removed: { id; name; mechanic = Isolation; muscles = [ muscle ] }
85 Added: let iso ~key ~id ~name muscle =
86 Added: { key; id; name; mechanic = Isolation; muscles = [ muscle ] }
37 87
38 Removed: let comp id name muscles = { id; name; mechanic = Compound; muscles }
88 Added: let comp ~key ~id ~name muscles =
89 Added: { key; id; name; mechanic = Compound; muscles }
39 90
40 91 (* The movements HD1 names, in the order its Ideal Routine introduces them.
41 Removed: Compound muscle lists put the chiefly-worked muscle first, followed by the
42 Removed: assisting muscles that HD1's weak-link discussion identifies. *)
92 Added: The stable [id] preserves external serialization. The structured [key] is the
93 Added: catalog identity. [Unspecified] records where HD1 names no equipment. *)
94 Added: let dumbbell_flyes =
95 Added: make_key ~equipment:Dumbbell ~movement:Fly ~variation:Standard
96 Added:
97 Added: let cable_crossovers =
98 Added: make_key ~equipment:Cable ~movement:Crossover ~variation:Standard
99 Added:
100 Added: let pec_deck =
101 Added: make_key ~equipment:Machine ~movement:Pec_deck ~variation:Standard
102 Added:
103 Added: let incline_presses =
104 Added: make_key ~equipment:Unspecified ~movement:Press ~variation:Incline
105 Added:
106 Added: let laterals =
107 Added: make_key ~equipment:Unspecified ~movement:Lateral_raise ~variation:Standard
108 Added:
109 Added: let bent_over_laterals =
110 Added: make_key ~equipment:Dumbbell ~movement:Lateral_raise ~variation:Bent_over
111 Added:
112 Added: let reverse_pec_deck =
113 Added: make_key ~equipment:Machine ~movement:Pec_deck ~variation:Rear_delt
114 Added:
115 Added: let lying_french_presses =
116 Added: make_key ~equipment:Unspecified ~movement:French_press ~variation:Lying
117 Added:
118 Added: let pressdowns =
119 Added: make_key ~equipment:Cable ~movement:Pressdown ~variation:Standard
120 Added:
121 Added: let triceps_machine =
122 Added: make_key ~equipment:Machine ~movement:Press ~variation:Triceps
123 Added:
124 Added: let dips = make_key ~equipment:Bodyweight ~movement:Dip ~variation:Standard
125 Added:
126 Added: let pullovers =
127 Added: make_key ~equipment:Unspecified ~movement:Pullover ~variation:Standard
128 Added:
129 Added: let straight_arm_pulldowns =
130 Added: make_key ~equipment:Cable ~movement:Pulldown ~variation:Straight_arm
131 Added:
132 Added: let close_grip_pulldowns =
133 Added: make_key ~equipment:Cable ~movement:Pulldown ~variation:Close_grip_palms_up
134 Added:
135 Added: let bent_over_rows =
136 Added: make_key ~equipment:Barbell ~movement:Row ~variation:Bent_over
137 Added:
138 Added: let chins = make_key ~equipment:Bodyweight ~movement:Chin ~variation:Standard
139 Added: let shrugs = make_key ~equipment:Unspecified ~movement:Shrug ~variation:Standard
140 Added:
141 Added: let hyperextensions =
142 Added: make_key ~equipment:Bodyweight ~movement:Hyperextension ~variation:Standard
143 Added:
144 Added: let deadlifts =
145 Added: make_key ~equipment:Barbell ~movement:Deadlift ~variation:Standard
146 Added:
147 Added: let curls = make_key ~equipment:Barbell ~movement:Curl ~variation:Standard
148 Added:
149 Added: let preacher_curls =
150 Added: make_key ~equipment:Barbell ~movement:Curl ~variation:Preacher
151 Added:
152 Added: let leg_extensions =
153 Added: make_key ~equipment:Machine ~movement:Leg_extension ~variation:Standard
154 Added:
155 Added: let leg_presses =
156 Added: make_key ~equipment:Machine ~movement:Leg_press ~variation:Standard
157 Added:
158 Added: let squats = make_key ~equipment:Barbell ~movement:Squat ~variation:Standard
159 Added:
160 Added: let leg_curls =
161 Added: make_key ~equipment:Machine ~movement:Leg_curl ~variation:Standard
162 Added:
163 Added: let calf_raises =
164 Added: make_key ~equipment:Unspecified ~movement:Calf_raise ~variation:Standard
165 Added:
166 Added: let sit_ups =
167 Added: make_key ~equipment:Bodyweight ~movement:Sit_up ~variation:Standard
168 Added:
43 169 let catalog =
44 170 [
45 Removed: (* Day 1 — pecs, delts, triceps *)
46 Removed: iso "dumbbell-flyes" "Dumbbell Flyes" Muscle.Pecs;
47 Removed: iso "cable-crossovers" "Cable Crossovers" Muscle.Pecs;
48 Removed: iso "pec-deck" "Pec Deck" Muscle.Pecs;
49 Removed: comp "incline-press" "Incline Presses"
171 Added: iso ~key:dumbbell_flyes ~id:"dumbbell-flyes" ~name:"Dumbbell Flyes"
172 Added: Muscle.Pecs;
173 Added: iso ~key:cable_crossovers ~id:"cable-crossovers" ~name:"Cable Crossovers"
174 Added: Muscle.Pecs;
175 Added: iso ~key:pec_deck ~id:"pec-deck" ~name:"Pec Deck" Muscle.Pecs;
176 Added: comp ~key:incline_presses ~id:"incline-press" ~name:"Incline Presses"
50 177 [ Muscle.Pecs; Muscle.Delts; Muscle.Triceps ];
51 Removed: iso "laterals" "Laterals" Muscle.Delts;
52 Removed: iso "bent-over-laterals" "Bent-over Dumbbell Laterals" Muscle.Delts;
53 Removed: iso "reverse-pec-deck" "Pec Deck (rear delts)" Muscle.Delts;
54 Removed: iso "lying-french-press" "Lying French Presses" Muscle.Triceps;
55 Removed: iso "pressdowns" "Pressdowns" Muscle.Triceps;
56 Removed: iso "triceps-machine" "Triceps Machine" Muscle.Triceps;
57 Removed: comp "dips" "Dips" [ Muscle.Triceps; Muscle.Pecs; Muscle.Delts ];
58 Removed: (* Day 2 — lats, traps, erectors, biceps *)
59 Removed: iso "pullovers" "Pullovers" Muscle.Lats;
60 Removed: iso "straight-arm-pulldowns" "Straight-Arm Pulldowns" Muscle.Lats;
61 Removed: comp "close-grip-pulldowns" "Close-grip, palms-up Pulldowns"
178 Added: iso ~key:laterals ~id:"laterals" ~name:"Laterals" Muscle.Delts;
179 Added: iso ~key:bent_over_laterals ~id:"bent-over-laterals"
180 Added: ~name:"Bent-over Dumbbell Laterals" Muscle.Delts;
181 Added: iso ~key:reverse_pec_deck ~id:"reverse-pec-deck"
182 Added: ~name:"Pec Deck (rear delts)" Muscle.Delts;
183 Added: iso ~key:lying_french_presses ~id:"lying-french-press"
184 Added: ~name:"Lying French Presses" Muscle.Triceps;
185 Added: iso ~key:pressdowns ~id:"pressdowns" ~name:"Pressdowns" Muscle.Triceps;
186 Added: iso ~key:triceps_machine ~id:"triceps-machine" ~name:"Triceps Machine"
187 Added: Muscle.Triceps;
188 Added: comp ~key:dips ~id:"dips" ~name:"Dips"
189 Added: [ Muscle.Triceps; Muscle.Pecs; Muscle.Delts ];
190 Added: iso ~key:pullovers ~id:"pullovers" ~name:"Pullovers" Muscle.Lats;
191 Added: iso ~key:straight_arm_pulldowns ~id:"straight-arm-pulldowns"
192 Added: ~name:"Straight-Arm Pulldowns" Muscle.Lats;
193 Added: comp ~key:close_grip_pulldowns ~id:"close-grip-pulldowns"
194 Added: ~name:"Close-grip, palms-up Pulldowns"
62 195 [ Muscle.Lats; Muscle.Biceps; Muscle.Forearms ];
63 Removed: comp "bent-over-rows" "Bent-over Barbell Rows"
196 Added: comp ~key:bent_over_rows ~id:"bent-over-rows" ~name:"Bent-over Barbell Rows"
64 197 [ Muscle.Lats; Muscle.Biceps; Muscle.Forearms; Muscle.Erectors ];
65 Removed: comp "chins" "Chins" [ Muscle.Lats; Muscle.Biceps; Muscle.Forearms ];
66 Removed: iso "shrugs" "Shrugs" Muscle.Traps;
67 Removed: iso "hyperextensions" "Hyperextensions" Muscle.Erectors;
68 Removed: comp "deadlifts" "Deadlifts"
198 Added: comp ~key:chins ~id:"chins" ~name:"Chins"
199 Added: [ Muscle.Lats; Muscle.Biceps; Muscle.Forearms ];
200 Added: iso ~key:shrugs ~id:"shrugs" ~name:"Shrugs" Muscle.Traps;
201 Added: iso ~key:hyperextensions ~id:"hyperextensions" ~name:"Hyperextensions"
202 Added: Muscle.Erectors;
203 Added: comp ~key:deadlifts ~id:"deadlifts" ~name:"Deadlifts"
69 204 [
70 205 Muscle.Erectors;
71 206 Muscle.Glutes;
@@ -73,43 +208,48 @@
73 208 Muscle.Quadriceps;
74 209 Muscle.Traps;
75 210 ];
76 Removed: iso "curls" "Curls" Muscle.Biceps;
77 Removed: iso "preacher-curls" "Preacher Curls" Muscle.Biceps;
78 Removed: (* Day 3 — legs, abs *)
79 Removed: iso "leg-extensions" "Leg Extensions" Muscle.Quadriceps;
80 Removed: comp "leg-presses" "Leg Presses"
211 Added: iso ~key:curls ~id:"curls" ~name:"Curls" Muscle.Biceps;
212 Added: iso ~key:preacher_curls ~id:"preacher-curls" ~name:"Preacher Curls"
213 Added: Muscle.Biceps;
214 Added: iso ~key:leg_extensions ~id:"leg-extensions" ~name:"Leg Extensions"
215 Added: Muscle.Quadriceps;
216 Added: comp ~key:leg_presses ~id:"leg-presses" ~name:"Leg Presses"
81 217 [ Muscle.Quadriceps; Muscle.Glutes; Muscle.Hamstrings ];
82 Removed: comp "squats" "Squats"
218 Added: comp ~key:squats ~id:"squats" ~name:"Squats"
83 219 [ Muscle.Quadriceps; Muscle.Glutes; Muscle.Hamstrings; Muscle.Erectors ];
84 Removed: iso "leg-curls" "Leg Curls" Muscle.Hamstrings;
85 Removed: iso "calf-raises" "Calf Raises" Muscle.Calves;
86 Removed: iso "sit-ups" "Sit-Ups" Muscle.Abdominals;
220 Added: iso ~key:leg_curls ~id:"leg-curls" ~name:"Leg Curls" Muscle.Hamstrings;
221 Added: iso ~key:calf_raises ~id:"calf-raises" ~name:"Calf Raises" Muscle.Calves;
222 Added: iso ~key:sit_ups ~id:"sit-ups" ~name:"Sit-Ups" Muscle.Abdominals;
87 223 ]
88 224
89 Removed: let find sought = List.find_opt (fun e -> String.equal e.id sought) catalog
225 Added: let find sought =
226 Added: List.find_opt (fun exercise -> key_equal exercise.key sought) catalog
90 227
91 Removed: (* Mutually substitutable movements. Grouping guarantees symmetry: every member
92 Removed: of a group may stand in for every other. Each group is one of HD1's own
93 Removed: "or" lists. *)
228 Added: let find_id sought =
229 Added: List.find_opt (fun exercise -> String.equal exercise.id sought) catalog
230 Added:
231 Added: (* Mutually substitutable catalog keys. Grouping guarantees symmetry: every
232 Added: member of a group may stand in for every other. Each group is one of HD1's
233 Added: own "or" lists. *)
94 234 let substitution_groups =
95 235 [
96 Removed: [ "dumbbell-flyes"; "cable-crossovers"; "pec-deck" ];
97 Removed: [ "lying-french-press"; "pressdowns"; "triceps-machine" ];
98 Removed: [ "bent-over-laterals"; "reverse-pec-deck" ];
99 Removed: [ "pullovers"; "straight-arm-pulldowns" ];
100 Removed: [ "close-grip-pulldowns"; "bent-over-rows"; "chins" ];
101 Removed: [ "hyperextensions"; "deadlifts" ];
102 Removed: [ "curls"; "preacher-curls" ];
103 Removed: [ "leg-presses"; "squats" ];
236 Added: [ dumbbell_flyes; cable_crossovers; pec_deck ];
237 Added: [ lying_french_presses; pressdowns; triceps_machine ];
238 Added: [ bent_over_laterals; reverse_pec_deck ];
239 Added: [ pullovers; straight_arm_pulldowns ];
240 Added: [ close_grip_pulldowns; bent_over_rows; chins ];
241 Added: [ hyperextensions; deadlifts ];
242 Added: [ curls; preacher_curls ];
243 Added: [ leg_presses; squats ];
104 244 ]
105 245
106 Removed: let group_of e =
107 Removed: List.find_opt (fun group -> List.mem e.id group) substitution_groups
246 Added: let group_of exercise =
247 Added: List.find_opt (List.exists (key_equal exercise.key)) substitution_groups
108 248 |> Option.value ~default:[]
109 249
110 Removed: let permitted_substitutes e =
111 Removed: group_of e
112 Removed: |> List.filter (fun id -> not (String.equal id e.id))
250 Added: let permitted_substitutes exercise =
251 Added: group_of exercise
252 Added: |> List.filter (fun key -> not (key_equal key exercise.key))
113 253 |> List.filter_map find
114 254
115 255 let may_substitute ~original ~candidate =
lib/core/exercise.mli
index daf3ca77..5a2b9a48 100644..100644
@@ -1,13 +1,64 @@
1 1 (** Curated exercises and their permitted relationships. *)
2 2
3 Added: type equipment =
4 Added: | Barbell
5 Added: | Cable
6 Added: | Dumbbell
7 Added: | Machine
8 Added: | Bodyweight
9 Added: | Unspecified
10 Added:
11 Added: type movement =
12 Added: | Fly
13 Added: | Crossover
14 Added: | Pec_deck
15 Added: | Press
16 Added: | Lateral_raise
17 Added: | French_press
18 Added: | Pressdown
19 Added: | Dip
20 Added: | Pullover
21 Added: | Pulldown
22 Added: | Row
23 Added: | Chin
24 Added: | Shrug
25 Added: | Hyperextension
26 Added: | Deadlift
27 Added: | Curl
28 Added: | Leg_extension
29 Added: | Leg_press
30 Added: | Squat
31 Added: | Leg_curl
32 Added: | Calf_raise
33 Added: | Sit_up
34 Added:
35 Added: type variation =
36 Added: | Standard
37 Added: | Incline
38 Added: | Bent_over
39 Added: | Rear_delt
40 Added: | Lying
41 Added: | Triceps
42 Added: | Close_grip_palms_up
43 Added: | Straight_arm
44 Added: | Preacher
45 Added:
46 Added: type key = { equipment : equipment; movement : movement; variation : variation }
47 Added: (** The catalog identity: equipment × movement × variation. *)
48 Added:
3 49 type t
4 Removed: (** Only obtainable by lookup. *)
50 Added: (** An opaque catalog entry, only obtainable by lookup. *)
5 51
6 52 type id = private string
53 Added: (** A stable serialized identifier for external boundaries. *)
7 54
8 Removed: val find : string -> t option
9 Removed: (** Looks up an exercise by its identifier. *)
55 Added: val find : key -> t option
56 Added: (** Looks up an exercise by structured identity. *)
10 57
58 Added: val find_id : string -> t option
59 Added: (** Looks up an exercise by stable serialized identifier. *)
60 Added:
61 Added: val key : t -> key
11 62 val id : t -> id
12 63 val name : t -> string
13 64 val equal : t -> t -> bool
lib/core/prescription.ml
index f636a4ce..21ecbfbe 100644..100644
@@ -142,25 +142,124 @@
142 142
143 143 (* {1 The Ideal Routine} *)
144 144
145 Removed: let movement id =
146 Removed: match Exercise.find id with
147 Removed: | Some e -> e
148 Removed: | None -> invalid_arg (Format.sprintf "Routine preset: no exercise %S" id)
145 Added: open Exercise
149 146
147 Added: let exercise key =
148 Added: match Exercise.find key with
149 Added: | Some exercise -> exercise
150 Added: | None -> invalid_arg "Ideal Routine references an absent catalog key"
151 Added:
152 Added: let dumbbell_flyes =
153 Added: exercise { equipment = Dumbbell; movement = Fly; variation = Standard }
154 Added:
155 Added: let cable_crossovers =
156 Added: exercise { equipment = Cable; movement = Crossover; variation = Standard }
157 Added:
158 Added: let pec_deck =
159 Added: exercise { equipment = Machine; movement = Pec_deck; variation = Standard }
160 Added:
161 Added: let incline_presses =
162 Added: exercise { equipment = Unspecified; movement = Press; variation = Incline }
163 Added:
164 Added: let laterals =
165 Added: exercise
166 Added: {
167 Added: equipment = Unspecified;
168 Added: movement = Lateral_raise;
169 Added: variation = Standard;
170 Added: }
171 Added:
172 Added: let bent_over_laterals =
173 Added: exercise
174 Added: { equipment = Dumbbell; movement = Lateral_raise; variation = Bent_over }
175 Added:
176 Added: let reverse_pec_deck =
177 Added: exercise { equipment = Machine; movement = Pec_deck; variation = Rear_delt }
178 Added:
179 Added: let lying_french_presses =
180 Added: exercise
181 Added: { equipment = Unspecified; movement = French_press; variation = Lying }
182 Added:
183 Added: let pressdowns =
184 Added: exercise { equipment = Cable; movement = Pressdown; variation = Standard }
185 Added:
186 Added: let triceps_machine =
187 Added: exercise { equipment = Machine; movement = Press; variation = Triceps }
188 Added:
189 Added: let dips =
190 Added: exercise { equipment = Bodyweight; movement = Dip; variation = Standard }
191 Added:
192 Added: let pullovers =
193 Added: exercise
194 Added: { equipment = Unspecified; movement = Pullover; variation = Standard }
195 Added:
196 Added: let straight_arm_pulldowns =
197 Added: exercise
198 Added: { equipment = Cable; movement = Pulldown; variation = Straight_arm }
199 Added:
200 Added: let close_grip_pulldowns =
201 Added: exercise
202 Added: {
203 Added: equipment = Cable;
204 Added: movement = Pulldown;
205 Added: variation = Close_grip_palms_up;
206 Added: }
207 Added:
208 Added: let bent_over_rows =
209 Added: exercise { equipment = Barbell; movement = Row; variation = Bent_over }
210 Added:
211 Added: let shrugs =
212 Added: exercise { equipment = Unspecified; movement = Shrug; variation = Standard }
213 Added:
214 Added: let hyperextensions =
215 Added: exercise
216 Added: {
217 Added: equipment = Bodyweight;
218 Added: movement = Hyperextension;
219 Added: variation = Standard;
220 Added: }
221 Added:
222 Added: let deadlifts =
223 Added: exercise { equipment = Barbell; movement = Deadlift; variation = Standard }
224 Added:
225 Added: let curls =
226 Added: exercise { equipment = Barbell; movement = Curl; variation = Standard }
227 Added:
228 Added: let preacher_curls =
229 Added: exercise { equipment = Barbell; movement = Curl; variation = Preacher }
230 Added:
231 Added: let leg_extensions =
232 Added: exercise
233 Added: { equipment = Machine; movement = Leg_extension; variation = Standard }
234 Added:
235 Added: let leg_presses =
236 Added: exercise { equipment = Machine; movement = Leg_press; variation = Standard }
237 Added:
238 Added: let squats =
239 Added: exercise { equipment = Barbell; movement = Squat; variation = Standard }
240 Added:
241 Added: let leg_curls =
242 Added: exercise { equipment = Machine; movement = Leg_curl; variation = Standard }
243 Added:
244 Added: let calf_raises =
245 Added: exercise
246 Added: { equipment = Unspecified; movement = Calf_raise; variation = Standard }
247 Added:
248 Added: let sit_ups =
249 Added: exercise { equipment = Bodyweight; movement = Sit_up; variation = Standard }
250 Added:
150 251 (* HD1's guideline window for every listed exercise. *)
151 252 let six_to_ten = Result.get_ok (Rep_range.make ~min:6 ~max:10)
152 253
153 254 let prescribe ?(substitutes = []) delivery =
154 255 Stimulus.make ~delivery ~rep_range:six_to_ten
155 Removed: ~allowed_substitutes:(List.map movement substitutes)
256 Added: ~allowed_substitutes:substitutes
156 257
157 Removed: let single ?substitutes id =
158 Removed: prescribe ?substitutes (Stimulus.Single (movement id))
258 Added: let single ?substitutes exercise =
259 Added: prescribe ?substitutes (Stimulus.Single exercise)
159 260
160 261 let pre_exhaust ?substitutes ~isolation ~compound () =
161 Removed: prescribe ?substitutes
162 Removed: (Stimulus.Pre_exhaust
163 Removed: { isolation = movement isolation; compound = movement compound })
262 Added: prescribe ?substitutes (Stimulus.Pre_exhaust { isolation; compound })
164 263
165 264 let day ~name stimuli = Workout.make ~name ~stimuli
166 265
@@ -168,35 +267,34 @@
168 267 day ~name:"Day 1"
169 268 [
170 269 pre_exhaust
171 Removed: ~substitutes:[ "cable-crossovers"; "pec-deck" ]
172 Removed: ~isolation:"dumbbell-flyes" ~compound:"incline-press" ();
173 Removed: single "laterals";
174 Removed: single ~substitutes:[ "reverse-pec-deck" ] "bent-over-laterals";
270 Added: ~substitutes:[ cable_crossovers; pec_deck ]
271 Added: ~isolation:dumbbell_flyes ~compound:incline_presses ();
272 Added: single laterals;
273 Added: single ~substitutes:[ reverse_pec_deck ] bent_over_laterals;
175 274 pre_exhaust
176 Removed: ~substitutes:[ "pressdowns"; "triceps-machine" ]
177 Removed: ~isolation:"lying-french-press" ~compound:"dips" ();
275 Added: ~substitutes:[ pressdowns; triceps_machine ]
276 Added: ~isolation:lying_french_presses ~compound:dips ();
178 277 ]
179 278
180 279 let ideal_day_two =
181 280 day ~name:"Day 2"
182 281 [
183 Removed: pre_exhaust
184 Removed: ~substitutes:[ "straight-arm-pulldowns" ]
185 Removed: ~isolation:"pullovers" ~compound:"close-grip-pulldowns" ();
186 Removed: single "bent-over-rows";
187 Removed: single "shrugs";
188 Removed: single ~substitutes:[ "deadlifts" ] "hyperextensions";
189 Removed: single ~substitutes:[ "preacher-curls" ] "curls";
282 Added: pre_exhaust ~substitutes:[ straight_arm_pulldowns ] ~isolation:pullovers
283 Added: ~compound:close_grip_pulldowns ();
284 Added: single bent_over_rows;
285 Added: single shrugs;
286 Added: single ~substitutes:[ deadlifts ] hyperextensions;
287 Added: single ~substitutes:[ preacher_curls ] curls;
190 288 ]
191 289
192 290 let ideal_day_three =
193 291 day ~name:"Day 3"
194 292 [
195 Removed: pre_exhaust ~substitutes:[ "squats" ] ~isolation:"leg-extensions"
196 Removed: ~compound:"leg-presses" ();
197 Removed: single "leg-curls";
198 Removed: single "calf-raises";
199 Removed: single "sit-ups";
293 Added: pre_exhaust ~substitutes:[ squats ] ~isolation:leg_extensions
294 Added: ~compound:leg_presses ();
295 Added: single leg_curls;
296 Added: single calf_raises;
297 Added: single sit_ups;
200 298 ]
201 299
202 300 let[@warning "-32"] ideal =
test/test_decode.ml
index b4b3c59c..f5f8791c 100644..100644
@@ -2,7 +2,7 @@
2 2 module Form = Dream_html.Form
3 3
4 4 let exercise id =
5 Removed: match Exercise.find id with
5 Added: match Exercise.find_id id with
6 6 | Some exercise -> exercise
7 7 | None -> Alcotest.failf "catalog is missing %S" id
8 8
test/test_evidence.ml
index 8c5b78e8..f10aa6ca 100644..100644
@@ -8,7 +8,7 @@
8 8 let ok = function Ok v -> v | Error _ -> Alcotest.fail "expected Ok"
9 9
10 10 let get id =
11 Removed: match Exercise.find id with
11 Added: match Exercise.find_id id with
12 12 | Some e -> e
13 13 | None -> Alcotest.failf "catalog is missing %S" id
14 14
test/test_exercise.ml
index 43d1c683..bcce94a9 100644..100644
@@ -1,21 +1,54 @@
1 1 (** Unit tests for {!Exercise}, authored against the exercise.mli contract. *)
2 2
3 3 let get id =
4 Removed: match Exercise.find id with
4 Added: match Exercise.find_id id with
5 5 | Some e -> e
6 6 | None -> Alcotest.failf "catalog is missing %S" id
7 7
8 Added: let dumbbell_flyes =
9 Added: {
10 Added: Exercise.equipment = Exercise.Dumbbell;
11 Added: movement = Exercise.Fly;
12 Added: variation = Exercise.Standard;
13 Added: }
14 Added:
8 15 let lookup_tests =
9 16 [
10 Removed: ( "find locates curated entries and rejects unknown ids",
17 Added: ( "a structured key locates the curated exercise",
11 18 `Quick,
12 19 fun () ->
13 Removed: Alcotest.(check string)
14 Removed: "name" "Dumbbell Flyes"
15 Removed: (Exercise.name (get "dumbbell-flyes"));
20 Added: match Exercise.find dumbbell_flyes with
21 Added: | Some exercise ->
22 Added: Alcotest.(check string)
23 Added: "name" "Dumbbell Flyes" (Exercise.name exercise);
24 Added: Alcotest.(check bool)
25 Added: "key round-trips" true
26 Added: (Exercise.key exercise = dumbbell_flyes);
27 Added: Alcotest.(check string)
28 Added: "stable id" "dumbbell-flyes"
29 Added: (Exercise.id exercise :> string)
30 Added: | None -> Alcotest.fail "Dumbbell Flyes key is absent" );
31 Added: ( "an absent structured key is rejected",
32 Added: `Quick,
33 Added: fun () ->
16 34 Alcotest.(check bool)
17 Removed: "unknown" true
18 Removed: (Option.is_none (Exercise.find "jefferson-curl")) );
35 Added: "no dumbbell press in HD1 catalog" true
36 Added: (Option.is_none
37 Added: (Exercise.find
38 Added: {
39 Added: Exercise.equipment = Exercise.Dumbbell;
40 Added: movement = Exercise.Press;
41 Added: variation = Exercise.Standard;
42 Added: })) );
43 Added: ( "a stable identifier remains an external lookup boundary",
44 Added: `Quick,
45 Added: fun () ->
46 Added: Alcotest.(check bool)
47 Added: "stable id" true
48 Added: (Option.is_some (Exercise.find_id "dumbbell-flyes"));
49 Added: Alcotest.(check bool)
50 Added: "unknown id" true
51 Added: (Option.is_none (Exercise.find_id "jefferson-curl")) );
19 52 ]
20 53
21 54 let pre_exhaust_tests =
test/test_prescription.ml
index 49ca0f22..4c5d7c24 100644..100644
@@ -4,7 +4,7 @@
4 4 let ok = function Ok v -> v | Error _ -> Alcotest.fail "expected Ok"
5 5
6 6 let get id =
7 Removed: match Exercise.find id with
7 Added: match Exercise.find_id id with
8 8 | Some e -> e
9 9 | None -> Alcotest.failf "catalog is missing %S" id
10 10
test/test_progression.ml
index 28b6755d..7cf30ff4 100644..100644
@@ -6,7 +6,7 @@
6 6 let ok = function Ok v -> v | Error _ -> Alcotest.fail "expected Ok"
7 7
8 8 let get id =
9 Removed: match Exercise.find id with
9 Added: match Exercise.find_id id with
10 10 | Some e -> e
11 11 | None -> Alcotest.failf "catalog is missing %S" id
12 12
test/test_service.ml
index 72220304..d96dc063 100644..100644
@@ -8,7 +8,7 @@
8 8 let ok = function Ok v -> v | Error _ -> Alcotest.fail "expected Ok"
9 9
10 10 let get id =
11 Removed: match Exercise.find id with
11 Added: match Exercise.find_id id with
12 12 | Some e -> e
13 13 | None -> Alcotest.failf "catalog is missing %S" id
14 14