bb8470a90643b057df7bbf5d0140a5b2bbf9dddd
braney
  Fri Jun 12 08:44:37 2026 -0700
quickLift: load genePreds by column name, not a fixed 15-col loader

Lifting a genePred track to another assembly used genePredExtLoad15, a
positional loader that assumes the extended genePred columns. Classic
knownGene-format tables instead carry proteinID and alignID after the ten
core columns, so the loader read proteinID as the integer score field and
aborted with "invalid signed integer" (e.g. "O54946", or "" when empty).
This showed up when lifting from an assembly whose knownGene is the legacy
format, such as mm10 to mm39 or rheMac10.

Add quickLiftGenePreds(), which loads through genePredReader so the actual
set of columns in the table is honored by name (proteinID maps to name2,
score defaults), matching how the tracks load when not lifted. The three
call sites that hardcoded genePredExtLoad15 (hgTracks gene loading and two
hgc detail handlers) now use it. The chain-walking shared with quickLiftSql
is factored into quickLiftLoadChains() and quickLiftChainQueryRange().

refs #37535

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

diff --git src/hg/inc/quickLift.h src/hg/inc/quickLift.h
index 4c992fa3081..bf3885d511d 100644
--- src/hg/inc/quickLift.h
+++ src/hg/inc/quickLift.h
@@ -1,97 +1,102 @@
 /* quickLift genome annotations on the fly between assemblies using chain files */
 
 /* Copyright (C) 2023 The Regents of the University of California 
  * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
 
 #ifndef QUICKLIFT_H      
 #define QUICKLIFT_H      
 
 #define quickLiftCartName     "hubQuickLift"
 
 #define quickLiftChainTableConfVariable      "quickLiftChainName"
 #define defaultQuickLiftChainTableName       "quickLiftChain"
 
 struct quickLiftRegions
 // store highlight information
 {
 struct quickLiftRegions *next;
 unsigned type;
 char *chrom;
 long chromStart;
 long chromEnd;
 char *bases;
 unsigned baseCount;
 char *oChrom;
 long oChromStart;
 long oChromEnd;
 char *otherBases;
 unsigned otherBaseCount;
 char * id;
 };
 
 #define QUICKTYPE_INSERT     0
 #define QUICKTYPE_DEL      1
 #define QUICKTYPE_DOUBLE     2
 #define QUICKTYPE_MISMATCH     3
 
 extern char *quickTypeStrings[];
 
 typedef struct slList *(*ItemLoader2)(char **row, int numFields);
 /* Load a bed file from an SQL query result. */
 
 struct bigBedInterval *quickLiftGetIntervals(char *instaPortFile, struct bbiFile *bbi,   char *chrom, int start, int end, struct hash **pChainHash);
 /* Return intervals from "other" species that will map to the current window.
  * These intervals are NOT YET MAPPED to the current assembly.
  */
 
 struct bed *quickLiftIntervalsToBed(struct bbiFile *bbi, struct hash *chainHash, struct bigBedInterval *bb);
 /* Using chains stored in chainHash, port a bigBedInterval from another assembly to a bed
  * on the reference.
  */
 
 struct slList *quickLiftSql(struct sqlConnection *conn, char *quickLiftFile, char *table, char *chromName, int winStart, int winEnd,  char *query, char *extraWhere, ItemLoader2 loader, int numFields, struct hash *chainHash);
 /* Load a list of items (usually beds) from another database in a region that corresponds to chromName:winStart-winEnd in the reference database.
  * Fill a hash with the chains that were used to map the desired range.  These chains will be used to map the query side items back to the reference. */
 
+struct genePred *quickLiftGenePreds(struct sqlConnection *conn, char *quickLiftFile, char *table, char *chromName, int winStart, int winEnd, char *extraWhere, struct hash *chainHash);
+/* Like quickLiftSql, but load genePreds through a genePredReader so the actual set of
+ * (extended) genePred columns in the table is honored rather than assuming 15 columns.
+ * Fill a hash with the chains that were used to map the desired range. */
+
 unsigned quickLiftGetChainId(struct cart *, char *fromDb, char *toDb);
 /* Return the id from the quickLiftChain table for given assemblies. */
 
 char *quickLiftGetChainPath(struct cart *, char *fromDb, char *toDb);
 /* Return the path from the quickLiftChain table for given assemblies. */
 
 struct bed *quickLiftBeds(struct bed *bedList, struct hash *chainHash, boolean blocked);
 // Map a list of bedd in query coordinates to our current reference
 
 boolean quickLiftEnabled(struct cart *cart);
 /* Return TRUE if feature is available */
 
 struct quickLiftRegions *quickLiftGetRegions(char *ourDb, char *liftDb, char *quickLiftFile, char *chrom, int seqStart, int seqEnd);
 /* Figure out the highlight regions and cache them. */
 
 char *quickLiftChainTable();
 /* Return the name of the quickLiftChain table. */
 
 void quickLiftResolveTable(struct trackDb *tdb, char *trackTable, char **retTable, char **retLiftDb);
 /* Resolve the table name and liftDb for a quickLift track.  For custom tracks,
  * sets *retLiftDb to CUSTOM_TRASH and *retTable to the dbTableName setting;
  * otherwise sets *retTable to trackTable. Caller should have already set
  * *retLiftDb to trackDbSetting(tdb, "quickLiftDb"). */
 
 struct bed *quickLiftSqlLoadBeds(struct trackDb *tdb, char *trackTable, char *liftDb,
     char *chrom, int start, int end, char *extraWhere,
     ItemLoader2 loader, int numFields, boolean blocked);
 /* Load items from another assembly via quickLift SQL, map them back to the reference,
  * and return the lifted beds.  Handles custom track table resolution internally.
  * Caller provides liftDb from trackDbSetting(tdb, "quickLiftDb"). */
 
 boolean quickLiftLiftPos(char *sourceDb, char *destDb,
     char *chrom, int start, int end,
     char **retChrom, int *retStart, int *retEnd);
 /* Map a position from source (sourceDb) coords to destination (destDb) coords
  * using the liftOver chain for sourceDb -> destDb.  Used to remap hgFind
  * results from quickLifted bigBed tracks back to the destination assembly. */
 
 boolean quickLiftHubRemoveTrack(struct cart *cart, char *sourceDb, char *trackName);
 /* Remove a track stanza from the quickLift hub file for sourceDb.  Returns
  * TRUE if a stanza matching trackName was found and removed. */
 #endif