68b9911e4c156cd1346fde5c957434b1a8780d1c
max
  Wed Sep 9 08:49:07 2026 -0700
Show the transcript's own codon number where it differs from the genomic one

The gene tracks count codons along the genome.  A RefSeq transcript is a
sequence in its own right, so where it has an insertion or a deletion relative
to the assembly, every codon 3' of that point gets a different number here than
the sequence provider gives it, one codon per three bases.  DNM1 on canFam3 is
the reported case: the transcript carries 21 bases canFam3 does not, so our
p.249 is NCBI's p.256.  Neither number is wrong, but HGVS c./p. is defined on
the transcript, so the number people quote is the one we were not showing.

The genomic number and amino acid are unchanged.  Codons whose two numbers
disagree now draw in the existing CDS_QUERY_INSERTION orange with a "!" after
the codon number, and their mouseover adds the transcript number plus a link to
a new FAQ entry.  Both directions of indel are covered, and so is the case
where the alignment does not reach the start of the CDS (801 transcripts on
hg38), which needs the transcript's own CDS annotation as the anchor rather
than the alignment.

Numbers come from the transcript alignment, ncbiRefSeqPsl or refSeqAli, which
is the same source hgvsMapToGenome already uses, so the browser now agrees with
its own position search.  Two queries per table per window, on the bin index,
and only at zoomedToCdsColorLevel, where the mouseover carrying the numbers is
drawn: on and off are within noise at every zoom.

Gated by showTxCodonNumbers in hg.conf, default off, catalogued as a release
gate.  With it off nothing is looked up and the rendering and mouseover are
byte-identical to before.

refs #38298

diff --git src/hg/hgTracks/hgTracks.h src/hg/hgTracks/hgTracks.h
index 475290643de..d9c7bc71c3e 100644
--- src/hg/hgTracks/hgTracks.h
+++ src/hg/hgTracks/hgTracks.h
@@ -372,30 +372,35 @@
     float defaultPriority; /* original priority before reordering */
     struct trackRef *trackList;  /* List of tracks. */
     boolean defaultIsClosed; /* close the track group by default. */
     char *errMessage;      /* any error messages that came up during trackDb parsing. */
     };
 
 struct simpleFeature
 /* Minimal feature - just stores position in browser coordinates. */
     {
     struct simpleFeature *next;
     int start, end;			/* Start/end in browser coordinates. */
     int qStart, qEnd;			/* query start/end; only used for alignment tracks
                                          * (PSL, BAM, chain, snake); 0 for gene models (genePred). */
     int grayIx;                         /* Level of gray usually. */
     int codonIndex;                     /* 1-based codon index (ignored if 0) */
+    int txCodonIndex;                   /* 1-based codon index counted in the transcript's own
+                                         * coordinates rather than along the genome.  Only set
+                                         * when the transcript aligns with bases this assembly
+                                         * does not have, which is what makes the two disagree;
+                                         * 0 the rest of the time, and for non-codons. */
     char codonAa;                       /* For a codon, its display amino-acid letter:
                                          * AA letter, '*' stop, 'M' start, 'X' error/partial,
                                          * 0 if not a codon.  Set when grayIx is. */
     };
 
 /* Some details of how to draw linked features. */
 enum {lfSubXeno = 1};
 enum {lfSubSample = 2};
 enum {lfWithBarbs = 3}; /* Turn on barbs to show direction based on
                          * strand field */
 enum {lfSubChain = 4};
 enum {lfNoIntronLines = 5}; /* Draw no lines between exon blocks */
 
 enum highlightMode
     {