d033cea2063e9362949baf5b4d8b837597173a0d
max
  Thu Sep 10 05:16:05 2026 -0700
Address the code review of the Sep 9 commits

Faceted composite: text that comes from a hub - a metadata column's
description, the name and title of a data type, and the values quoted back in
the "could not load the metadata" row - is put on the page as text rather than
as markup. The three places built their markup from template strings, so a
value carrying angle brackets or a quote was read as HTML: the column
description now goes through the shared htmlEncode() once where the header is
parsed, and the other two build their elements as nodes. The error row reads
better for it as well, since a value with brackets in it used to disappear from
the message that was meant to show it.

The saved UI state keys on the assembly as well as the metadata id. localStorage
is per-origin, so two assemblies whose tracks share a name were sharing one
entry, and a row order dragged on one came back on the other over a different
set of samples. hgTrackUi passes the database down for it. State saved under the
old key is dropped, which costs a facet selection or a page length.

Imprinting: the five subtrack description pages link back to the container as
hgTrackUi?db=$db&g=$parentTrack, without the hgsid. Native trackDb html is
substituted by hgTrackDb as it loads the table, where there is no cart, so
${hgsid} came out empty and the link read 'hgsid=&g=...'. Matches what the
Fiber-seq pages already do. The makeDoc note that described the old form is
updated with the reason.

UniProt otto: README.txt lists all eight things that reach runLog.txt. It had
four, and was missing LOCKED, along with PREFLIGHT-FAIL, END and INTERRUPTED.

refs #36210
refs #37599
refs #38300

diff --git src/hg/utils/otto/uniprot/README.txt src/hg/utils/otto/uniprot/README.txt
index 1a89dc56e93..11a2dec2488 100644
--- src/hg/utils/otto/uniprot/README.txt
+++ src/hg/utils/otto/uniprot/README.txt
@@ -23,34 +23,40 @@
 
 uniprotToTab needs the lxml XML parser. It is not in the python standard library
 and hgwdev has no system-wide copy, so it lives in a virtualenv in venv/. Build
 or rebuild it with:
 
     cd /hive/data/outside/otto/uniprot && ./makeVenv.sh
 
 Note that ~/.local is not enough: cron runs this as otto, which does not see
 anyone else's per-user python packages.
 
 Did it run?
 
 runLog.txt gets one line per run and is never truncated, so it is the history of
 the job:
 
+    PREFLIGHT-FAIL  the venv or the parser was not usable, doUniprot never ran
     START           a run began
+    END             doUniprot returned, exit code on the line
+    LOCKED          another doUniprot holds the lock file, this run did nothing
     NOCHANGE        UniProt had no new release, nothing to do, no mail sent
     OK              new release, tracks rebuilt
     FAIL            the run died, exit code and log named on the line
+    INTERRUPTED     a signal killed the run, the lock file was removed
+
+A normal month is START, END, then one of LOCKED, NOCHANGE, OK or FAIL.
 
 lastRun.log is the log of the most recent run and is overwritten every month. A
 failing run is kept as lastFail.log, and its last 25 lines are mailed to the
 MAILTO addresses in otto's crontab. A month without a new UniProt release sends
 no mail, so silence means "nothing to do", not "it worked".
 
 version.txt in each bigBed/<db> directory is what the trackDb dataVersion setting
 shows on the track description page. It is only rewritten when the release string
 changes, so its date on disk is the date the data last moved, not the date the
 pipeline last ran.
 
 Directories:
 
 fasta - current protein sequences and their sizes, named by taxon
 geneMaps/ - a mapping of the current protein sequences to the genome, one for each species and database.