[OCaml] High Intensity Training Online
refactor Lift Feedback out of Evidence
Evidence's own header says "stimuli, workouts, and history": what the body did. A subjective self-report is what the trainee said. The two make different kinds of claim, so give Feedback its own core module. Nothing in the module changes; consumers name Feedback instead of Evidence.Feedback. Service had internal submodules named Routines and Feedback that now shadow the core modules of the same names. Rename them Routine_flow and Self_report so a later edit inside Service cannot silently bind the wrong module.
Changed files
- ARCHITECTURE.org
- lib/app/repository.ml
- lib/app/repository.mli
- lib/app/service.ml
- lib/app/service.mli
- lib/core/dune
- lib/core/evidence.ml
- lib/core/evidence.mli
- lib/core/feedback.ml
- lib/core/feedback.mli
- lib/persistence/codec.ml
- lib/persistence/codec.mli
- lib/presenter/view_model.ml
- lib/web/handlers_kit.ml
- lib/web/handlers_logbook.ml
- test/memory_repo.ml
- test/test_codec.ml
- test/test_evidence.ml
- test/test_sqlite_repo.ml
- test/test_web.ml
ARCHITECTURE.org
@@ -108,7 +108,9 @@
108
108
|-------------+----------------+--------------------------------|
109
109
| vocabulary | =Exercise= | what movements exist, and pair |
110
110
| normative | =Prescription= | what should be done |
111
Added:
| authored | =Routines= | the plans the book supplies |
111
112
| factual | =Evidence= | what was done |
113
Added:
| reported | =Feedback= | what the trainee said |
112
114
| inferential | =Progress= | what that means |
113
115
114
116
=Recovery= straddles the divide deliberately: it measures a fact (elapsed rest)
@@ -159,7 +161,7 @@
159
161
hito.app Trainee · Repository · Password_hash (ports) · Service · Catalog · Workout_import
160
162
| identity, the ports, recovery policy, Lwt — no database
161
163
v
162
Removed:
hito.core Exercise · Recovery · Prescription · Routines · Evidence · Progress
164
Added:
hito.core Exercise · Recovery · Prescription · Routines · Feedback · Evidence · Progress
163
165
pure domain: no framework, no database, no serialization
164
166
#+end_src
165
167
@@ -173,7 +175,7 @@
173
175
composition root, the one file that names both an adapter and the use case it
174
176
plugs into.
175
177
176
Removed:
The core is six modules, unwrapped (=wrapped false=), so they are referred to
178
Added:
The core is seven modules, unwrapped (=wrapped false=), so they are referred to
177
179
bare: =Prescription.Stimulus=, =Evidence.Workout=, =Evidence.Log=. It has no
178
180
dependency on Lwt, Caqti, Dream, or any serializer, and gaining one would be a
179
181
design failure rather than a convenience.
@@ -254,7 +256,11 @@
254
256
a prescription or clearance. =Progress= judges observations and therefore
255
257
does not know their provenance.
256
258
257
Removed:
=Feedback= is a typed vocabulary for the two self-reports HD1 grounds —
259
Added:
** Feedback — the self-report
260
Added:
261
Added:
=Feedback= is its own module, not part of =Evidence=, because the two make
262
Added:
different kinds of claim: =Evidence= records what the body did, =Feedback= what
263
Added:
the trainee said. It is a typed vocabulary for the two self-reports HD1 grounds —
258
264
motivation (chapter 6, and a named overtraining symptom) and perceived
259
265
difficulty ("the weights feel much heavier than usual") — with duplicate
260
266
categories rejected. Each carries a relative reading, not an absolute score:
lib/app/repository.ml
@@ -70,8 +70,8 @@
70
70
val replace : t -> Trainee.id -> record -> bool Lwt.t
71
71
val log : t -> Trainee.id -> Evidence.Log.t Lwt.t
72
72
val history : t -> Trainee.id -> record list Lwt.t
73
Removed:
val save_feedback : t -> Trainee.id -> Evidence.Feedback.t -> unit Lwt.t
74
Removed:
val feedback : t -> Trainee.id -> Evidence.Feedback.t list Lwt.t
73
Added:
val save_feedback : t -> Trainee.id -> Feedback.t -> unit Lwt.t
74
Added:
val feedback : t -> Trainee.id -> Feedback.t list Lwt.t
75
75
76
76
val save_app_feedback :
77
77
t ->
lib/app/repository.mli
@@ -118,11 +118,11 @@
118
118
119
119
(** {2 Subjective feedback} *)
120
120
121
Removed:
val save_feedback : t -> Trainee.id -> Evidence.Feedback.t -> unit Lwt.t
121
Added:
val save_feedback : t -> Trainee.id -> Feedback.t -> unit Lwt.t
122
122
(** Store a subjective feedback report. Feedback is a standalone observation,
123
123
not tied to a workout: a trainee may report it at any time. *)
124
124
125
Removed:
val feedback : t -> Trainee.id -> Evidence.Feedback.t list Lwt.t
125
Added:
val feedback : t -> Trainee.id -> Feedback.t list Lwt.t
126
126
(** Stored feedback reports, most recent first. *)
127
127
128
128
val save_app_feedback :
lib/app/service.ml
@@ -167,7 +167,7 @@
167
167
end
168
168
169
169
(* --- routines and selection --- *)
170
Removed:
module Routines = struct
170
Added:
module Routine_flow = struct
171
171
let list_routines t = R.list_routines t.repo
172
172
173
173
let select_routine t trainee id =
@@ -342,11 +342,11 @@
342
342
end
343
343
344
344
(* --- subjective feedback --- *)
345
Removed:
module Feedback = struct
345
Added:
module Self_report = struct
346
346
let record t trainee ~reported_at signals =
347
Removed:
match Evidence.Feedback.make ~reported_at signals with
347
Added:
match Feedback.make ~reported_at signals with
348
348
| report -> R.save_feedback t.repo trainee report >|= fun () -> Ok report
349
Removed:
| exception Evidence.Feedback.Invalid error -> Lwt.return (Error error)
349
Added:
| exception Feedback.Invalid error -> Lwt.return (Error error)
350
350
351
351
let list t trainee = R.feedback t.repo trainee
352
352
end
@@ -491,11 +491,11 @@
491
491
let find_trainee = Accounts.find_trainee
492
492
let change_username = Accounts.change_username
493
493
let change_password = Accounts.change_password
494
Removed:
let list_routines = Routines.list_routines
495
Removed:
let select_routine = Routines.select_routine
496
Removed:
let active_routine = Routines.active_routine
497
Removed:
let next_workout = Routines.next_workout
498
Removed:
let readiness = Routines.readiness
494
Added:
let list_routines = Routine_flow.list_routines
495
Added:
let select_routine = Routine_flow.select_routine
496
Added:
let active_routine = Routine_flow.active_routine
497
Added:
let next_workout = Routine_flow.next_workout
498
Added:
let readiness = Routine_flow.readiness
499
499
let begin_workout = Workouts.begin_workout
500
500
let in_progress = Workouts.in_progress
501
501
let log = Workouts.log
@@ -509,8 +509,8 @@
509
509
let workout_log = Records.workout_log
510
510
let progress = Assessment.progress
511
511
let diagnostics = Assessment.diagnostics
512
Removed:
let record_feedback = Feedback.record
513
Removed:
let feedback = Feedback.list
512
Added:
let record_feedback = Self_report.record
513
Added:
let feedback = Self_report.list
514
514
let record_app_feedback = App_feedback.record
515
515
let app_feedback = App_feedback.list
516
516
let upvote_app_feedback = App_feedback.upvote
lib/app/service.mli
@@ -190,13 +190,13 @@
190
190
t ->
191
191
Trainee.id ->
192
192
reported_at:Recovery.timestamp ->
193
Removed:
Evidence.Feedback.signal list ->
194
Removed:
(Evidence.Feedback.t, Evidence.Feedback.error) result Lwt.t
193
Added:
Feedback.signal list ->
194
Added:
(Feedback.t, Feedback.error) result Lwt.t
195
195
(** Store a subjective feedback report. [Error] when a signal category
196
196
repeats. Feedback is standalone: a trainee may report it at any time,
197
197
independent of a workout. *)
198
198
199
Removed:
val feedback : t -> Trainee.id -> Evidence.Feedback.t list Lwt.t
199
Added:
val feedback : t -> Trainee.id -> Feedback.t list Lwt.t
200
200
(** Stored feedback reports, most recent first. *)
201
201
202
202
(** {2 Application feedback} *)
lib/core/dune
@@ -5,5 +5,5 @@
5
5
(library
6
6
(name hito_core)
7
7
(public_name hito.core)
8
Removed:
(modules exercise recovery prescription routines evidence progress)
8
Added:
(modules exercise recovery prescription routines feedback evidence progress)
9
9
(wrapped false))
lib/core/evidence.ml
@@ -66,39 +66,6 @@
66
66
Format.fprintf ppf "%a then %a" Effort.pp first Effort.pp second
67
67
end
68
68
69
Removed:
module Feedback = struct
70
Removed:
type level = Worse_than_usual | As_usual | Better_than_usual
71
Removed:
72
Removed:
let pp_level ppf = function
73
Removed:
| Worse_than_usual -> Format.pp_print_string ppf "worse than usual"
74
Removed:
| As_usual -> Format.pp_print_string ppf "as usual"
75
Removed:
| Better_than_usual -> Format.pp_print_string ppf "better than usual"
76
Removed:
77
Removed:
type signal = Motivation of level | Difficulty of level
78
Removed:
type t = { reported_at : Recovery.timestamp; signals : signal list }
79
Removed:
type error = Duplicate_signal of signal
80
Removed:
81
Removed:
exception Invalid of error
82
Removed:
83
Removed:
let same_category left right =
84
Removed:
match (left, right) with
85
Removed:
| Motivation _, Motivation _ | Difficulty _, Difficulty _ -> true
86
Removed:
| _ -> false
87
Removed:
88
Removed:
let make ~reported_at signals =
89
Removed:
let rec validate seen = function
90
Removed:
| [] -> { reported_at; signals }
91
Removed:
| signal :: rest ->
92
Removed:
if List.exists (same_category signal) seen then
93
Removed:
raise (Invalid (Duplicate_signal signal))
94
Removed:
else validate (signal :: seen) rest
95
Removed:
in
96
Removed:
validate [] signals
97
Removed:
98
Removed:
let reported_at t = t.reported_at
99
Removed:
let signals t = t.signals
100
Removed:
end
101
Removed:
102
69
module Workout = struct
103
70
type shape = As_single | As_pair
104
71
type completeness = Complete | Incomplete
lib/core/evidence.mli
@@ -53,44 +53,6 @@
53
53
val pp : Format.formatter -> t -> unit
54
54
end
55
55
56
Removed:
(** Typed signals reported at a point in time. *)
57
Removed:
module Feedback : sig
58
Removed:
type level =
59
Removed:
| Worse_than_usual
60
Removed:
| As_usual
61
Removed:
| Better_than_usual
62
Removed:
(** A self-report relative to the trainee's usual baseline, not an
63
Removed:
absolute score. HD1 frames both signals this way — Difficulty is
64
Removed:
"the weights feel much heavier than usual". Three values resist the
65
Removed:
false precision of a finer scale, in the spirit of HD1's refusal of
66
Removed:
spurious measurement gradations. [Worse_than_usual] is the
67
Removed:
concerning direction for both signals. *)
68
Removed:
69
Removed:
val pp_level : Format.formatter -> level -> unit
70
Removed:
71
Removed:
type signal =
72
Removed:
| Motivation of level
73
Removed:
| Difficulty of level
74
Removed:
(** The only self-reports HD1 grounds. Motivation is HD1 chapter 6, and
75
Removed:
a halt in it is a recognized overtraining symptom ("with those who
76
Removed:
chronically overtrain, such a disinclination is easy to
77
Removed:
understand"). Difficulty is HD1's "the weights feel much heavier
78
Removed:
than usual" — a depletion symptom. HD1 gauges recovery by time and
79
Removed:
by effect (a stall or decompensation), not by a wider battery of
80
Removed:
wellness proxies, so none are modeled. *)
81
Removed:
82
Removed:
type t
83
Removed:
type error = Duplicate_signal of signal
84
Removed:
85
Removed:
exception Invalid of error
86
Removed:
87
Removed:
val make : reported_at:Recovery.timestamp -> signal list -> t
88
Removed:
(** Raises [Invalid] when feedback repeats a signal category. *)
89
Removed:
90
Removed:
val reported_at : t -> Recovery.timestamp
91
Removed:
val signals : t -> signal list
92
Removed:
end
93
Removed:
94
56
(** A prescribed workout as observed through its whole life. A workout may be
95
57
edited before or after it ends. The log records what happened, so
96
58
[add_stimulus], [replace_stimulus], and [record_at] deliberately accept an
lib/core/feedback.ml
@@ -0,0 +1,33 @@
1
Added:
(* Subjective self-reports, kept apart from Evidence: what the trainee said,
2
Added:
not what the body did. *)
3
Added:
4
Added:
type level = Worse_than_usual | As_usual | Better_than_usual
5
Added:
6
Added:
let pp_level ppf = function
7
Added:
| Worse_than_usual -> Format.pp_print_string ppf "worse than usual"
8
Added:
| As_usual -> Format.pp_print_string ppf "as usual"
9
Added:
| Better_than_usual -> Format.pp_print_string ppf "better than usual"
10
Added:
11
Added:
type signal = Motivation of level | Difficulty of level
12
Added:
type t = { reported_at : Recovery.timestamp; signals : signal list }
13
Added:
type error = Duplicate_signal of signal
14
Added:
15
Added:
exception Invalid of error
16
Added:
17
Added:
let same_category left right =
18
Added:
match (left, right) with
19
Added:
| Motivation _, Motivation _ | Difficulty _, Difficulty _ -> true
20
Added:
| _ -> false
21
Added:
22
Added:
let make ~reported_at signals =
23
Added:
let rec validate seen = function
24
Added:
| [] -> { reported_at; signals }
25
Added:
| signal :: rest ->
26
Added:
if List.exists (same_category signal) seen then
27
Added:
raise (Invalid (Duplicate_signal signal))
28
Added:
else validate (signal :: seen) rest
29
Added:
in
30
Added:
validate [] signals
31
Added:
32
Added:
let reported_at t = t.reported_at
33
Added:
let signals t = t.signals
lib/core/feedback.mli
@@ -0,0 +1,38 @@
1
Added:
(** Subjective self-reports at a point in time: what the trainee said, not what
2
Added:
the body did. HD1 grounds two, and gauges recovery by time and by effect
3
Added:
rather than by a wider battery of wellness proxies. *)
4
Added:
5
Added:
type level =
6
Added:
| Worse_than_usual
7
Added:
| As_usual
8
Added:
| Better_than_usual
9
Added:
(** A self-report relative to the trainee's usual baseline, not an
10
Added:
absolute score. HD1 frames both signals this way — Difficulty is "the
11
Added:
weights feel much heavier than usual". Three values resist the false
12
Added:
precision of a finer scale, in the spirit of HD1's refusal of spurious
13
Added:
measurement gradations. [Worse_than_usual] is the concerning direction
14
Added:
for both signals. *)
15
Added:
16
Added:
val pp_level : Format.formatter -> level -> unit
17
Added:
18
Added:
type signal =
19
Added:
| Motivation of level
20
Added:
| Difficulty of level
21
Added:
(** The only self-reports HD1 grounds. Motivation is HD1 chapter 6, and a
22
Added:
halt in it is a recognized overtraining symptom ("with those who
23
Added:
chronically overtrain, such a disinclination is easy to understand").
24
Added:
Difficulty is HD1's "the weights feel much heavier than usual" — a
25
Added:
depletion symptom. HD1 gauges recovery by time and by effect (a stall
26
Added:
or decompensation), not by a wider battery of wellness proxies, so
27
Added:
none are modeled. *)
28
Added:
29
Added:
type t
30
Added:
type error = Duplicate_signal of signal
31
Added:
32
Added:
exception Invalid of error
33
Added:
34
Added:
val make : reported_at:Recovery.timestamp -> signal list -> t
35
Added:
(** Raises [Invalid] when feedback repeats a signal category. *)
36
Added:
37
Added:
val reported_at : t -> Recovery.timestamp
38
Added:
val signals : t -> signal list
lib/persistence/codec.ml
@@ -323,18 +323,18 @@
323
323
324
324
(* --- subjective feedback --- *)
325
325
326
Removed:
let level_code : Evidence.Feedback.level -> string = function
326
Added:
let level_code : Feedback.level -> string = function
327
327
| Worse_than_usual -> "worse"
328
328
| As_usual -> "usual"
329
329
| Better_than_usual -> "better"
330
330
331
331
let level_of_code = function
332
Removed:
| "worse" | "1" | "2" -> Ok Evidence.Feedback.Worse_than_usual
333
Removed:
| "usual" | "3" -> Ok Evidence.Feedback.As_usual
334
Removed:
| "better" | "4" | "5" -> Ok Evidence.Feedback.Better_than_usual
332
Added:
| "worse" | "1" | "2" -> Ok Feedback.Worse_than_usual
333
Added:
| "usual" | "3" -> Ok Feedback.As_usual
334
Added:
| "better" | "4" | "5" -> Ok Feedback.Better_than_usual
335
335
| code -> Error (Malformed (Printf.sprintf "level %S" code))
336
336
337
Removed:
let signal_code : Evidence.Feedback.signal -> string = function
337
Added:
let signal_code : Feedback.signal -> string = function
338
338
| Motivation l -> "motivation:" ^ level_code l
339
339
| Difficulty l -> "difficulty:" ^ level_code l
340
340
@@ -344,14 +344,14 @@
344
344
Ok (make l)
345
345
in
346
346
match String.split_on_char ':' code with
347
Removed:
| [ "motivation"; l ] -> leveled (fun l -> Evidence.Feedback.Motivation l) l
348
Removed:
| [ "difficulty"; l ] -> leveled (fun l -> Evidence.Feedback.Difficulty l) l
347
Added:
| [ "motivation"; l ] -> leveled (fun l -> Feedback.Motivation l) l
348
Added:
| [ "difficulty"; l ] -> leveled (fun l -> Feedback.Difficulty l) l
349
349
| _ -> Error (Malformed (Printf.sprintf "signal %S" code))
350
350
351
351
let encode_feedback report =
352
Removed:
let reported_at = Timestamp.encode (Evidence.Feedback.reported_at report) in
352
Added:
let reported_at = Timestamp.encode (Feedback.reported_at report) in
353
353
let signals =
354
Removed:
String.concat "," (List.map signal_code (Evidence.Feedback.signals report))
354
Added:
String.concat "," (List.map signal_code (Feedback.signals report))
355
355
in
356
356
Printf.sprintf "%s\t%s" reported_at signals
357
357
@@ -373,5 +373,5 @@
373
373
| Error _ as e -> e)
374
374
in
375
375
let* signals = go [] codes in
376
Removed:
Ok (Evidence.Feedback.make ~reported_at signals))
376
Added:
Ok (Feedback.make ~reported_at signals))
377
377
| _ -> Error (Malformed "feedback arity")
lib/persistence/codec.mli
@@ -31,8 +31,8 @@
31
31
(Evidence.Workout.t, error) result
32
32
(** Rebuilds a workout, resolving its prescription through [find_routine]. *)
33
33
34
Removed:
val encode_feedback : Evidence.Feedback.t -> string
34
Added:
val encode_feedback : Feedback.t -> string
35
35
(** A stable, single-string encoding of a subjective feedback report. *)
36
36
37
Removed:
val decode_feedback : string -> (Evidence.Feedback.t, error) result
37
Added:
val decode_feedback : string -> (Feedback.t, error) result
38
38
(** Rebuilds a feedback report from its encoding. *)
lib/presenter/view_model.ml
@@ -39,8 +39,8 @@
39
39
presenter graphs. [None] where the report gave that factor no level.
40
40
Flags such as pain carry no score and are absent here. *)
41
41
}
42
Removed:
(** One subjective-feedback report, ready to render. Carries no
43
Removed:
[Evidence.Feedback] variant and no timestamp type. *)
42
Added:
(** One subjective-feedback report, ready to render. Carries no [Feedback]
43
Added:
variant and no timestamp type. *)
44
44
end
45
45
46
46
module Routine = struct
lib/web/handlers_kit.ml
@@ -130,14 +130,14 @@
130
130
| `Incorrect_password -> "The current password is not correct."
131
131
| `Unknown -> "That account no longer exists."
132
132
133
Removed:
let feedback_level : Evidence.Feedback.level -> string = function
134
Removed:
| Evidence.Feedback.Worse_than_usual -> "worse than usual"
135
Removed:
| Evidence.Feedback.As_usual -> "as usual"
136
Removed:
| Evidence.Feedback.Better_than_usual -> "better than usual"
133
Added:
let feedback_level : Feedback.level -> string = function
134
Added:
| Feedback.Worse_than_usual -> "worse than usual"
135
Added:
| Feedback.As_usual -> "as usual"
136
Added:
| Feedback.Better_than_usual -> "better than usual"
137
137
138
Removed:
let feedback_signal : Evidence.Feedback.signal -> string = function
139
Removed:
| Evidence.Feedback.Motivation l -> "Motivation " ^ feedback_level l
140
Removed:
| Evidence.Feedback.Difficulty l -> "Difficulty " ^ feedback_level l
138
Added:
let feedback_signal : Feedback.signal -> string = function
139
Added:
| Feedback.Motivation l -> "Motivation " ^ feedback_level l
140
Added:
| Feedback.Difficulty l -> "Difficulty " ^ feedback_level l
141
141
142
142
let app_feedback_empty = "Enter feedback before submitting."
143
143
let username_changed = "Username changed."
lib/web/handlers_logbook.ml
@@ -61,9 +61,9 @@
61
61
62
62
let feedback_signals answers _fields =
63
63
let level = function
64
Removed:
| "worse" -> Evidence.Feedback.Worse_than_usual
65
Removed:
| "better" -> Evidence.Feedback.Better_than_usual
66
Removed:
| _ -> Evidence.Feedback.As_usual
64
Added:
| "worse" -> Feedback.Worse_than_usual
65
Added:
| "better" -> Feedback.Better_than_usual
66
Added:
| _ -> Feedback.As_usual
67
67
in
68
68
let leveled field make =
69
69
List.find_map
@@ -75,26 +75,26 @@
75
75
in
76
76
List.filter_map Fun.id
77
77
[
78
Removed:
leveled "motivation" (fun l -> Evidence.Feedback.Motivation l);
79
Removed:
leveled "difficulty" (fun l -> Evidence.Feedback.Difficulty l);
78
Added:
leveled "motivation" (fun l -> Feedback.Motivation l);
79
Added:
leveled "difficulty" (fun l -> Feedback.Difficulty l);
80
80
]
81
81
82
82
let describe_signal = Present.feedback_signal
83
83
let factor_fields = [ "motivation"; "difficulty" ]
84
84
85
Removed:
let factor_score field (report : Evidence.Feedback.t) =
85
Added:
let factor_score field (report : Feedback.t) =
86
86
let score = function
87
Removed:
| Evidence.Feedback.Worse_than_usual -> 1
87
Added:
| Feedback.Worse_than_usual -> 1
88
88
| As_usual -> 2
89
89
| Better_than_usual -> 3
90
90
in
91
Removed:
let of_signal (signal : Evidence.Feedback.signal) =
91
Added:
let of_signal (signal : Feedback.signal) =
92
92
match (field, signal) with
93
93
| "motivation", Motivation l | "difficulty", Difficulty l ->
94
94
Some (score l)
95
95
| _ -> None
96
96
in
97
Removed:
List.find_map of_signal (Evidence.Feedback.signals report)
97
Added:
List.find_map of_signal (Feedback.signals report)
98
98
99
99
let entry_view log (record : Repository.record) : View_model.Logbook_entry.t =
100
100
let workout = record.Repository.workout in
@@ -114,13 +114,10 @@
114
114
progressed_exercises = Progress.workout_progress log workout;
115
115
}
116
116
117
Removed:
let feedback_view (report : Evidence.Feedback.t) : View_model.Feedback.report
118
Removed:
=
117
Added:
let feedback_view (report : Feedback.t) : View_model.Feedback.report =
119
118
{
120
Removed:
at_unix =
121
Removed:
Recovery.timestamp_to_unix_seconds
122
Removed:
(Evidence.Feedback.reported_at report);
123
Removed:
signals = List.map describe_signal (Evidence.Feedback.signals report);
119
Added:
at_unix = Recovery.timestamp_to_unix_seconds (Feedback.reported_at report);
120
Added:
signals = List.map describe_signal (Feedback.signals report);
124
121
factor_scores =
125
122
List.map (fun f -> (f, factor_score f report)) factor_fields;
126
123
}
test/memory_repo.ml
@@ -5,7 +5,7 @@
5
5
mutable active : Repository.routine_id option;
6
6
mutable current : Evidence.Workout.t option;
7
7
mutable stored : Repository.record list; (* most recent first *)
8
Removed:
mutable feedback : Evidence.Feedback.t list; (* most recent first *)
8
Added:
mutable feedback : Feedback.t list; (* most recent first *)
9
9
mutable batches : Workout_import.batch list;
10
10
(* insertion order, newest first *)
11
11
mutable records : Repository.imported_record list; (* newest ended_at first *)
test/test_codec.ml
@@ -184,7 +184,7 @@
184
184
( "relative feedback round-trips every level",
185
185
`Quick,
186
186
fun () ->
187
Removed:
let open Evidence.Feedback in
187
Added:
let open Feedback in
188
188
let report =
189
189
make ~reported_at:(at 100)
190
190
[ Motivation Better_than_usual; Difficulty Worse_than_usual ]
@@ -213,12 +213,10 @@
213
213
| Ok report ->
214
214
Alcotest.(check bool)
215
215
"legacy levels mapped" true
216
Removed:
(Evidence.Feedback.signals report
216
Added:
(Feedback.signals report
217
217
= [
218
Removed:
Evidence.Feedback.Motivation
219
Removed:
Evidence.Feedback.Worse_than_usual;
220
Removed:
Evidence.Feedback.Difficulty
221
Removed:
Evidence.Feedback.Better_than_usual;
218
Added:
Feedback.Motivation Feedback.Worse_than_usual;
219
Added:
Feedback.Difficulty Feedback.Better_than_usual;
222
220
])
223
221
| Error e -> Alcotest.failf "decode failed: %a" Codec.pp_error e );
224
222
]
test/test_evidence.ml
@@ -2,7 +2,6 @@
2
2
3
3
module Stimulus = Evidence.Stimulus
4
4
module Workout = Evidence.Workout
5
Removed:
module Feedback = Evidence.Feedback
6
5
module Log = Evidence.Log
7
6
module Observation = Evidence.Observation
8
7
test/test_sqlite_repo.ml
@@ -292,10 +292,8 @@
292
292
(run
293
293
(S.record_feedback s id ~reported_at:(day 1)
294
294
[
295
Removed:
Evidence.Feedback.Motivation
296
Removed:
Evidence.Feedback.Better_than_usual;
297
Removed:
Evidence.Feedback.Difficulty
298
Removed:
Evidence.Feedback.As_usual;
295
Added:
Feedback.Motivation Feedback.Better_than_usual;
296
Added:
Feedback.Difficulty Feedback.As_usual;
299
297
]))
300
298
in
301
299
id
@@ -306,18 +304,14 @@
306
304
let s = S.make ~repo in
307
305
let reports = run (S.feedback s t) in
308
306
Alcotest.(check int) "one feedback report" 1 (List.length reports);
309
Removed:
let signals = Evidence.Feedback.signals (List.hd reports) in
307
Added:
let signals = Feedback.signals (List.hd reports) in
310
308
Alcotest.(check int) "two signals" 2 (List.length signals);
311
309
Alcotest.(check bool)
312
310
"motivation signal preserved" true
313
Removed:
(List.mem
314
Removed:
(Evidence.Feedback.Motivation
315
Removed:
Evidence.Feedback.Better_than_usual) signals);
311
Added:
(List.mem (Feedback.Motivation Feedback.Better_than_usual) signals);
316
312
Alcotest.(check bool)
317
313
"difficulty signal preserved" true
318
Removed:
(List.mem
319
Removed:
(Evidence.Feedback.Difficulty Evidence.Feedback.As_usual)
320
Removed:
signals)) );
314
Added:
(List.mem (Feedback.Difficulty Feedback.As_usual) signals)) );
321
315
( "application feedback survives a reconnect",
322
316
`Quick,
323
317
fun () ->
test/test_web.ml
@@ -781,14 +781,12 @@
781
781
in
782
782
Alcotest.(check int)
783
783
"one feedback report stored" 1 (List.length reports);
784
Removed:
let signal_list = Evidence.Feedback.signals (List.hd reports) in
784
Added:
let signal_list = Feedback.signals (List.hd reports) in
785
785
Alcotest.(check (list bool))
786
786
"only motivation stored" [ true ]
787
787
(List.map
788
788
(function
789
Removed:
| Evidence.Feedback.Motivation
790
Removed:
Evidence.Feedback.Better_than_usual ->
791
Removed:
true
789
Added:
| Feedback.Motivation Feedback.Better_than_usual -> true
792
790
| _ -> false)
793
791
signal_list) );
794
792
( "skipping the entire feedback flow records nothing",
@@ -833,14 +831,12 @@
833
831
Lwt_main.run (Memory_repo.feedback repo trainee.Trainee.id)
834
832
in
835
833
Alcotest.(check int) "one report stored" 1 (List.length reports);
836
Removed:
let signals = Evidence.Feedback.signals (List.hd reports) in
834
Added:
let signals = Feedback.signals (List.hd reports) in
837
835
Alcotest.(check bool)
838
836
"the pre-back motivation answer persists" true
839
837
(List.exists
840
838
(function
841
Removed:
| Evidence.Feedback.Motivation
842
Removed:
Evidence.Feedback.Better_than_usual ->
843
Removed:
true
839
Added:
| Feedback.Motivation Feedback.Better_than_usual -> true
844
840
| _ -> false)
845
841
signals) );
846
842
( "closing the feedback modal discards the flow",
@@ -1677,9 +1673,9 @@
1677
1673
Lwt_main.run (Memory_repo.feedback repo trainee.Trainee.id)
1678
1674
in
1679
1675
Alcotest.(check int) "one report stored" 1 (List.length reports);
1680
Removed:
let signals = Evidence.Feedback.signals (List.hd reports) in
1676
Added:
let signals = Feedback.signals (List.hd reports) in
1681
1677
let count p = List.length (List.filter p signals) in
1682
Removed:
let open Evidence.Feedback in
1678
Added:
let open Feedback in
1683
1679
Alcotest.(check int)
1684
1680
"one motivation signal" 1
1685
1681
(count (function Motivation _ -> true | _ -> false));