(** Curated exercises and their permitted relationships. *) type equipment = | Barbell | Cable | Dumbbell | Machine | Bodyweight | Unspecified type movement = | Fly | Crossover | Pec_deck | Press | Lateral_raise | French_press | Pressdown | Dip | Pullover | Pulldown | Row | Chin | Shrug | Hyperextension | Deadlift | Curl | Leg_extension | Leg_press | Squat | Leg_curl | Calf_raise | Sit_up type variation = | Standard | Incline | Bent_over | Rear_delt | Lying | Triceps | Close_grip_palms_up | Straight_arm | Preacher type key = { equipment : equipment; movement : movement; variation : variation } (** The catalog identity: equipment × movement × variation. *) type t (** An opaque catalog entry, only obtainable by lookup. *) type id = private string (** A stable serialized identifier for external boundaries. *) val find : key -> t option (** Looks up an exercise by structured identity. *) val find_id : string -> t option (** Looks up an exercise by stable serialized identifier. *) val key : t -> key val id : t -> id val name : t -> string val equal : t -> t -> bool val pp : Format.formatter -> t -> unit val may_pre_exhaust : isolation:t -> compound:t -> bool (** Whether the pair shares the isolation's target. *) val may_substitute : original:t -> candidate:t -> bool (** Whether [candidate] is author-approved for [original]. *)