0cfb3c37fdb1de8873336f9d6f95b3422a465964
hiram
  Sun Aug 9 10:45:26 2026 -0700
in the case of an equivalent available browser for a user browser build request, alert the user to the existence of the equivalent refs #31811

diff --git src/hg/utils/otto/userRequests/ottoRequest.py src/hg/utils/otto/userRequests/ottoRequest.py
index 80171c95fdb..789ba169c1a 100755
--- src/hg/utils/otto/userRequests/ottoRequest.py
+++ src/hg/utils/otto/userRequests/ottoRequest.py
@@ -168,30 +168,43 @@
 
     m2 = re.match(r"; betterName: '([^']*)'(.*)$", rest, re.DOTALL)
     if m2:
         betterName = m2.group(1)
         rest = m2.group(2)
 
     m3 = re.match(r"; comment: '(.*)'\s*$", rest, re.DOTALL)
     if m3:
         userComment = m3.group(1)
     else:
         userComment = rest.lstrip('; ')
 
     return name, betterName, userComment
 
 
+def browserUrl(db):
+    """Return the hgTracks URL for a browser db -- a GenArk hub accession
+    (GC[AF]_...) needs the mirrored hub.txt gbdb path, a UCSC native db
+    just needs db=.  Mirrors asmRequestWatch.sh phase 6's URL
+    construction (accessionToPath() + hubTxt)."""
+    m = re.match(r'^(GC[AF])_(\d{3})(\d{3})(\d{3})', db)
+    if m:
+        gcX, d0, d1, d2 = m.groups()
+        gbDbPath = f"/gbdb/genark/{gcX}/{d0}/{d1}/{d2}/{db}/hub.txt"
+        return f"https://genome.ucsc.edu/cgi-bin/hgTracks?genome={db}&hubUrl={gbDbPath}"
+    return f"https://genome.ucsc.edu/cgi-bin/hgTracks?db={db}"
+
+
 def sendMail(toAddr, subject, body, fromAddr=None, bccAddr=None, bounceAddr=None):
     """Send email via /usr/sbin/sendmail.
     If fromAddr is provided it is used as the envelope sender (-f)
     and the From: header so that bounces return to that address.
     If bccAddr is provided, sendmail -t reads it from the header,
     delivers a copy, and strips the Bcc: line before transmission."""
     headers = f"To: {toAddr}\nSubject: {subject}"
     if bccAddr:
         headers = f"Bcc: {bccAddr}\n{headers}"
     if fromAddr:
         headers = (f"From: {fromAddr}\n"
                    f"Reply-To: {fromAddr}\n"
                    f"Return-Path: {fromAddr}\n"
                    f"{headers}")
     message = f"{headers}\n\n{body}\n"
@@ -240,33 +253,63 @@
     for req in pending:
         reqType = req['requestType']
         bccAddr = BCC_BY_TYPE.get(reqType)
         if not bccAddr:
             print(f"Warning: unknown requestType '{reqType}' for"
                   f" request #{req['id']}, skipping",
                   file=sys.stderr)
             continue
 
         userEmail = req.get('email', '')
         if not userEmail:
             print(f"Warning: no user email for request #{req['id']},"
                   f" skipping", file=sys.stderr)
             continue
 
+        # findGenome.c:apiAssemblyRequest() sets toDb != fromDb when
+        # asmAlias already maps the requested asmId to a browser we have
+        # -- no build is needed, so send the "already available"
+        # acknowledgement here and close out the row now instead of
+        # handing it to asmRequestWatch.sh, which would otherwise wait
+        # forever for a build that will never happen.
+        alreadyExists = (reqType == 'assembly' and req['toDb']
+                          and req['toDb'] != req['fromDb'])
+
         subject = (f"UCSC Genome Browser: your {reqType}"
                    f" request has been received")
-        if reqType == 'assembly':
+        if alreadyExists:
+            subject = "UCSC Genome Browser: your assembly request is already available"
+            name, betterName, userComment = parseAssemblyComment(req['comment'])
+            body = (
+                f"Good news -- the assembly you requested already has an\n"
+                f"equivalent browser available, so no new build is needed.\n"
+                f"\n"
+                f"name: '{name}'\n"
+                f"email: '{userEmail}'\n"
+                f"requested asmId: '{req['fromDb']}'\n"
+                f"existing browser: '{req['toDb']}'\n"
+                f"comment: '{userComment.rstrip()}'\n"
+                f"date: '{req['requestTime']}'\n"
+                f"\n"
+                f"View it here:\n"
+                f"  {browserUrl(req['toDb'])}\n"
+                f"\n"
+                f"If this is insufficient for your research purpose, please let us know in response to this email.\n"
+                f"\n"
+                f"-- UCSC Genome Browser\n"
+            )
+        elif reqType == 'assembly':
             name, betterName, userComment = parseAssemblyComment(req['comment'])
             body = (
                 f"Your assembly request has been received and is being\n"
                 f"processed.\n"
                 f"\n"
                 f"name: '{name}'\n"
                 f"email: '{userEmail}'\n"
                 f"asmId: '{req['fromDb']}'\n"
                 f"betterName: '{betterName}'\n"
                 f"comment: '{userComment.rstrip()}'\n"
                 f"date: '{req['requestTime']}'\n"
                 f"\n"
                 f"Will advise when this assembly is available in the genome browser.\n"
                 f"\n"
                 f"-- UCSC Genome Browser\n"
@@ -277,24 +320,30 @@
                 f"processed.\n"
                 f"\n"
                 f"Request details:\n"
                 f"  From:      {req['fromDb']}\n"
                 f"  To:        {req['toDb']}\n"
                 f"  Comment:   {req['comment'].rstrip()}\n"
                 f"  Submitted: {req['requestTime']}\n"
                 f"\n"
                 f"Will advise when this alignment is available in the genome browser.\n"
                 f"\n"
                 f"-- UCSC Genome Browser\n"
             )
         bitParts = ["gb", "aut", "o", "@", "uc", "sc.", "ed", "u"]
         if sendMail(userEmail, subject, body,
            fromAddr=NOTIFY_FROM, bccAddr=bccAddr, bounceAddr="".join(bitParts)):
+            if alreadyExists:
+                # resolved by asmAlias -- no build, close the row out now
+                hgsqlUpdate(dbHost, ottoDb,
+                    f"UPDATE {ottoTable} SET status = 8, completeTime = NOW()"
+                    f" WHERE id = {req['id']}")
+            else:
                 hgsqlUpdate(dbHost, ottoDb, f"UPDATE {ottoTable} SET status = 1"
                     f" WHERE id = {req['id']}")
         else:
             print(f"Failed to send notification for request #{req['id']}",
                   file=sys.stderr)
 
 
 if __name__ == '__main__':
     main()