From af51ffb9c77d038a5adb5da841f34fb092d2dd0f Mon Sep 17 00:00:00 2001 From: Robin Huang Date: Thu, 28 May 2026 20:32:17 -0700 Subject: [PATCH] feat(tracking): namespace PostHog events with cli: prefix Apply a "cli:" prefix to event names sent to PostHog only, so CLI events are distinct from other surfaces (app:/hub:/registry:) in the shared project. Mixpanel keeps the bare legacy names for stream continuity. Co-Authored-By: Claude Opus 4.8 (1M context) --- comfy_cli/tracking.py | 10 ++++++++- tests/comfy_cli/test_tracking_providers.py | 25 +++++++++++++++++++--- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/comfy_cli/tracking.py b/comfy_cli/tracking.py index 32695a66..484e54e5 100644 --- a/comfy_cli/tracking.py +++ b/comfy_cli/tracking.py @@ -32,6 +32,12 @@ # Only these events get the tracing_id --> workflow_run_id alias on PostHog. EXECUTION_EVENTS = frozenset({"execution_start", "execution_success", "execution_error"}) +# Namespace applied to event names on PostHog only, matching the +# app:/hub:/registry: surface-prefix convention in the shared project. Mixpanel +# keeps the bare legacy names (see ``mixpanel_name`` in track_event) so its +# historical streams stay continuous. +POSTHOG_EVENT_PREFIX = "cli:" + # Kwargs whose values must never reach tracking system. # The key is kept (with a redacted marker) so we can still see whether the option was supplied. SENSITIVE_TRACKING_KEYS = frozenset({"api_key"}) @@ -113,9 +119,11 @@ def track(self, event_name: str, distinct_id: str | None, properties: dict[str, if not self.enabled or self.client is None or distinct_id is None: return merged = {**self._STANDARD_PROPERTIES, **properties} + # Membership check uses the canonical (unprefixed) name; the prefix is + # cosmetic to the PostHog taxonomy and applied only at capture time. if event_name in EXECUTION_EVENTS and "tracing_id" in merged: merged.setdefault("workflow_run_id", merged["tracing_id"]) - self.client.capture(event=event_name, distinct_id=distinct_id, properties=merged) + self.client.capture(event=f"{POSTHOG_EVENT_PREFIX}{event_name}", distinct_id=distinct_id, properties=merged) def flush(self) -> None: if self.client is None: diff --git a/tests/comfy_cli/test_tracking_providers.py b/tests/comfy_cli/test_tracking_providers.py index dc16b6d4..f3a9846e 100644 --- a/tests/comfy_cli/test_tracking_providers.py +++ b/tests/comfy_cli/test_tracking_providers.py @@ -168,17 +168,36 @@ def test_mixpanel_name_kwarg_routes_to_mixpanel_only(self, tracking_with_two_pro _, mp_kwargs = mp_provider.client.track.call_args assert mp_kwargs["event_name"] == "run" + # PostHog receives the canonical name, prefixed; Mixpanel keeps "run". ph_kwargs = _posthog_capture_kwargs(ph_provider.client) - assert ph_kwargs["event"] == "execution_start" + assert ph_kwargs["event"] == "cli:execution_start" - def test_without_alias_both_providers_get_same_name(self, tracking_with_two_providers): + def test_posthog_prefixes_event_while_mixpanel_stays_bare(self, tracking_with_two_providers): tracking_mod, mp_provider, ph_provider = tracking_with_two_providers tracking_mod.track_event("execution_success") _, mp_kwargs = mp_provider.client.track.call_args ph_kwargs = _posthog_capture_kwargs(ph_provider.client) + # Mixpanel keeps the bare name for stream continuity; PostHog is namespaced. assert mp_kwargs["event_name"] == "execution_success" - assert ph_kwargs["event"] == "execution_success" + assert ph_kwargs["event"] == "cli:execution_success" + + +class TestPostHogEventPrefix: + def test_top_level_event_is_prefixed(self, tracking_with_two_providers): + tracking_mod, mp_provider, ph_provider = tracking_with_two_providers + tracking_mod.track_event("install") + + # Mixpanel bare, PostHog namespaced. + _, mp_kwargs = mp_provider.client.track.call_args + assert mp_kwargs["event_name"] == "install" + assert _posthog_capture_kwargs(ph_provider.client)["event"] == "cli:install" + + def test_sub_namespaced_event_composes_with_prefix(self, tracking_with_two_providers): + tracking_mod, _, ph_provider = tracking_with_two_providers + tracking_mod.track_event("node:install") + + assert _posthog_capture_kwargs(ph_provider.client)["event"] == "cli:node:install" class TestProviderConstruction: