b5a4ddd8543a87f46988a60069148b0f2e1a8031
max
  Mon Aug 10 08:37:29 2026 -0700
hgBlat/hgPcr: show the chrUn info note (fix swapped startsWith args), refs #37893

The chrUn branch of the sequence-type note used startsWith(name, "chrUn"),
but startsWith(start, string) tests whether string begins with start, so it
asked whether "chrUn" begins with the sequence name and never matched. As a
result chrUn (unplaced) sequences got no info icon on the new BLAT results
page, and no note on the classic results page or in hgPcr, while _alt/_fix/
_random (which use endsWith) worked. Fix the argument order in all three.

Also, on the new results page, check the sequence's aliases and not just its
single display name, so a hit whose displayed label is an accession but which
has a chrUn/alt/fix alias (e.g. a GenArk hub) still gets the note.

diff --git src/hg/hgBlat/hgBlat.c src/hg/hgBlat/hgBlat.c
index 5235a06b1c0..3f71514befe 100644
--- src/hg/hgBlat/hgBlat.c
+++ src/hg/hgBlat/hgBlat.c
@@ -523,35 +523,52 @@
     hgcUrl, psl->tStart, pslName, cgiEncode(faName), psl->qName,  psl->tName,
     psl->tStart, psl->tEnd, database, uiState);
 printf("details</A> ");
 }
 
 static char *chromTypeNote(char *tName)
 /* Return a short explanation for special sequence names (alt/fix/random/hap/unplaced), or NULL for a
  * normal chromosome.  tName should be the display name the user sees. */
 {
 if (endsWith(tName, "_fix"))
     return "Assembly fix patch: corrects an error in the reference assembly.";
 if (endsWith(tName, "_alt") || stringIn("_hap", tName))
     return "Alternate haplotype: an alternate sequence for this region.";
 if (endsWith(tName, "_random"))
     return "Unlocalized sequence: known chromosome, position not determined.";
-if (startsWith(tName, "chrUn"))
+if (startsWith("chrUn", tName))
     return "Unplaced sequence: chromosome of origin unknown.";
 return NULL;
 }
 
+static char *blatSeqNote(char *tName, char *displayName)
+/* The info-icon note for one hit.  chromTypeNote() only sees the single display name, but a
+ * sequence can have several aliases and the chosen display name may not be the chrUn/alt/fix one
+ * (e.g. a GenArk hub shows a GenBank accession while "chrUn_..." is only an alias).  So if the
+ * display name looks ordinary, scan the sequence's other aliases too. */
+{
+char *note = chromTypeNote(displayName);
+if (note == NULL)
+    {
+    struct slName *al;   /* chromAliasFindAliases returns a cached list - do not free it */
+    for (al = chromAliasFindAliases(tName);  al != NULL;  al = al->next)
+        if ((note = chromTypeNote(al->name)) != NULL)
+            break;
+    }
+return note;
+}
+
 static char *blatBrowserUrl(struct psl *psl, char *database, char *browserUrl,
     char *pslName, char *faName, char *customText, char *uiState, char *unhideTrack, boolean withUiState)
 /* Return a Genome Browser URL for one BLAT hit.  withUiState appends the hgsid; it is included on
  * the in-tab link but omitted from the new-tab link, matching the classic hyperlink behavior. */
 {
 struct dyString *dy = dyStringNew(256);
 dyStringPrintf(dy, "%s?position=%s:%d-%d&db=%s", browserUrl, psl->tName, psl->tStart + 1, psl->tEnd, database);
 if (customText)
     dyStringPrintf(dy, "&hgt.customText=%s", customText);
 else if (!autoBigPsl && pslName != NULL)
     dyStringPrintf(dy, "&ss=%s+%s", pslName, faName);
 if (withUiState)
     dyStringPrintf(dy, "&%s", uiState);
 dyStringPrintf(dy, "%s", unhideTrack);
 return dyStringCannibalize(&dy);
@@ -696,31 +713,31 @@
     {
     ++rank;
     double ident = 100.0 - pslCalcMilliBad(psl, TRUE) * 0.1;
     char *displayChromName = chromAliasGetDisplayChrom(database, cart, psl->tName);
     char *inTabUrl = blatBrowserUrl(psl, database, browserUrl, pslName, faName, customText,
         uiState, unhideTrack, TRUE);
     char *newTabUrl = blatBrowserUrl(psl, database, browserUrl, pslName, faName, customText,
         uiState, unhideTrack, FALSE);
 
     jsonWriteObjectStart(jw, NULL);
     jsonWriteNumber(jw, "rank", rank);
     jsonWriteString(jw, "qName", psl->qName);
     jsonWriteNumber(jw, "score", pslScore(psl));
     jsonWriteDouble(jw, "identity", ident);
     jsonWriteString(jw, "chrom", displayChromName);
-    char *note = chromTypeNote(displayChromName);   /* note must match the NAME the user sees */
+    char *note = blatSeqNote(psl->tName, displayChromName);   /* check the display name and its aliases */
     if (note != NULL)
         jsonWriteString(jw, "chromNote", note);
     jsonWriteString(jw, "strand", psl->strand);
     jsonWriteNumber(jw, "tStart", psl->tStart + 1);
     jsonWriteNumber(jw, "tEnd", psl->tEnd);
     jsonWriteNumber(jw, "span", psl->tEnd - psl->tStart);
     jsonWriteNumber(jw, "qStart", psl->qStart + 1);
     jsonWriteNumber(jw, "qEnd", psl->qEnd);
     jsonWriteNumber(jw, "qSize", psl->qSize);
     jsonWriteNumber(jw, "matches", psl->match + psl->repMatch);
     jsonWriteNumber(jw, "misMatch", psl->misMatch);
     jsonWriteNumber(jw, "gaps", psl->qNumInsert + psl->tNumInsert);
     jsonWriteNumber(jw, "blocks", psl->blockCount);
     jsonWriteString(jw, "browserUrl", inTabUrl);
     jsonWriteString(jw, "newTabUrl", newTabUrl);
@@ -1188,31 +1205,31 @@
         char *displayChromName = chromAliasGetDisplayChrom(database, cart, psl->tName);
 	printf("%s",displayChromName);
 	spaceOut(stdout, maxTChromNameSize - strlen(displayChromName));
 	printf("  %-2s  %9d %9d %6d",
 	    psl->strand, psl->tStart+1, psl->tEnd,
 	    psl->tEnd - psl->tStart);
 
         // if you modify this, also modify hgPcr.c:doQuery, which implements a similar feature
         char *seq = psl->tName;
         if (endsWith(seq, "_fix"))
             printf("   <A target=_blank HREF=\"../FAQ/FAQdownloads.html#downloadFix\">What is chrom_fix?</A>");
         else if (endsWith(seq, "_alt"))
             printf("   <A target=_blank HREF=\"../FAQ/FAQdownloads.html#downloadAlt\">What is chrom_alt?</A>");
         else if (endsWith(seq, "_random"))
             printf("   <A target=_blank HREF=\"../FAQ/FAQdownloads.html#download10\">What is chrom_random?</A>");
-        else if (startsWith(seq, "chrUn"))
+        else if (startsWith("chrUn", seq))
             printf("   <A target=_blank HREF=\"../FAQ/FAQdownloads.html#download11\">What is a chrUn sequence?</A>");
         printf("\n");
 	}
     printf("</PRE>\n");
         webNewSection("Help");
         puts("<P style=\"text-align:left\"><A target=_blank HREF=\"../FAQ/FAQblat.html#blat1b\">Missing a match?</A><br>");
         puts("<A target=_blank HREF=\"../FAQ/FAQblat.html#blat1c\">What is chr_alt & chr_fix?</A></P>\n");
         puts("</DIV>\n");
         }
     }
 pslFreeList(&pslList);
 
 }
 
 void trimUniq(bioSeq *seqList)