77f91b38ab166f2adfefbdff3c2cbd50c2591cd0
hiram
  Mon Jun 8 15:21:14 2026 -0700
correct status labels to differeniate liftOver vs. assembly status refs #31811

diff --git src/hg/utils/otto/userRequests/ottoRequestView.cgi src/hg/utils/otto/userRequests/ottoRequestView.cgi
index 3495e163221..62467287688 100644
--- src/hg/utils/otto/userRequests/ottoRequestView.cgi
+++ src/hg/utils/otto/userRequests/ottoRequestView.cgi
@@ -43,38 +43,37 @@
     1: 'acknowledged, email sent',
     2: 'galaxy job started',
     3: 'galaxy done, download started',
     4: 'downloaded, track files made',
     5: 'symlinks ready, awaiting push',
     6: 'push complete',
     7: 'ERROR',
     8: 'COMPLETE (final email sent)',
 }
 
 asmStatus = {
     0: 'received by API',
     1: 'acknowledged, email sent',
     2: 'assembly build started',
     3: 'assembly build done',
-    4: 'downloaded, track files made',
-    5: 'symlinks ready, awaiting push',
-    6: 'push complete',
+    4: 'assembly available on hgwdev',
+    5: 'assembly available on hgwbeta',
+    6: 'assembly available on hgw2 - done',
     7: 'ERROR',
     8: 'COMPLETE (final email sent)',
 }
 
-
 COLS = ['id', 'requestType', 'fromDb', 'toDb', 'email', 'comment',
         'requestTime', 'status', 'buildDir', 'completeTime']
 
 # featureBits coverage lookup roots
 HIVE_GENOMES = '/hive/data/genomes'
 ASMHUB_ROOT  = HIVE_GENOMES + '/asmHubs'
 
 # in-process caches; one CGI invocation only, but rows reuse same accessions
 _buildDirCache = {}
 _fbPctCache    = {}
 _genarkAsmName = {}    # populated up-front by loadGenarkNames()
 _fbSnapshot    = {}    # populated up-front by loadFeatureBitsSnapshot()
 
 
 def forbidden(msg):
@@ -103,30 +102,35 @@
     out, i, n = [], 0, len(s)
     while i < n:
         if s[i] == '\\' and i + 1 < n:
             c = s[i+1]
             if   c == 'n':  out.append('\n')
             elif c == 't':  out.append('\t')
             elif c == '\\': out.append('\\')
             elif c == '0':  out.append('\0')
             else:           out.append(s[i:i+2])
             i += 2
         else:
             out.append(s[i]); i += 1
     return ''.join(out)
 
 
+def getStatusDict(requestType):
+    """Return appropriate status dictionary based on request type."""
+    return asmStatus if requestType == 'assembly' else liftStatus
+
+
 def hgsqlRun(sql):
     """Run sql via hgsql against DB. Returns (ok, stdout, stderr).
     Running under Apache the process has no ~/.hg.conf, so point hgsql
     at the cgi-bin hg.conf via HGDB_CONF."""
     env = dict(os.environ)
     env['HGDB_CONF'] = HGDB_CONF
     env['HOME'] = TRASH
     cmd = ['/cluster/bin/x86_64/hgsql']
     if USE_PROFILE:
         cmd.append('-profile=central')
     cmd.extend([DB, '-N', '-B', '-e', sql])
     r = subprocess.run(cmd, capture_output=True, text=True, env=env)
     return (r.returncode == 0, r.stdout, r.stderr)
 
 
@@ -343,32 +347,37 @@
         out('<div class="legend">Galaxy queue: '
             f'<b>{galaxyStatus.get("running", "?")}</b> running &middot; '
             f'<b>{galaxyStatus.get("queued",  "?")}</b> queued &middot; '
             f'<b>{galaxyStatus.get("new",     "?")}</b> new '
             f'<small>(as of {html.escape(galaxyStatus.get("ts", ""))})</small>'
             f'{staleNote}</div>\n')
     else:
         out('<div class="legend">Galaxy queue: '
             '<i>status unavailable</i></div>\n')
     if info:
         out(f'<div class="banner info">{html.escape(info)}</div>\n')
     if error:
         out(f'<div class="banner error">{html.escape(error)}</div>\n')
 
     out('<div class="legend">status: ')
+    # Show both status types
+    out('<strong>liftOver:</strong> ')
     out(' &middot; '.join(f'<code>{k}</code>={html.escape(v)}'
                           for k, v in liftStatus.items()))
+    out('<br><strong>assembly:</strong> ')
+    out(' &middot; '.join(f'<code>{k}</code>={html.escape(v)}'
+                          for k, v in asmStatus.items()))
     # Count rows by type for toggle button labels
     completed_count = sum(1 for r in rows if len(r) > 7 and r[7] == '8')
     assembly_count = sum(1 for r in rows if len(r) > 1 and r[1] == 'assembly')
     liftover_count = sum(1 for r in rows if len(r) > 1 and r[1] == 'liftOver')
     # Config toggle button - switches between test and production databases
     current_config = 'otto' if use_otto else 'test'
     switch_config = 'test' if use_otto else 'otto'
     switch_label = 'Switch to hgwdev' if use_otto else 'Switch to RR'
     config_url = f'?config={switch_config}'
 
     out(f' &middot; <b>{len(rows)}</b> row(s)'
         f'<a href="{config_url}" class="configBtn">{switch_label}</a>'
         '<button class="refreshBtn" type="button" '
         'onclick="location.reload()">refresh</button>'
         f'<button class="toggleBtn" type="button" id="toggleComplete" '
@@ -402,31 +411,33 @@
         cls_parts = []
         if stnum in (7, 8):
             cls_parts.append(f's{stnum}')
         # Add requestType class for toggle filtering
         if typeIdx < len(r):
             req_type = r[typeIdx].lower()
             if req_type in ('assembly', 'liftover'):
                 cls_parts.append(req_type)
         cls = ' '.join(cls_parts)
         out(f'<tr class="{cls}">')
         for i, c in enumerate(COLS):
             cell = r[i] if i < len(r) else ''
             if c == 'comment':
                 out(f'<td class="comment">{html.escape(cell)}</td>')
             elif c == 'status':
-                label = liftStatus.get(stnum, '?')
+                reqType = r[typeIdx] if typeIdx < len(r) else 'liftOver'
+                statusDict = getStatusDict(reqType)
+                label = statusDict.get(stnum, '?')
                 out(f'<td><b>{html.escape(cell)}</b> '
                     f'<small>{html.escape(label)}</small></td>')
             elif c in ('fromDb', 'toDb') and cell:
                 href = ('https://genome-test.gi.ucsc.edu/cgi-bin/hgTracks?db='
                         + urllib.parse.quote(cell, safe=''))
                 out(f'<td><a href="{html.escape(href)}" target="_blank">'
                     f'{html.escape(cell)}</a></td>')
             elif c == 'email' and '@' in cell:
                 user = cell.split('@', 1)[0]
                 out(f'<td title="{html.escape(cell)}">'
                     f'{html.escape(user)}</td>')
             else:
                 out(f'<td>{html.escape(cell)}</td>')
         fromAcc = r[fromIdx] if fromIdx < len(r) else ''
         toAcc   = r[toIdx]   if toIdx   < len(r) else ''
@@ -436,31 +447,33 @@
             out(f'<td>{html.escape(fwd or "-")} / '
                 f'{html.escape(rev or "-")}</td>')
         else:
             out('<td></td>')
 
         elapsed = elapsedStr(r[reqIdx]  if reqIdx  < len(r) else '',
                              r[doneIdx] if doneIdx < len(r) else '')
         out(f'<td>{html.escape(elapsed)}</td>')
         # reset form
         out('<td><form method="post" '
             'onsubmit="return confirm(\'Reset status of id=' +
             html.escape(rid) + ' to \' + this.status.value + \'?\')">'
             '<input type="hidden" name="action" value="resetStatus">'
             f'<input type="hidden" name="id" value="{html.escape(rid)}">'
             '<select name="status">')
-        for k in sorted(liftStatus):
+        reqType = r[typeIdx] if typeIdx < len(r) else 'liftOver'
+        statusDict = getStatusDict(reqType)
+        for k in sorted(statusDict):
             sel = ' selected' if k == stnum else ''
             out(f'<option value="{k}"{sel}>{k}</option>')
         out('</select> <button type="submit">set</button></form></td>')
         out('</tr>\n')
     out('</table>\n')
     out('<script src="/js/sorttable.js"></script>\n')
     out('<script>\n'
         'function toggleCompleted() {\n'
         '    var table = document.querySelector("table");\n'
         '    var btn = document.getElementById("toggleComplete");\n'
         '    var isHidden = table.classList.contains("hide-complete");\n'
         '    if (isHidden) {\n'
         '        table.classList.remove("hide-complete");\n'
         f'        btn.textContent = "hide completed ({completed_count})";\n'
         '        localStorage.setItem("hideCompleted", "false");\n'