refactor share import observation wire helpers

Keep promoted snapshot and imported record observation fields in one byte-order definition while preserving their distinct decode policies.

Commit
c9bc0a9c1f79ff7e7c477a3be7ed20aad8ce3127
Author
Marius Peter <dev@marius-peter.com>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
lib/persistence/import_codec.ml
index 97b7c64c..379c7f58 100644..100644
@@ -135,6 +135,33 @@
135 135 | exception Unknown id -> Error (Unknown_exercise id)
136 136 end
137 137
138 Added: (* --- observation wire fields ---
139 Added:
140 Added: A promoted observation always serializes as the same four fields, in the same
141 Added: order: an exercise id, a load, a rep count, and a performed time. The snapshot
142 Added: path keeps the id as a raw [Exercise.id]. The record path resolves it to a
143 Added: catalog [Exercise.t] and rebuilds the effort at [Positive_failure]. Both share
144 Added: this framing, so the byte layout lives here once. *)
145 Added:
146 Added: module Observation_wire = struct
147 Added: (* Write the four fields from already-extracted primitive parts. *)
148 Added: let write buf ~exercise_id ~load ~reps ~performed_at =
149 Added: Writer.string buf exercise_id;
150 Added: Writer.float buf load;
151 Added: Writer.int buf reps;
152 Added: Writer.timestamp buf performed_at
153 Added:
154 Added: (* Read the four fields in order, resolving the leading exercise id with
155 Added: [resolve]. The snapshot path resolves to an [Exercise.id]. The record path
156 Added: resolves to a catalog [Exercise.t]. The remaining three fields are shared. *)
157 Added: let read r ~resolve ~build =
158 Added: let exercise = resolve r in
159 Added: let load = Reader.float r in
160 Added: let reps = Reader.int r in
161 Added: let performed_at = Reader.timestamp r in
162 Added: build ~exercise ~load ~reps ~performed_at
163 Added: end
164 Added:
138 165 (* --- source set --- *)
139 166
140 167 let set_type_code : WI.source_set_type -> string = function
@@ -203,19 +230,16 @@
203 230 (* --- observation snapshot --- *)
204 231
205 232 let write_observation buf (o : WI.observation_snapshot) =
206 Removed: Writer.string buf (o.exercise_id :> string);
207 Removed: Writer.float buf o.load;
208 Removed: Writer.int buf o.reps;
209 Removed: Writer.timestamp buf o.performed_at
233 Added: Observation_wire.write buf
234 Added: ~exercise_id:(o.exercise_id :> string)
235 Added: ~load:o.load ~reps:o.reps ~performed_at:o.performed_at
210 236
211 237 (* Read one observation snapshot, resolving its exercise id to an [Exercise.id]
212 238 through the catalog. *)
213 239 let read_observation_snapshot r : WI.observation_snapshot =
214 Removed: let exercise_id = Reader.exercise_id r in
215 Removed: let load = Reader.float r in
216 Removed: let reps = Reader.int r in
217 Removed: let performed_at = Reader.timestamp r in
218 Removed: { WI.exercise_id; load; reps; performed_at }
240 Added: Observation_wire.read r ~resolve:Reader.exercise_id
241 Added: ~build:(fun ~exercise ~load ~reps ~performed_at ->
242 Added: { WI.exercise_id = exercise; load; reps; performed_at })
219 243
220 244 (* --- promotion snapshot --- *)
221 245
@@ -336,11 +360,12 @@
336 360 Writer.list
337 361 (fun buf obs ->
338 362 let effort = Evidence.Observation.effort obs in
339 Removed: Writer.string buf
340 Removed: (Exercise.id (Evidence.Stimulus.Effort.exercise effort) :> string);
341 Removed: Writer.float buf (Evidence.Stimulus.Effort.load effort);
342 Removed: Writer.int buf (Evidence.Stimulus.Effort.reps effort);
343 Removed: Writer.timestamp buf (Evidence.Observation.performed_at obs))
363 Added: Observation_wire.write buf
364 Added: ~exercise_id:
365 Added: (Exercise.id (Evidence.Stimulus.Effort.exercise effort) :> string)
366 Added: ~load:(Evidence.Stimulus.Effort.load effort)
367 Added: ~reps:(Evidence.Stimulus.Effort.reps effort)
368 Added: ~performed_at:(Evidence.Observation.performed_at obs))
344 369 buf rec_.observations;
345 370 (* Provenance. The batch and workout ids repeat the record's own; storing them
346 371 keeps the provenance self-contained after a decode. *)
@@ -363,23 +388,21 @@
363 388 let observations =
364 389 Reader.list
365 390 (fun r ->
366 Removed: let exercise = Reader.exercise r in
367 Removed: let load = Reader.float r in
368 Removed: let reps = Reader.int r in
369 Removed: let performed_at = Reader.timestamp r in
370 Removed: let effort =
371 Removed: match
372 Removed: Evidence.Stimulus.Effort.make ~exercise ~load ~reps
373 Removed: ~outcome:Evidence.Stimulus.Positive_failure
374 Removed: with
375 Removed: | Ok effort -> effort
376 Removed: | Error e ->
377 Removed: raise
378 Removed: (Reader.Bad
379 Removed: (Format.asprintf "observation %a"
380 Removed: Evidence.Stimulus.Effort.pp_error e))
381 Removed: in
382 Removed: Evidence.Observation.make ~exercise ~effort ~performed_at)
391 Added: Observation_wire.read r ~resolve:Reader.exercise
392 Added: ~build:(fun ~exercise ~load ~reps ~performed_at ->
393 Added: let effort =
394 Added: match
395 Added: Evidence.Stimulus.Effort.make ~exercise ~load ~reps
396 Added: ~outcome:Evidence.Stimulus.Positive_failure
397 Added: with
398 Added: | Ok effort -> effort
399 Added: | Error e ->
400 Added: raise
401 Added: (Reader.Bad
402 Added: (Format.asprintf "observation %a"
403 Added: Evidence.Stimulus.Effort.pp_error e))
404 Added: in
405 Added: Evidence.Observation.make ~exercise ~effort ~performed_at))
383 406 r
384 407 in
385 408 let prov_batch_id = Reader.string r in