236b28263edfc3b0cb9da780d65d2b647a0d98a6
braney
  Wed Sep 9 08:47:28 2026 -0700
docent: rm35920 was reading hg38's own ultras track, not the fixture hub's

The nightly went red on 2026-09-08 at rm35920's tooltip check. The cause was not
the bug the script is about. hg38 has a native `ultras` track under the
unusualcons superTrack, our copy of the reporter's hub called its track `ultras`
too, and a name resolves to `img_data_<name>` before it resolves to a hub row's
`hub_<n>_<name>`. The exact native id won every time: `track: {ultras: pack}`
turned on the native track and its superTrack, and `mouseover: {track: ultras}`
read the native row. The native items are named uc.N as well, so
`expect: {tip: "uc.1"}` passed on native data and nothing warned. The script
looked green for as long as it existed and tested nothing.

The fixture at ~/public_html/docentFixtures/Auto-generated_hub/ now calls its
tracks rm35920Ultras and rm35920UltraZoos, and declares `visibility pack` itself,
so the `track:` step is gone -- a hub track's cart name carries the per-run
hub_<n>_ prefix, which `track:` cannot write, so that step only ever moved native
tracks. README.txt gains the rule: a fixture hub must never name a track anything
a native assembly might also call it.

With the collision gone, what the two malformed tracks do on genome-test, hgwbeta
and the RR alike, measured 2026-09-09:

rm35920Ultras     bigBed 12 + over a 4-field file -- row drawn, EMPTY. No crash,
no dialog, no garbage. #19984's auto-detection does not apply
when the declared type carries a number, so hgTracks trusts
the 12 and drops every row.
rm35920UltraZoos  bigBed 4 + over a 3-field file -- items drawn with an EMPTY
name, byte for byte what a correctly declared `type bigBed 3`
over the same file produces, measured against a probe hub.
That is the garbage string gone, and it is #31771's fix.

So the tooltip assertion cannot be restored: the hub track has no named item to
hover, on any server. The script now asserts the crash half (both rows drawn, no
jsEmbedded) and clicks an ultraZoos item by position -- `at:` rather than `item:`,
because the fixed behavior leaves those boxes nameless -- and asserts the click
reaches a real hgc detail page. Checked against a deliberately wrong expectation
so it is not passing vacuously.

refs #35920, refs #38252

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

diff --git src/hg/utils/docent/tests/regress/README.txt src/hg/utils/docent/tests/regress/README.txt
index a052c576f21..5f89124f58b 100644
--- src/hg/utils/docent/tests/regress/README.txt
+++ src/hg/utils/docent/tests/regress/README.txt
@@ -1,55 +1,63 @@
 Docent regression tests
 -----------------------
 
 One script per fixed bug, named for its ticket. Run by hand:
 
     make test               # every *.docent.yaml here
     make test T=rm36382     # just one
 
 The candidate list this directory is being built from, with the recipe and assertion
 worked out for each ticket, is at
 
     /hive/groups/browser/redmineNotes/37892/claude/2026-09-04_1100_regression_candidates.md
 
 What these are, and what they are not
 -------------------------------------
 
 Each script asserts the behavior the ticket says is correct, on genome-test. None of them
 was run against a build that still had the bug, so none has been seen to fail for the
 reason it exists. That is a deliberate choice about cost, and it puts the whole weight on
 how tight the assertion is:
 
   * name the error string the ticket quoted in `noText:`, not a generic "Error"
   * prefer `rows: [...] exact: true` and `noRows:` over a bare `rows:`
   * a test that only checks a row is PRESENT usually passes on the buggy build too,
     because the bug was an extra row, a wrong label, or a bad tooltip
 
-Two things will rot these tests
--------------------------------
+Three things will rot these tests
+---------------------------------
 
 Most recipes start from the saved session named in the ticket, because that is the
 cheapest way to reach the exact state. A session that is deleted does not fail loudly:
 hgTracks serves a page saying it could not find it, and every `noText:` check on that
 page passes. So a session-based test also asserts something that is only true when the
 session really loaded.
 
 Six recipes need a test hub on a colleague's public_html. Same problem, same remedy.
 
 Fixtures we own live in ~/public_html/docentFixtures/, and `make preflight` checks that
 every hub a script here names still answers. Copy a reporter's hub in there rather than
 loading theirs, so nothing outside this repository can change what a test measures.
 
+A fixture hub must never name a track anything the assembly might also call it. A track
+name resolves to `img_data_<name>` first and only then to a hub row's `hub_<n>_<name>`,
+so an exact native id wins: the hub row is on the page, and every `track:`, `mouseover:`
+and `rows:` in the script reads the NATIVE row instead. Nothing warns. rm35920's fixture
+called its track `ultras`, hg38 has its own `ultras`, and that script asserted a tooltip
+off the native data for as long as it existed -- it looked green and tested nothing.
+Prefix a fixture's track names with the ticket number.
+
 rm36212 is the one to read before writing another
 --------------------------------------------------
 
 It is the only script here that has been watched to fail on a build with the bug AND to
 pass on a build with the fix, which is the evidence every other script in this directory
 would like to have and does not. The recipe: build the fix into a ticket sandbox, point a
 copy of the script at that port with `target: http://127.0.0.1:PORT/cgi-bin`, and record
 in the comment which checks flipped. It costs one build and it settles what a tight
 assertion can only argue.
 
 It is also the first script to assert a COLOR, using `expect: {color: ...}`, because it
 is the first bug here that leaves the page identical -- same rows, same height, same item
 names, same tooltips. When rows:, height:, text: and has: are all blind to a bug, the
 pixels are what is left. See tests/colorchecks.docent.yaml for the check itself.