2070aedea88da26aee0af3e2fd867b67140b09b5
lrnassar
  Wed Aug 5 16:59:19 2026 -0700
Move the maf sequence-name splitter into jkweb so both summary tools share one copy. refs #37928

mafSplitSrcGetChrom existed as two independent copies, in hgLoadMafSummary.c and
mafToBigMafSummary.c, and they had diverged: only the first had the GenArk accession
rule added by 2db6bab8db0. It now lives in src/lib/maf.c, with the rules documented
in maf.h.

mafToBigMafSummary therefore picks up the GenArk rule it was missing, so a dotted
GenArk name like GCA_009914755.4.CM034974.1 now keeps its accession version instead of
dropping it, which matches what hprc90waySummary already holds.

Also removes mafCompGetSrcDb and mafCompGetSrcName from maf.c and maf.h. Both were
first-dot splitters with no callers anywhere in the tree.

diff --git src/inc/maf.h src/inc/maf.h
index 095a514c85e..33d2c6e5912 100644
--- src/inc/maf.h
+++ src/inc/maf.h
@@ -66,35 +66,59 @@
     int size;	 /* Size in sequence (does not include dashes).  */
     char *text;  /* The sequence including dashes. */
     char *quality;  /* The quality data (same length as text, or NULL). */
     char leftStatus; /* the syntenic status of the alignment before us vis a vis ourselves */
     int leftLen;     /* length related information for the previous alignment for the species */
     char rightStatus; /* the syntenic status of the alignment after us vis a vis ourselves */
     int rightLen;     /* length related information for the following alignment for the species */
     };
 
 void mafCompFree(struct mafComp **pObj);
 /* Free up a maf component. */
 
 void mafCompFreeList(struct mafComp **pList);
 /* Free up a list of maf components. */
 
-char *mafCompGetSrcDb(struct mafComp *mc, char *buf, int bufSize);
-/* parse the srcDb name from the mafComp src name, return NULL if no srcDb */
-
-char *mafCompGetSrcName(struct mafComp *mc);
-/* parse the src sequence name from the mafComp src name */
+char *mafSplitSrcGetChrom(char *src, char *database);
+/* src is one of: chrom, db|chrom, or db.chrom.  Return a pointer to the chrom part and
+ * truncate src in place so it holds only the db.  See mafSrcDb for the simpler
+ * non-destructive first-dot-only version used by the track display code.
+ *
+ * The hard part is that BOTH db and chrom may themselves contain dots, so the db/chrom
+ * split is not simply "the first dot" or "the middle dot".  We resolve it like this,
+ * in order:
+ *   1. A pipe '|' is always an explicit, unambiguous separator -- use it if present.
+ *   2. No dot at all -> the whole string is the chrom, and src is left untouched, so a
+ *      caller that wants the db gets the whole string too.
+ *   3. If the caller passed the reference 'database' and src begins with "<database>.",
+ *      split right there.  This nails the master component whether or not database itself
+ *      contains a dot (e.g. a GenArk db like GCF_000001405.40).  The match must end at a
+ *      dot, so "hg38" does not claim "hg38Patch11.chr1".  'database' is trusted as
+ *      given: it wins over the GCA_/GCF_ rule below.
+ *   4. A GenArk accession db (GCA_/GCF_) is the only db that legitimately carries an
+ *      internal dot -- its accession.version adds exactly one -- so its db ends at the
+ *      SECOND dot and the chrom follows.  A GCA_/GCF_ name with no second dot has no
+ *      chrom to hand back, so it falls through to step 5 ("GCA_123.1" -> db "GCA_123",
+ *      chrom "1").
+ *   5. Every other db (hg38, mm10, a species name, ...) has no dot, so split at the FIRST
+ *      dot; anything after it (including further dots, e.g. an accession.version chrom) is
+ *      the chrom.
+ *
+ * There is no universal way to resolve an ambiguous multi-dot name from the dots alone: if
+ * the db part is itself a dotted accession that is not a GenArk GCA_/GCF_ id (e.g. a bare
+ * INSDC accession used as the assembly), step 5 may split it in the wrong place.  For those,
+ * use the pipe form db|chrom, which is always unambiguous. */
 
 struct mafRegDef
 /* MAF region definition (r line) */
 {
     char *type;   // type of definition, one of constants below (not malloced)
     int size;     // region size
     char *id;     // identifiers
 };
 extern char *mafRegDefTxUpstream;  // transcription start size upstream region
 
 struct mafRegDef *mafRegDefNew(char *type, int size, char *id);
 /* construct a new mafRegDef object */
 
 void mafRegDefFree(struct mafRegDef **mrdPtr);
 /* Free a mafRegDef object */