f04f1b9af06c823602c5e0ecd3b8c2059d7704d3
jcasper
  Thu Aug 27 14:42:31 2026 -0700
Faceted composites now have a max display mode setting instead of a full override
of child track visibilities, with accompanying support for the onlyVisibility setting.  We also
now include a filter block (applied to appropriate child tracks) when those settings are in place.
refs #37662

diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index f7e6b7bf466..f077aae2aa2 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -3822,31 +3822,34 @@
         }
     }
 if (countUnchecked + countVisChanged)
     {
     WARN("%s visOrig:%s visMax:%s unchecked:%d  Vis changed:%d",parent->track,
          hStringFromTv(visOrig),hStringFromTv(visMax),countUnchecked,countVisChanged);
     }
 
 return (countUnchecked + countVisChanged);
 }
 
 boolean cartTdbTreeReshapeIfNeeded(struct cart *cart,struct trackDb *tdbContainer)
 /* When subtrack vis is set via findTracks, and composite has no cart settings,
    then "shape" composite to match found */
 {
-if (!tdbIsContainer(tdbContainer))
+// Reshaping raises the container to the max of its children and drops child vis that
+// matches.  For a faceted composite the container vis is a ceiling set by the curator,
+// so raising it would silently widen it and the child vis is not ours to drop.
+if (!tdbIsContainer(tdbContainer) || tdbIsFacetedComposite(tdbContainer))
     return FALSE;  // Don't do any shaping
 
 // First look for subtrack level vis
 char setting[512];
 struct trackDb *subtrack = NULL;
 struct trackDb *tdbView  = NULL;
 struct hash *subVisHash = newHash(0);
 struct slRef *tdbRef, *tdbRefList = trackDbListGetRefsToDescendantLeaves(tdbContainer->subtracks);
 for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next)
     {
     subtrack = tdbRef->val;
     char *val=cartOptionalString(cart,subtrack->track);
     if (val && differentString(val,"hide"))  // NOTE should we include hide?
         {
         int fourState = subtrackFourStateChecked(subtrack,cart);
@@ -4024,31 +4027,33 @@
             char *viewVis = hStringFromTv(tdbVisLimitedByAncestry(newCart, tdbView, FALSE));
             if (cartRemoveOldFromTdbTree(newCart,oldVars,tdbView,NULL,viewVis,TRUE) > 0)
                 clensed++;
             }
         changedSettings = leftOvers;
         }
     }
 
 // Now deal with anything remaining at the container level
 while ((oneName = slPopHead(&changedSettings)) != NULL)
     {
     suffix = oneName->name + strlen(tdb->track) + 1;
     if (cartRemoveOldFromTdbTree(newCart,oldVars,tdb,suffix,oneName->val,TRUE) > 0)
         clensed++;
     }
-if  (containerVisChanged && !hasViews)
+// Not for faceted composites: there the container vis is only a maximum, so changing it
+// must leave the children's own display modes alone.
+if  (containerVisChanged && !hasViews && !tdbIsFacetedComposite(tdb))
     { // vis is a special additive case!
     char *vis = hStringFromTv(tdbVisLimitedByAncestry(newCart, tdb, FALSE));
     if (cartRemoveOldFromTdbTree(newCart,oldVars,tdb,NULL,vis,TRUE) > 0)
         clensed++;
     }
 
 anythingChanged = (anythingChanged || (clensed > 0));
 return anythingChanged;
 }
 
 void cgiExitTime(char *cgiName, long enteredMainTime)
 /* single stderr print out called at end of CGI binaries to record run
  * time in apache error_log */
 {
 if (sameWord("yes", cfgOptionDefault("browser.cgiTime", "yes")) )