8afc792afaf50aab2d6b83a33ba41b47dbf1df4a
max
  Tue Sep 29 15:51:16 2026 -0700
hgSession: also clear the pending session-load marker before a local-file save

The named-session save path already did this; the "save as local file"
export path did not, so the marker (and the session name/owner it points
at) could ride along into an exported file and resurface on re-import,
refs #38399

diff --git src/hg/hgSession/hgSession.c src/hg/hgSession/hgSession.c
index bed7f0cb928..3ab009f40af 100644
--- src/hg/hgSession/hgSession.c
+++ src/hg/hgSession/hgSession.c
@@ -818,30 +818,42 @@
 cartRemovePrefix(cart, hgsMakeDownloadPrefix);
 cartRemovePrefix(cart, hgsDoDownloadPrefix);
 cartRemovePrefix(cart, hgsDo);
 cartRemove(cart, hgsOldSessionName);
 cartRemove(cart, hgsCancel);
 /* Two of the Save form's own inputs.  If they stay in the cart they are stored inside every
  * session saved afterwards, so one session's description travels in sessions that never had
  * one.  hgsNewSessionShare is left alone on purpose: it has the same problem, but it is also
  * the only memory of the user's "Allow this session to be loaded by others" choice, and
  * showSavingOptions() defaults that box to checked.  Removing it here would quietly re-check
  * the box for someone who keeps their sessions private. */
 cartRemove(cart, hgsNewSessionName);
 cartRemove(cart, hgsNewSessionDescription);
 }
 
+static void clearSessionJustLoadedMarker(struct cart *cart)
+/* A pending "session just loaded" marker (and the name/owner it refers to) belongs to the
+ * live cart's next page view, not to a session's own saved contents.  Call this at every
+ * place that bakes the current cart into a persistent artifact (a named session, a local
+ * download) -- but not at hgSession's own generic end-of-request cleanup, which must leave
+ * the marker alone so hgTracks still gets to show the notice on its next page. */
+{
+cartRemove(cart, hgsSessionJustLoaded);
+cartRemove(cart, hgsOtherUserSessionName);
+cartRemove(cart, hgsOtherUserName);
+}
+
 static void outIfNotPresent(struct cart *cart, struct dyString *dy, char *track, int tdbVis)
 /* Output default trackDb visibility if it's not mentioned in the cart. */
 {
 char *cartVis = cartOptionalString(cart, track);
 if (cartVis == NULL)
     {
     if (dy)
         dyStringPrintf(dy,"&%s=%s", track, hStringFromTv(tdbVis));
     else
         printf("%s %s\n", track, hStringFromTv(tdbVis));
     }
 }
 
 static void outAttachedHubUrls(struct cart *cart, struct dyString *dy)
 /* output the hubUrls for all attached hubs in the cart. */
@@ -958,35 +970,31 @@
 sqlDyStringPrintf(dy, "DELETE FROM %s WHERE userName = '%s' AND "
                   "sessionName = '%s';",
                   namedSessionTable, encUserName, encSessionName);
 sqlUpdate(conn, dy->string);
 
 dyStringClear(dy);
 sqlDyStringPrintf(dy, "INSERT INTO %s ", namedSessionTable);
 sqlDyStringPrintf(dy, "(userName, sessionName, contents, shared, "
                "firstUse, lastUse, useCount");
 if (gotSettings)
     sqlDyStringPrintf(dy, ", settings");
 sqlDyStringPrintf(dy, ") VALUES (");
 sqlDyStringPrintf(dy, "'%s', '%s', ", encUserName, encSessionName);
 sqlDyStringPrintf(dy, "'");
 cleanHgSessionFromCart(cart);
-/* A pending "session just loaded" marker (and the name/owner it refers to) belongs to the
- * live cart's next page view, not to a session's own saved contents. */
-cartRemove(cart, hgsSessionJustLoaded);
-cartRemove(cart, hgsOtherUserSessionName);
-cartRemove(cart, hgsOtherUserName);
+clearSessionJustLoadedMarker(cart);
 struct dyString *encoded = dyStringNew(4096);
 cartEncodeState(cart, encoded);
 
 // First output the hubStatus id's for attached trackHubs
 outAttachedHubUrls(cart, encoded);
 
 // Now add all the default visibilities to output.
 outDefaultTracks(cart, encoded);
 
 sqlDyAppendEscaped(dy, encoded->string);
 dyStringFree(&encoded);
 sqlDyStringPrintf(dy, "', ");
 sqlDyStringPrintf(dy, "%d, ", sharingLevel);
 if (firstUse)
     sqlDyStringPrintf(dy, "'%s', ", firstUse);
@@ -1753,30 +1761,31 @@
 cartHideDefaultTracks(cart);
 cartCheckForCustomTracks(cart, dyMessage);
 hDisconnectCentral(&conn);
 return dyStringCannibalize(&dyMessage);
 }
 
 void doSaveLocal()
 /* Output current settings to be saved as a file on the user's machine.
  * Return a message confirming what we did. */
 {
 char *fileName = textOutSanitizeHttpFileName(cartString(cart, hgsSaveLocalFileName));
 char *compressType = cartString(cart, hgsSaveLocalFileCompress);
 struct pipeline *compressPipe = textOutInit(fileName, compressType, NULL);
 
 cleanHgSessionFromCart(cart);
+clearSessionJustLoadedMarker(cart);
 
 cartDumpHgSession(cart);
 
 // First output the hubStatus id's for attached trackHubs
 outAttachedHubUrls(cart, NULL);
 
 // Now add all the default visibilities to output.
 outDefaultTracks(cart, NULL);
 
 textOutClose(&compressPipe, NULL);
 }
 
 char *doLoad(boolean fromUrl, char *actionVar)
 /* Load settings from a file or URL sent by the user.
  * Return a message confirming what we did. */