(** The workout-import port. An adapter parses one third-party export format into a provisional {!Workout_import.batch}. The web layer names only this port, so no adapter (and no parser library) is reachable from a controller. The composition root plugs a concrete adapter in. Errors are the adapter's own type. The web layer only phrases them through [pp_error], so a new export format needs no change to the port. *) module type S = sig type error val pp_error : Format.formatter -> error -> unit val parse : batch_id:Workout_import.batch_id -> fingerprint:string -> imported_at:Recovery.timestamp -> utc_offset_seconds:int -> string -> (Workout_import.batch, error) result (** Parse one export. [utc_offset_seconds] is the offset of the export's wall-clock times from UTC. The batch is provisional: it is stored for review, and promotion happens later through the service. *) end