92ed679e589bc5f2f4bcc78dd89584e67e496cfc
angie
  Fri Aug 28 08:20:24 2026 -0700
Support representativeBacktrack for exclusions too.
It occurs to me that if a representative is used in multiple places and has representativeBacktrack in any of them, the one that the script finds first will be applied to all.  Pressed for time and not yet sure what to do about that.  Probably should at least detect & warn.

diff --git src/hg/utils/otto/sarscov2phylo/branchSpecificMask.py src/hg/utils/otto/sarscov2phylo/branchSpecificMask.py
index 1ba9c5800e1..2a6be2dad78 100755
--- src/hg/utils/otto/sarscov2phylo/branchSpecificMask.py
+++ src/hg/utils/otto/sarscov2phylo/branchSpecificMask.py
@@ -53,38 +53,46 @@
             for r in ranges:
                 try:
                     range(r[0], r[1]+1)
                 except TypeError as e:
                     die(f'Unexpected non-list value "{r}" in ranges for {branch} in {yamlIn}')
     return spec
 
 def run(cmd):
     """Run a command and exit with error output if it fails"""
     try:
         subprocess.run(cmd).check_returncode()
     except subprocess.CalledProcessError as e:
         die(e)
 
 def getBacktrack(spec, rep):
+    #*** Note: if a representative is used multiple times, the first representativeBacktrack that we come across for it
+    #*** will be applied to all.
     """If spec for branch whose representative is rep has representativeBacktrack, return that
     value, otherwise return 0."""
     for branch in spec:
         branchSpec = spec[branch]
         if branchSpec['representative'] == rep:
             backtrack = branchSpec.get('representativeBacktrack')
             if backtrack is not None:
                 return backtrack
+        exclusions = spec[branch].get('exclusions', [])
+        for ex in exclusions:
+            if ex['representative'] == rep:
+                backtrack = ex.get('representativeBacktrack')
+                if backtrack is not None:
+                    return backtrack
     return 0
 
 def getRepresentativeNodes(pbIn, spec):
     """Run matUtils extract --sample-paths on pbIn and find path to each branch's representative.
     Return dict mapping representative name to final node in path."""
     repNodes = {}
     for branch in spec:
         rep = spec[branch]['representative']
         repNodes[rep] = ''
         exclusions = spec[branch].get('exclusions', [])
         for ex in exclusions:
             rep = ex['representative']
             repNodes[rep] = ''
     samplePaths = tempfile.NamedTemporaryFile(delete=False)
     samplePaths.close()