Skip to content

Commit 6e88448

Browse files
committed
experiments: badge and hide culled promotions on the promoted-vs-original cards; hide aborted by default
A promoted track can be culled by a LATER promotion in the same market while its experiment row stays 'promoted', so the comparison section was charting disabled tracks as mysteriously silent live ones (7 such cards today). The section now cross-references the tracks endpoint: culled promotions are hidden by default behind a 'show culled (N)' toggle, badged 'culled' when shown, and their SigNoz traffic queries are skipped while hidden. A disabled ORIGINAL track gets its own muted badge. Also hide 'aborted' experiments in the lifecycle list by default, like 'retired' — together they are the bulk of terminal history.
1 parent c631b3e commit 6e88448

1 file changed

Lines changed: 88 additions & 10 deletions

File tree

src/components/ExperimentsOverview.tsx

Lines changed: 88 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
abortExperiment,
1717
buildExperimentTrackQuery,
1818
fetchSigNozMetrics,
19+
fetchTracks,
1920
retireExperiment,
2021
type ExperimentDetail,
2122
type ExperimentStratum,
@@ -678,17 +679,28 @@ function avgGoodputByTrack(
678679
return out;
679680
}
680681

682+
// deadBadge marks a track that is disabled in the tracks table — most commonly
683+
// culled by a later promotion in the same market — so a flat/absent line reads
684+
// as "torn down", never as a mysteriously silent live track.
685+
const deadBadge: CSSProperties = {
686+
...mono, fontSize: "0.5rem", textTransform: "uppercase", letterSpacing: "0.05em",
687+
padding: "0.05rem 0.35rem", borderRadius: "3px",
688+
color: "#ff4060", background: "#ff40601a", border: "1px solid #ff406040",
689+
};
690+
681691
// PromotionTrafficCard is one promotion's traffic chart: the promoted track's
682692
// line vs the original (control), both scoped to the experiment's target market,
683693
// over the shared window. A vertical marker at the promotion time (when it falls
684694
// in-window) shows the hand-off. If the promotion is working the promoted line
685695
// climbs while the control's share of this market falls.
686-
function PromotionTrafficCard({ point, seriesByTrackCountry, startMs, endMs, logScale }: {
696+
function PromotionTrafficCard({ point, seriesByTrackCountry, startMs, endMs, logScale, promotedDisabled, originalDisabled }: {
687697
point: PromotedComparisonPoint;
688698
seriesByTrackCountry: Map<string, Array<{ ts: number; value: number }>>;
689699
startMs: number;
690700
endMs: number;
691701
logScale: boolean;
702+
promotedDisabled: boolean;
703+
originalDisabled: boolean;
692704
}) {
693705
const rows = useMemo(
694706
() => mergeTrafficRows(
@@ -704,8 +716,14 @@ function PromotionTrafficCard({ point, seriesByTrackCountry, startMs, endMs, log
704716

705717
return (
706718
<div style={{ border: "1px solid #ffffff0d", borderRadius: "var(--radius-sm)", padding: "0.6rem 0.7rem" }}>
707-
<div style={{ ...mono, fontSize: "0.58rem", color: "var(--text-muted)", marginBottom: "0.15rem" }}>
708-
#{point.experimentId} · {point.targetCountry} · {point.protocolName || "—"}{point.providerName ? ` · ${point.providerName}` : ""}
719+
<div style={{ ...mono, fontSize: "0.58rem", color: "var(--text-muted)", marginBottom: "0.15rem", display: "flex", alignItems: "center", gap: "0.4rem" }}>
720+
<span>#{point.experimentId} · {point.targetCountry} · {point.protocolName || "—"}{point.providerName ? ` · ${point.providerName}` : ""}</span>
721+
{promotedDisabled && (
722+
<span style={deadBadge} title="The promoted track is disabled — most commonly culled by a later promotion in this market — so it carries no traffic. The experiment row still reads 'promoted'.">culled</span>
723+
)}
724+
{originalDisabled && (
725+
<span style={{ ...deadBadge, color: "#8890a0", background: "#8890a01a", border: "1px solid #8890a040" }} title="The original (control) track is disabled; only the promoted line carries meaning in this window.">original disabled</span>
726+
)}
709727
</div>
710728
<div style={{ ...mono, fontSize: "0.62rem", marginBottom: "0.35rem", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
711729
<span style={{ color: CHALLENGER_COLOR }}>{point.promotedTrackName}</span>
@@ -755,6 +773,31 @@ function PromotedTraffic({ enabled }: { enabled: boolean }) {
755773
const [provider, setProvider] = useState("");
756774
const { data, isLoading, error } = usePromotedComparison(enabled, hours);
757775

776+
// Track liveness from the tracks endpoint (name → disabled), fetched once per
777+
// activation. A promoted track can be culled by a LATER promotion in the same
778+
// market while its experiment row stays 'promoted' forever, so without this
779+
// cross-reference the section charts dead tracks as mysteriously silent live
780+
// ones. A fetch failure leaves the map null: everything renders unbadged and
781+
// unhidden rather than mislabeled.
782+
const [trackDisabled, setTrackDisabled] = useState<Map<string, boolean> | null>(null);
783+
const [showCulled, setShowCulled] = useState(false);
784+
useEffect(() => {
785+
if (!enabled || !isAuthenticated) return;
786+
let cancelled = false;
787+
fetchTracks()
788+
.then((d) => {
789+
if (cancelled) return;
790+
const m = new Map<string, boolean>();
791+
for (const t of d.tracks ?? []) m.set(t.name, t.disabled);
792+
setTrackDisabled(m);
793+
})
794+
.catch(() => { if (!cancelled) setTrackDisabled(null); });
795+
return () => { cancelled = true; };
796+
}, [enabled, isAuthenticated]);
797+
// Only an explicit disabled=true counts: a track missing from the map (or a
798+
// failed fetch) is treated as live so an endpoint hiccup can't hide real cards.
799+
const isTrackDisabled = useCallback((name: string) => trackDisabled?.get(name) === true, [trackDisabled]);
800+
758801
const allPoints = useMemo(() => data?.points ?? [], [data]);
759802

760803
// Filter option lists come from all promotions (before country/protocol/provider
@@ -769,7 +812,18 @@ function PromotedTraffic({ enabled }: { enabled: boolean }) {
769812
(!provider || p.providerName === provider),
770813
[country, protocol, provider]);
771814

772-
const promotions = useMemo(() => allPoints.filter(matchesFilters), [allPoints, matchesFilters]);
815+
const filteredPoints = useMemo(() => allPoints.filter(matchesFilters), [allPoints, matchesFilters]);
816+
// Culled promotions (promoted track disabled) are hidden by default: they
817+
// carry no traffic, so their cards are pure noise unless explicitly asked
818+
// for. Hiding them BEFORE byMarket also skips their SigNoz traffic queries.
819+
const culledCount = useMemo(
820+
() => filteredPoints.filter((p) => isTrackDisabled(p.promotedTrackName)).length,
821+
[filteredPoints, isTrackDisabled],
822+
);
823+
const promotions = useMemo(
824+
() => (showCulled ? filteredPoints : filteredPoints.filter((p) => !isTrackDisabled(p.promotedTrackName))),
825+
[filteredPoints, showCulled, isTrackDisabled],
826+
);
773827

774828
const startMs = data?.windowStart ? Date.parse(data.windowStart) : 0;
775829
const endMs = data?.windowEnd ? Date.parse(data.windowEnd) : 0;
@@ -919,6 +973,17 @@ function PromotedTraffic({ enabled }: { enabled: boolean }) {
919973
{providers.map((p) => <option key={p} value={p}>{p}</option>)}
920974
</select>
921975
</div>
976+
{culledCount > 0 && (
977+
<button
978+
type="button"
979+
onClick={() => setShowCulled((v) => !v)}
980+
style={chip(showCulled)}
981+
aria-pressed={showCulled}
982+
title="Promotions whose promoted track has since been disabled (most commonly culled by a later promotion in the same market). They carry no traffic, so their cards are hidden by default."
983+
>
984+
{showCulled ? `hide culled (${culledCount})` : `show culled (${culledCount})`}
985+
</button>
986+
)}
922987
{hasFilters && (
923988
<button type="button" onClick={() => { setCountry(""); setProtocol(""); setProvider(""); }} style={chip(false)}>Clear</button>
924989
)}
@@ -930,7 +995,8 @@ function PromotedTraffic({ enabled }: { enabled: boolean }) {
930995
<div style={{ ...mono, fontSize: "0.65rem", color: "var(--text-muted)" }}>Loading promotions…</div>
931996
) : promotions.length === 0 ? (
932997
<div style={{ ...mono, fontSize: "0.65rem", color: "var(--text-muted)" }}>
933-
No promoted experiments{hasFilters ? " for the selected filters" : ""}.
998+
No live promoted experiments{hasFilters ? " for the selected filters" : ""}.
999+
{!showCulled && culledCount > 0 ? ` ${culledCount} culled ${culledCount === 1 ? "promotion is" : "promotions are"} hidden — use the "show culled" toggle.` : ""}
9341000
</div>
9351001
) : (
9361002
<>
@@ -939,11 +1005,22 @@ function PromotedTraffic({ enabled }: { enabled: boolean }) {
9391005
)}
9401006
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(26rem, 1fr))", gap: "1rem" }}>
9411007
{promotions.map((p) => (
942-
<PromotionTrafficCard key={p.experimentId} point={p} seriesByTrackCountry={seriesByTrackCountry} startMs={startMs} endMs={endMs} logScale={logScale} />
1008+
<PromotionTrafficCard
1009+
key={p.experimentId}
1010+
point={p}
1011+
seriesByTrackCountry={seriesByTrackCountry}
1012+
startMs={startMs}
1013+
endMs={endMs}
1014+
logScale={logScale}
1015+
promotedDisabled={isTrackDisabled(p.promotedTrackName)}
1016+
originalDisabled={isTrackDisabled(p.originalTrackName)}
1017+
/>
9431018
))}
9441019
</div>
9451020
<div style={{ ...mono, fontSize: "0.55rem", color: "var(--text-muted)", marginTop: "0.5rem" }}>
946-
{promotions.length} {promotions.length === 1 ? "promotion" : "promotions"}{trafficLoading ? ` · loading ${metricNoun}…` : ""}
1021+
{promotions.length} {promotions.length === 1 ? "promotion" : "promotions"}
1022+
{!showCulled && culledCount > 0 ? ` · ${culledCount} culled hidden` : ""}
1023+
{trafficLoading ? ` · loading ${metricNoun}…` : ""}
9471024
</div>
9481025
</>
9491026
)}
@@ -956,9 +1033,10 @@ function PromotedTraffic({ enabled }: { enabled: boolean }) {
9561033
export default function ExperimentsOverview({ enabled }: { enabled: boolean }) {
9571034
const [view, setView] = useState<"experiments" | "settings">("experiments");
9581035
const [selectedId, setSelectedId] = useState<number | null>(null);
959-
// Status filter driven by the pipeline strip. Retired experiments are hidden by
960-
// default — they're the bulk of terminal history and rarely what you're after.
961-
const [hiddenStatuses, setHiddenStatuses] = useState<Set<string>>(() => new Set(["retired"]));
1036+
// Status filter driven by the pipeline strip. Retired and aborted experiments
1037+
// are hidden by default — together they're the bulk of terminal history and
1038+
// rarely what you're after; the strip's counts still show them.
1039+
const [hiddenStatuses, setHiddenStatuses] = useState<Set<string>>(() => new Set(["retired", "aborted"]));
9621040
const { experiments, pipeline, isLoading, hasLoaded, error, refresh } = useExperiments(enabled);
9631041
const settings = useExperimentSettings(enabled);
9641042

0 commit comments

Comments
 (0)