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/cds.h src/hg/hgTracks/cds.h
index a545e88067d..c88971bd587 100644
--- src/hg/hgTracks/cds.h
+++ src/hg/hgTracks/cds.h
@@ -97,34 +97,52 @@
 #define CDS_RIBO_SLIP2_B  255
 
 #define CDS_NUM_COLORS 15
 
 extern struct cacheTwoBitRanges *cdsQueryCache;  /* Cache of querie sequences in alignments */
 
 Color getCdsColor(int index);
 /* return color from index of types of colors */
 
 enum baseColorDrawOpt baseColorGetDrawOpt(struct track *tg);
 /* Determine what base/codon coloring option (if any) has been selected 
  * in trackDb/cart, and gate with zoom level. */
 
 
 struct simpleFeature *baseColorCodonsFromGenePred(struct linkedFeatures *lf,
-        struct genePred *gp, boolean colorStopStart, boolean codonNumbering);
+        struct genePred *gp, boolean colorStopStart, boolean codonNumbering,
+        struct psl *txAli, struct genbankCds *txCds);
 /* Given an lf and the genePred from which the lf was constructed,
  * return a list of simpleFeature elements, one per codon (or partial
- * codon if the codon falls on a gap boundary. */
+ * codon if the codon falls on a gap boundary.
+ * txAli and txCds are the transcript's own alignment and its CDS in transcript
+ * coordinates, from baseColorTxAliForGenePred; together they give each codon a second
+ * number counted the way the transcript counts.  Pass NULL for txAli when there is none,
+ * and codons are numbered only along the genome, as they always have been. */
+
+struct psl *baseColorTxAliForGenePred(struct track *tg, struct genePred *gp,
+        struct genbankCds *retCds);
+/* Return the alignment that gives gp's transcript coordinates of its own, and fill in
+ * retCds with the transcript's CDS in those coordinates, so that codons can be numbered
+ * the way the transcript numbers them as well as the way they fall on the genome.  NULL
+ * when this assembly has no such alignment or no CDS for gp, and codons are then numbered
+ * only along the genome, as they always have been. */
+
+boolean baseColorCodonIsShifted(struct simpleFeature *sf);
+/* Does this codon's number along the genome disagree with its number in the transcript?
+ * True where an indel in the transcript relative to the genome comes between the CDS
+ * start and this codon, in either direction. */
 
 struct simpleFeature *baseColorCodonsFromPsl(struct linkedFeatures *lf, 
         struct psl *psl, int sizeMul, boolean isXeno, int maxShade,
         enum baseColorDrawOpt drawOpt, struct track *tg);
 /* Given an lf and the psl from which the lf was constructed, 
  * return a list of simpleFeature elements, one per codon (or partial 
  * codon if the codon falls on a gap boundary.  sizeMul, isXeno and maxShade
  * are for defaulting to one-simpleFeature-per-exon if cds is not found. */
 
 
 INLINE boolean baseColorCanDraw(struct track *tg)
 /* baseColor uses tg->drawItems as a proxy for type of tg->items, which must be 
  * linkedFeatures or linkedFeaturesSeries.  Return TRUE if tg->drawItems
  * implies that tg->items is linkedFeatures or linkedFeaturesSeries, and from
  * a subtype supported by the baseColor code. */