5d76e853fa84baa6c4a05880d3f3b985a5e51878
braney
  Sat Aug 8 13:22:15 2026 -0700
docent: add session, loadSession and expect verbs, refs #37892

session: writes the whole cart at that step to sessions/<base>/<name>.txt, in
the format hgSession's save-to-a-local-file button produces. No login is
involved. With sessionUrlBase: set, the run also prints the load URL, so a tour
hands back the state it built instead of only a picture of it. A file rather
than a live hgsid link, because the hgsid cart keeps changing as the tour runs.

loadSession: is the other direction: a settings file by URL, a share link, a
named session, or a local file written by an earlier session:. The load always
goes to the server named in target:, since named sessions are per-server and
every later step navigates to target: by absolute URL.

expect: is the only verb that can fail a run. It checks the rows drawn, the
image height, the tooltip now up, and the page text, then throws, so make stops
at that step rather than writing a wrong figure over a right one.

A session taken on a lifted view is short-lived: it names the quickLift hub by
its trash path, and re-pointing it at a durable copy does not work today. See
#38046. The README says so rather than working around it.

diff --git src/hg/utils/docent/docent.mk src/hg/utils/docent/docent.mk
index 7925bf6c2d7..8775d3ec6f7 100644
--- src/hg/utils/docent/docent.mk
+++ src/hg/utils/docent/docent.mk
@@ -36,39 +36,42 @@
 # FAST=1 -> figures only: no dwells, no cursor animation, no screen recording, no mp4.
 # Same stills, about a third of the wall clock. Use it while iterating on figure content;
 # drop it for the final build that has to produce the videos.
 FAST_ENV = $(if $(FAST),DOCENT_FAST=1 ,)
 
 .PHONY: all list clean hires $(BASES)
 
 all: $(MP4S)
 
 $(FIGDIR)/%.mp4: %.docent.yaml $(DOCENT)
 	$(FAST_ENV)$(PW_ENV) node $(DOCENT) $<
 
 # hires: the same tours rendered for print -- SCALE times the pixels (a wider server image
 # drawn with a bigger track font, the HTML zoomed to match), stills only, written to their
 # own tree so the screen stills and the videos are left alone. Always a full rebuild: a
-# print run is rare and cheap to ask for exactly when it is wanted.
+# print run is rare and cheap to ask for exactly when it is wanted. Its `session:` files go
+# to their own tree too: a print run's cart carries pix=2550 and textSize=24, which is not
+# the state anyone wants handed to them.
 #
 #   make hires                     # every scenario at 3x -> stills.hires/<base>/
 #   make hires SCALE=2             # 2x
 #   make hires BASES=BP1           # one scenario
 #
 SCALE ?= 3
 HIRES ?= stills.hires
+HIRESSESS ?= sessions.hires
 hires:
 	@for b in $(BASES); do \
 	  echo "=== $$b at $(SCALE)x"; \
-	  DOCENT_SCALE=$(SCALE) DOCENT_STILLS=$(HIRES) DOCENT_FAST=1 $(PW_ENV) \
-	    node $(DOCENT) $$b.docent.yaml || exit 1; \
+	  DOCENT_SCALE=$(SCALE) DOCENT_STILLS=$(HIRES) DOCENT_SESSIONS=$(HIRESSESS) DOCENT_FAST=1 \
+	    $(PW_ENV) node $(DOCENT) $$b.docent.yaml || exit 1; \
 	done
 
 # Convenience: `make AP1` -> build ../AP1.mp4
 $(BASES): %: $(FIGDIR)/%.mp4
 
 list:
 	@echo $(BASES)
 
 clean:
 	rm -f $(MP4S)
-	rm -rf stills $(HIRES)
+	rm -rf stills $(HIRES) sessions $(HIRESSESS)