docs Apply STE100 to code comments

Split every prose semicolon in a comment or doc-comment into two sentences across lib/ and bin/, keeping semicolons that belong to OCaml code (record and list syntax, sequence expressions, string literals). No code, type, or interface declaration changed; the edits are wording only. dune build @check and @fmt stay clean.

Commit
5b53df8bdf10e819d14a290922d2633793c85208
Author
Marius Peter <dev@marius-peter.com>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
bin/main.ml
index 66ee58fa..a89c504e 100644..100644
@@ -8,12 +8,12 @@
8 8 unset, a random secret is generated for this run only, so
9 9 sessions do not survive a restart. Set it in production.
10 10 - HITO_PORT TCP port. Default: 8080
11 Removed: - HITO_SEED_PASSWORD Password for the seeded [blendux] account. Required;
12 Removed: the server refuses to start when unset. Temporary, until
11 Added: - HITO_SEED_PASSWORD Password for the seeded [blendux] account. Required.
12 Added: The server refuses to start when unset. Temporary, until
13 13 public registration returns.
14 14
15 15 The socket binds loopback only. Authentication is local username and
16 Removed: password; sessions and CSRF tokens are signed with the secret.
16 Added: password. Sessions and CSRF tokens are signed with the secret.
17 17
18 18 Public sign-up is closed: [Handlers.make] leaves [registration_open] at its
19 19 [false] default, and a single account ([blendux]) is seeded on startup with
lib/app/service.ml
index 0a610f2f..4448133d 100644..100644
@@ -7,7 +7,7 @@
7 7
8 8 (* Error types are part of the flat public interface, so they live at the top
9 9 level of the functor. The implementation below is grouped into focused
10 Removed: use-case modules over the shared [t]; the public names are re-exported at
10 Added: use-case modules over the shared [t]. The public names are re-exported at
11 11 the end, so callers and {!Service.mli} see one flat service. *)
12 12
13 13 type register_error = [ `Username of Trainee.username_error | `Username_taken ]
@@ -58,7 +58,7 @@
58 58 let register t ~username ~password =
59 59 let open Lwt_result.Syntax in
60 60 (* Validate the username, hash the password, then create the account.
61 Removed: Username validation short-circuits into [register_error]; the password
61 Added: Username validation short-circuits into [register_error]. The password
62 62 carries no policy, so hashing always succeeds. *)
63 63 let* username =
64 64 Lwt.return
@@ -199,7 +199,7 @@
199 199 let finished = Evidence.Workout.finish workout ~ended_at in
200 200 R.finish_workout t.repo trainee finished >|= fun record -> Some record
201 201
202 Removed: (* Discard the workout in progress. This clears the slot only; it never
202 Added: (* Discard the workout in progress. This clears the slot only. It never
203 203 writes to history, so a cancelled workout leaves no record. The doctrine
204 204 keeps plan and record distinct — an abandoned session is not evidence. *)
205 205 let cancel t trainee =
lib/app/service.mli
index cb3aa082..ef458f96 100644..100644
@@ -113,7 +113,7 @@
113 113 type log_error =
114 114 | No_workout_in_progress
115 115 | Rejected of Evidence.Workout.error
116 Removed: (** The workout refused the stimulus; see {!Evidence.Workout.error}. *)
116 Added: (** The workout refused the stimulus. See {!Evidence.Workout.error}. *)
117 117
118 118 val pp_log_error : Format.formatter -> log_error -> unit
119 119
lib/app/trainee.mli
index 5093bdd5..609b66dd 100644..100644
@@ -32,7 +32,7 @@
32 32
33 33 type credential
34 34 (** A password verifier. Carries a salted hash, never the password. The hashing
35 Removed: algorithm is a {!Password_hash.S} adapter detail; this type only wraps the
35 Added: algorithm is a {!Password_hash.S} adapter detail. This type only wraps the
36 36 stored verifier so no other layer sees a plaintext password. *)
37 37
38 38 val credential_of_hash : string -> credential
lib/core/evidence.ml
index 2b3493d9..9625e7ea 100644..100644
@@ -278,7 +278,7 @@
278 278
279 279 let replace_stimulus t ~slot s =
280 280 check_against (prescription_at t slot) s;
281 Removed: (* A correction targets the slot; it never adds to the recorded volume.
281 Added: (* A correction targets the slot. It never adds to the recorded volume.
282 282 Replace the slot's fill in place, keeping its position in performance
283 283 order. When the slot was empty, record it as its first fill. *)
284 284 if List.mem_assoc slot t.performed then
lib/core/evidence.mli
index c22c144d..95696db9 100644..100644
@@ -127,7 +127,7 @@
127 127 [Invalid] for a stimulus the slot does not call for. *)
128 128
129 129 val finish : t -> ended_at:Recovery.timestamp -> t
130 Removed: (** Sets [ended_at] once; later calls retain the first value. *)
130 Added: (** Sets [ended_at] once. Later calls retain the first value. *)
131 131
132 132 val prescription : t -> Prescription.Workout.t
133 133 val clearance : t -> Recovery.clearance
lib/core/prescription.mli
index c5194c47..c7543936 100644..100644
@@ -84,7 +84,7 @@
84 84 (** Cycle order. *)
85 85
86 86 val workout_after : t -> Workout.t -> Workout.t
87 Removed: (** Wraps; unknown workouts fall back to the first. *)
87 Added: (** Wraps. Unknown workouts fall back to the first. *)
88 88
89 89 val pp : Format.formatter -> t -> unit
90 90
lib/core/progression.ml
index 5b1969cb..a7b94685 100644..100644
@@ -50,7 +50,7 @@
50 50 else Progressing
51 51 | None ->
52 52 (* Never advanced. Only a stall once the record is long enough to say
53 Removed: so; otherwise two sessions a day apart would condemn the routine. *)
53 Added: so. Otherwise two sessions a day apart would condemn the routine. *)
54 54 if elapsed_between first latest >= window then Stalled
55 55 else raise (Invalid Insufficient_data))
56 56
lib/core/progression.mli
index c6623434..4412d522 100644..100644
@@ -23,7 +23,7 @@
23 23 }
24 24
25 25 val remedy : assessment -> remedy option
26 Removed: (** [Some] only for [Stalled]; it never adds work. *)
26 Added: (** [Some] only for [Stalled]. It never adds work. *)
27 27
28 28 val pp_remedy : Format.formatter -> remedy -> unit
29 29
@@ -39,7 +39,7 @@
39 39 rep_range:Prescription.Rep_range.t ->
40 40 Evidence.Stimulus.Effort.t ->
41 41 load_verdict
42 Removed: (** Only the range floor matters: below it is [Too_heavy]; at twelve reps the
42 Added: (** Only the range floor matters: below it is [Too_heavy]. At twelve reps the
43 43 verdict is [Increase]. *)
44 44
45 45 val pp_load_verdict : Format.formatter -> load_verdict -> unit
lib/persistence/codec.ml
index 4bf9488d..db4ddf02 100644..100644
@@ -89,7 +89,7 @@
89 89 | _ -> Error (Malformed "effort arity")
90 90
91 91 (* Decode a stimulus and the slot it filled. The current format prefixes the
92 Removed: slot; a record from before slots were stored omits it, and replays in
92 Added: slot. A record from before slots were stored omits it, and replays in
93 93 performance order through [add_stimulus] instead. *)
94 94 let decode_stimulus fields =
95 95 let delivery = function
@@ -133,8 +133,8 @@
133 133 ~since:(Recovery.timestamp_of_unix_seconds 0)
134 134 ~now:(Recovery.timestamp_of_unix_seconds secs)
135 135
136 Removed: (* A clearance cannot be minted directly; it is derived from a readiness.
137 Removed: [Recovered] comes from a [Ready] reading; an override needs a [Recovering]
136 Added: (* A clearance cannot be minted directly. It is derived from a readiness.
137 Added: [Recovered] comes from a [Ready] reading. An override needs a [Recovering]
138 138 reading carrying the stored durations. *)
139 139 let decode_clearance = function
140 140 | [ "recovered" ] -> Ok (Option.get (Recovery.clear Recovery.Ready))
@@ -176,7 +176,7 @@
176 176 Buffer.contents buf
177 177
178 178 (* A fully-parsed header, gathered before any replay. Parsing produces this
179 Removed: typed record; replay consumes it. Keeping the two phases apart removes the
179 Added: typed record. Replay consumes it. Keeping the two phases apart removes the
180 180 mutable accumulators the old single pass needed. *)
181 181 type parsed = {
182 182 routine_name : string;
@@ -188,7 +188,7 @@
188 188 (** Performance order, each with the slot it filled when known. *)
189 189 }
190 190
191 Removed: (* Fields accumulated while folding over lines; every field is optional until
191 Added: (* Fields accumulated while folding over lines. Every field is optional until
192 192 its line is seen. [stimuli] is reversed for O(1) prepend and flipped once at
193 193 the end. *)
194 194 type acc = {
@@ -216,7 +216,7 @@
216 216 | Error _ -> Error (Malformed label)
217 217
218 218 (* Fold one line into the accumulator. A line either sets a header field or
219 Removed: appends a stimulus; anything else is malformed. *)
219 Added: appends a stimulus. Anything else is malformed. *)
220 220 let step acc = function
221 221 | [ "routine"; name ] -> Ok { acc with a_routine = Some name }
222 222 | [ "prescription"; name ] -> Ok { acc with a_prescription = Some name }
@@ -284,7 +284,7 @@
284 284 }))
285 285
286 286 (* Drive the core constructors from a typed header. The core raises on a
287 Removed: rejected stimulus; catch it once here and report it as data corruption. *)
287 Added: rejected stimulus. Catch it once here and report it as data corruption. *)
288 288 let replay ~prescription parsed =
289 289 try
290 290 let workout =
lib/persistence/codec.mli
index be568bab..9dfe1492 100644..100644
@@ -17,7 +17,7 @@
17 17 | Unknown_routine of string
18 18 | Unknown_workout_name of { routine : string; workout : string }
19 19 | Replay_rejected of string
20 Removed: (** The core refused a stored stimulus; the store is inconsistent. *)
20 Added: (** The core refused a stored stimulus. The store is inconsistent. *)
21 21
22 22 val pp_error : Format.formatter -> error -> unit
23 23
lib/persistence/migrations.ml
index c460e427..ef13f7dc 100644..100644
@@ -197,7 +197,7 @@
197 197 Db.exec request (migration.version, migration.name)
198 198
199 199 (* Apply one migration inside a transaction, then record it. The ledger check
200 Removed: makes this idempotent; the [IF NOT EXISTS] clauses keep an already-populated
200 Added: makes this idempotent. The [IF NOT EXISTS] clauses keep an already-populated
201 201 file from a pre-ledger build safe. *)
202 202 let apply_migration ((module Db : Caqti_lwt.CONNECTION) as db) migration =
203 203 let open Lwt_result.Syntax in
lib/web/decode.ml
index 3538a058..61d59394 100644..100644
@@ -86,10 +86,10 @@
86 86
87 87 (* --- profile --- *)
88 88
89 Removed: (* The raw username string; the domain normalizes and validates it downstream. *)
89 Added: (* The raw username string. The domain normalizes and validates it downstream. *)
90 90 let profile_username = Form.required Form.string "username"
91 91
92 Removed: (* Current and new password, both required. Passwords carry no policy here; the
92 Added: (* Current and new password, both required. Passwords carry no policy here. The
93 93 service verifies the current one before storing the new one. *)
94 94 let profile_password =
95 95 let open Form in
lib/web/decode.mli
index acde3f66..8d10d6be 100644..100644
@@ -4,7 +4,7 @@
4 4 val stimulus : Prescription.Stimulus.t -> Evidence.Stimulus.t Dream_html.Form.t
5 5
6 6 val profile_username : string Dream_html.Form.t
7 Removed: (** The raw username from the rename form; the domain validates it. *)
7 Added: (** The raw username from the rename form. The domain validates it. *)
8 8
9 9 val profile_password : (string * string) Dream_html.Form.t
10 10 (** The current and new passwords from the change-password form. *)
lib/web/handlers.ml
index d0466d1b..5a32ad20 100644..100644
@@ -95,7 +95,7 @@
95 95 | Some id -> Service.find_trainee t.service (Trainee.id id)
96 96
97 97 (* Resolve the authenticated trainee, or send an unauthenticated request to
98 Removed: the sign-in page. [handler] receives the trainee; the request and any path
98 Added: the sign-in page. [handler] receives the trainee. The request and any path
99 99 captures stay in the caller's scope, so this one combinator serves every
100 100 route regardless of how many captures Dream passes. *)
101 101 let authenticated t request handler =
@@ -179,7 +179,7 @@
179 179 redirect_to request Routes.login
180 180
181 181 let routes t =
182 Removed: (* Public sign-up is disabled by default; the [/register] routes appear
182 Added: (* Public sign-up is disabled by default. The [/register] routes appear
183 183 only when [registration_open] is set. Everything else is unconditional. *)
184 184 let register_routes =
185 185 if t.registration_open then
@@ -216,14 +216,14 @@
216 216
217 217 (* The slot a workout view should open on: the first slot still awaiting a
218 218 record, or the first slot when every slot is filled. A caller clamps a
219 Removed: requested slot against the prescription; this supplies the default. *)
219 Added: requested slot against the prescription. This supplies the default. *)
220 220 let default_slot workout =
221 221 match Evidence.Workout.outstanding workout with
222 222 | (slot, _) :: _ -> slot
223 223 | [] -> 0
224 224
225 225 (* The slot a workout view should open on. An explicit [?slot=] query
226 Removed: wins when it names a real slot; otherwise the view defaults to the first
226 Added: wins when it names a real slot. Otherwise the view defaults to the first
227 227 incomplete slot. A [?slot=] out of range, or absent, falls back to the
228 228 default, so a bookmarked or hand-edited URL never renders an empty view. *)
229 229 let active_slot request workout =
@@ -240,7 +240,7 @@
240 240
241 241 (* Map an [Evidence.Workout.t] into the view-model DTO the presenter renders,
242 242 so no Evidence or Prescription type crosses the boundary into Pages. The
243 Removed: same mapping serves the live workout and a saved-record view; the caller
243 Added: same mapping serves the live workout and a saved-record view. The caller
244 244 supplies [record_id]/[editing]/[errors] separately. *)
245 245
246 246 (* The ending code a single-choice form uses, taken from an effort's outcome.
lib/web/handlers.mli
index 5ad5f157..bb7e80a0 100644..100644
@@ -16,7 +16,7 @@
16 16 pre-seeded accounts until public sign-up returns. *)
17 17
18 18 val routes : t -> Dream.route list
19 Removed: (** The route table. Session and CSRF middleware are applied per handler; wrap
19 Added: (** The route table. Session and CSRF middleware are applied per handler. Wrap
20 20 with {!Dream.sql_sessions} or {!Dream.memory_sessions} and a secret at the
21 21 top level. *)
22 22
lib/web/pages.ml
index 4f3fddd2..1c82a140 100644..100644
@@ -41,7 +41,7 @@
41 41 (* Three always-available actions. The middle slot points to the routine
42 42 normally and to the workout in progress while logging, so a running
43 43 workout stays one tap away without adding a fourth destination. The logbook
44 Removed: tab always reads "Logbook"; the username lives on its own profile control. *)
44 Added: tab always reads "Logbook". The username lives on its own profile control. *)
45 45 let navigation_links () =
46 46 [
47 47 nav_link "home" Routes.home "Home";
@@ -435,7 +435,7 @@
435 435
436 436 (* Beginning under override needs an explicit acknowledgement, so its submit is
437 437 gated behind a confirmation modal. Without script the form submits at once —
438 Removed: the doctrine's deviation stays possible; the modal only makes it deliberate.
438 Added: the doctrine's deviation stays possible. The modal only makes it deliberate.
439 439 The client reuses the shared confirm machinery: [data-hito-confirm-cancel]
440 440 opens the dialog, [data-hito-confirm-form] is the form its accept submits. *)
441 441 let override_begin request ~routine_id =
@@ -698,7 +698,7 @@
698 698 let field_id field = Printf.sprintf "slot-%d-%s" slot field in
699 699 let selected = selected_extension in
700 700 (* A single-exercise slot shows one row with a visible "Reps to failure"
701 Removed: label; a pre-exhaust pair shows a shared column heading and hides the
701 Added: label. A pre-exhaust pair shows a shared column heading and hides the
702 702 per-row labels. *)
703 703 let hide_labels = List.length movements > 1 in
704 704 let head =
@@ -787,7 +787,7 @@
787 787 in
788 788 (* The early-workout notice. The override was already confirmed in a modal, so
789 789 on the workout screen this is informational only: a toast rather than a
790 Removed: component in the main content. It is a polite live region; the client shows
790 Added: component in the main content. It is a polite live region. The client shows
791 791 it briefly then dismisses it. Without script it stays visible as a quiet
792 792 fixed notice, so a no-JS visitor is still told. *)
793 793 let override_note =
@@ -858,7 +858,7 @@
858 858 in
859 859 (* The panel for the active slot. It shows one exercise at a time: a recorded
860 860 slot renders its read-only summary and a pre-filled correction form (which
861 Removed: replaces the slot rather than adding volume); an outstanding slot renders
861 Added: replaces the slot rather than adding volume). An outstanding slot renders
862 862 the record form. *)
863 863 let active_panel =
864 864 match List.nth_opt vm.slots active_slot with
@@ -948,7 +948,7 @@
948 948 void "input" [ type_ "submit"; value "Finish workout" ];
949 949 ];
950 950 (* Cancel is a native POST form. Without script, it submits
951 Removed: immediately. The client only opens the confirm dialog; its
951 Added: immediately. The client only opens the confirm dialog. Its
952 952 acceptance submits this form as a full document navigation so
953 953 the cancelled workout cannot leave a stale app shell behind. *)
954 954 tag "form"
@@ -970,7 +970,7 @@
970 970 ];
971 971 ];
972 972 (* The confirmation modal. Native dialog for built-in focus trapping
973 Removed: and Escape-to-close. The client opens it; "Cancel workout" submits
973 Added: and Escape-to-close. The client opens it. "Cancel workout" submits
974 974 the cancel form, "Keep logging" closes it. *)
975 975 tag "dialog"
976 976 [
@@ -1035,7 +1035,7 @@
1035 1035 ]
1036 1036
1037 1037 (* The subjective feedback form. Leveled selects report sleep, appetite,
1038 Removed: readiness, motivation, and difficulty against a personal baseline; flags
1038 Added: readiness, motivation, and difficulty against a personal baseline. Flags
1039 1039 report pain, injury, and insufficient preparation. A field left blank reports
1040 1040 nothing, so the trainee submits only what they mean to. Feedback is
1041 1041 standalone — recorded from the Logbook at any time. *)
@@ -1633,7 +1633,7 @@
1633 1633
1634 1634 (* The account profile page. It names the signed-in trainee and offers two
1635 1635 independent forms: rename the account, and change the password. Each form
1636 Removed: reports its own error inline; [notice] confirms a successful change. Both are
1636 Added: reports its own error inline. [notice] confirms a successful change. Both are
1637 1637 plain authenticated app-forms, so they work with or without script. *)
1638 1638 let profile request ?(logging = false) ~viewer ?username_error ?password_error
1639 1639 ?notice () =
lib/web/pages.mli
index ba94da8e..9522dbd5 100644..100644
@@ -40,12 +40,12 @@
40 40 page
41 41 (** Renders one prescribed slot at a time under a vertical group of named
42 42 exercise buttons. Authenticated pages carry generic progressive-enhancement
43 Removed: markers; current workouts additionally mark slot links and forms, while
43 Added: markers. Current workouts additionally mark slot links and forms, while
44 44 saved-record edits use the generic authenticated form path. [active_slot]
45 Removed: button; a handler clamps a requested slot and falls back to the first
45 Added: button. A handler clamps a requested slot and falls back to the first
46 46 outstanding slot. [record_id] is [None] for the workout in progress and
47 47 [Some id] for a saved history record. [logging] sets the middle navigation
48 Removed: action; it defaults to a live workout view (true when [record_id] is
48 Added: action. It defaults to a live workout view (true when [record_id] is
49 49 [None]). *)
50 50
51 51 type feedback_flow = { step : int; answers : (string * string) list }
@@ -78,7 +78,7 @@
78 78 page
79 79 (** The account profile page: rename the account and change the password, each
80 80 an independent form. [username_error] and [password_error] report a refused
81 Removed: change inline; [notice] confirms a successful one. *)
81 Added: change inline. [notice] confirms a successful one. *)
82 82
83 83 val problem : title:string -> detail:string -> page
84 84
@@ -96,4 +96,4 @@
96 96 View_model.App_feedback.t list ->
97 97 page
98 98 (** The authenticated application feedback page. One tab accepts a freeform
99 Removed: message; the other lists the trainee's submitted messages. *)
99 Added: message. The other lists the trainee's submitted messages. *)
lib/web/view_model.ml
index 6dd98cc2..4a65260e 100644..100644
@@ -7,7 +7,7 @@
7 7 model without ever naming an inner-circle type.
8 8
9 9 Migrated so far: the signed-in viewer, application feedback, and subjective
10 Removed: feedback. Other pages still take entities directly; they move here page by
10 Added: feedback. Other pages still take entities directly. They move here page by
11 11 page. *)
12 12
13 13 module Viewer = struct
@@ -75,7 +75,7 @@
75 75 gate : gate;
76 76 }
77 77 (** The overview while no workout is in progress. The recovery policy has
78 Removed: already decided [gate] in the use case; the page only renders it. *)
78 Added: already decided [gate] in the use case. The page only renders it. *)
79 79 end
80 80
81 81 module Workout = struct
@@ -98,7 +98,7 @@
98 98 label : string; (** Exercise label for the selector option and heading. *)
99 99 movements : movement list;
100 100 recorded_summary : string option;
101 Removed: (** [Some description] once the slot is filled; [None] while
101 Added: (** [Some description] once the slot is filled. [None] while
102 102 outstanding. Drives the recorded/outstanding branch without an
103 103 entity. *)
104 104 selected_extension : string;
lib/web/workout_client.ml
index 88d72e2a..e5a66408 100644..100644
@@ -55,7 +55,7 @@
55 55 (Js.number_of_float 3000.)))
56 56
57 57 (* The workout timer. The sticky bar carries the workout's start time as an
58 Removed: epoch in [data-started]; the elapsed time is computed from it, so a content
58 Added: epoch in [data-started]. The elapsed time is computed from it, so a content
59 59 swap that re-renders the bar never resets the count. A single interval runs
60 60 at a time: [start_timer] clears the previous one before it reads the bar the
61 61 latest render produced. When no bar is present, the timer stops. *)
@@ -75,7 +75,7 @@
75 75 | None -> ()
76 76 | Some started -> (
77 77 (* Epoch seconds exceed js_of_ocaml's 31-bit [int] range, so the
78 Removed: start and the current time are kept as floats; only the small
78 Added: start and the current time are kept as floats. Only the small
79 79 elapsed difference is narrowed to an [int]. Doing the subtraction
80 80 in [int] would overflow and yield a wrong count. *)
81 81 let started =
@@ -326,8 +326,8 @@
326 326 Js._true
327 327
328 328 (* The cancel confirmation modal. The cancel form submits directly without
329 Removed: script; with script, its submit is intercepted only to open a native dialog.
330 Removed: "Cancel workout" submits the native form as a full document POST; "Keep
329 Added: script. With script, its submit is intercepted only to open a native dialog.
330 Added: "Cancel workout" submits the native form as a full document POST. "Keep
331 331 logging" and Escape close the dialog. The dialog and the pending form are
332 332 found fresh on each click, so a content swap never leaves a stale
333 333 reference. *)
@@ -411,7 +411,7 @@
411 411 Js._true)))))
412 412
413 413 (* The exercise dropdown navigates the moment its selection changes. It lives in
414 Removed: a GET form ([data-hito-exercise-form]) that submits to the workout path; the
414 Added: a GET form ([data-hito-exercise-form]) that submits to the workout path. The
415 415 client turns a change into a workout-scoped content swap to [?slot=N], so no
416 416 submit click is needed. Without script the form's submit button still works. *)
417 417 let exercise_change event =