fix discard workout on cancel instead of saving it

The cancel handler called Service.finish, which persisted the in-progress workout to history and only cleared the slot. Cancelling therefore navigated away but never took effect as a cancellation: it saved a record instead of discarding one. Call Service.cancel, which clears the slot without writing history. This restores the doctrine that plan and record stay distinct: an abandoned session is not evidence, so it leaves no record (domain.md, "Keep plan and record distinct"). ARCHITECTURE.org already documents /workout/cancel as "Discard without saving"; the handler now matches it. Update the web flow test to assert the discarded workout leaves no logbook entry and its record route returns 404.

Commit
5aaa11f9346ba4d2ab568779039541dd6e6ab8d6
Author
Marius Peter <dev@marius-peter.com>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
lib/web/handlers.ml
index 67b35a40..6c1f5261 100644..100644
@@ -369,17 +369,18 @@
369 369 | None -> not_found Present.no_workout)
370 370
371 371 (* Leave the current workout unconditionally. Cancelling never shows an
372 Removed: invalid-form response: the workout in progress is saved as-is — a partial
373 Removed: record the logbook keeps and stays editable later — and the user returns
374 Removed: to the Routine tab, where the middle navigation action reverts from
375 Removed: "Current workout" to "Routine". A forged or missing CSRF token skips the
376 Removed: save but still navigates away, so the view is always left cleanly. *)
372 Added: invalid-form response: the workout in progress is discarded — an
373 Added: abandoned session is not evidence, so it leaves no record — and the user
374 Added: returns to the Routine tab, where the middle navigation action reverts
375 Added: from "Current workout" to "Routine". A forged or missing CSRF token skips
376 Added: the discard but still navigates away, so the view is always left
377 Added: cleanly. *)
377 378 let cancel t trainee request =
378 379 guard_csrf request >>= function
379 380 | Error _ -> redirect_to request Routes.routine
380 381 | Ok () ->
381 Removed: Service.finish t.service trainee.Trainee.id ~ended_at:(t.now ())
382 Removed: >>= fun _ -> redirect_to request Routes.routine
382 Added: Service.cancel t.service trainee.Trainee.id >>= fun _ ->
383 Added: redirect_to request Routes.routine
383 384
384 385 let routes t =
385 386 [
test/test_web.ml
index a2ae6449..9c9a4ee9 100644..100644
@@ -825,7 +825,7 @@
825 825 Alcotest.(check int)
826 826 "workout still in progress" 200
827 827 (status (get c "/workout")) );
828 Removed: ( "cancelling after recording a set saves the workout for later editing",
828 Added: ( "cancelling after recording a set discards the workout",
829 829 `Quick,
830 830 fun () ->
831 831 let c = client () in
@@ -850,7 +850,7 @@
850 850 ]
851 851 in
852 852 Alcotest.(check int) "recorded a set" 303 (status recorded);
853 Removed: (* Cancel with a valid token. It saves the log as a partial entry
853 Added: (* Cancel with a valid token. It discards the in-progress workout
854 854 and returns to the routine tab. *)
855 855 let token = Option.get (csrf_token (body (get c "/workout"))) in
856 856 let cancelled =
@@ -865,14 +865,14 @@
865 865 Alcotest.(check int)
866 866 "no workout in progress" 303
867 867 (status (get c "/workout"));
868 Removed: (* The workout was saved as a partial entry: the logbook holds the
869 Removed: record and it opens for later editing. *)
868 Added: (* The workout left no record: an abandoned session is not
869 Added: evidence, so the logbook holds nothing and no record opens. *)
870 870 let logbook_page = body (get c "/logbook") in
871 871 Alcotest.(check bool)
872 Removed: "logbook shows the saved workout" true
872 Added: "logbook shows no saved workout" false
873 873 (contains ~substring:"/logbook/w1" logbook_page);
874 874 Alcotest.(check int)
875 Removed: "the saved workout opens for editing" 200
875 Added: "the discarded workout has no record" 404
876 876 (status (get c "/logbook/w1")) );
877 877 ( "the saved logbook view does not offer a cancel control",
878 878 `Quick,