Skip to content

feat(telemetry): instrument cloud funnel gaps (auth, onboarding, canvas, output) - #12894

Closed
deepme987 wants to merge 27 commits into
mainfrom
deepme987/frontend/cloud-funnel-telemetry
Closed

feat(telemetry): instrument cloud funnel gaps (auth, onboarding, canvas, output)#12894
deepme987 wants to merge 27 commits into
mainfrom
deepme987/frontend/cloud-funnel-telemetry

Conversation

@deepme987

@deepme987 deepme987 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Quick Read

Tracks the steps between "user lands on the site" and "user sees their first result" — sign-in, the post-login fork, the canvas loading, the first output — so we can see exactly where people drop off instead of guessing from a coarse 6-step funnel. Cloud-only, additive events; no behavior changes.


Summary

Instruments the dark sub-steps of the cloud user funnel between landing and first output, so we can see where users actually drop instead of inferring it from a coarse 6-step macro funnel.

Changes

  • What: Adds cloud-only PostHog events across the post-landing journey.
    • app:auth_method_selected, app:oauth_popup_result, app:auth_failed — the OAuth popup gap where users abandon before auth completes.
    • app:canvas_ready — canvas first interactive, carrying is_new_user and ms_since_auth (user_logged_in carries neither), to anchor new-user activation on the canvas.
    • app:onboarding_routed — the UserCheckView post-auth fork (waitlist / survey / onboarded), where users vanish before the canvas.
    • app:output_viewed — first media output of a run becoming visible (the activation moment); deduped per run, is_first_output flags the session's first.
    • app:checkout_initiate_failed / app:checkout_window_blocked and a paywall reason on the subscription path.
    • Re-enables app:workflow_opened / app:workflow_created (previously in the default-disabled list) and removes the dead email-verification telemetry path.
  • Breaking: None. New registry methods dispatch via optional chaining; the GTM and Mixpanel providers ignore them, PostHog carries them. All emits are gated on isCloud.

Review Focus

  • canvas_ready bridge (authActivationMarker.ts): is_new_user / ms_since_auth are set at the four auth-completion sites in authStore and consumed once when the graph canvas first becomes interactive. The onboarded path navigates via a full location.href reload, so an in-memory store ref would not survive; a per-tab sessionStorage marker does, and is cleared on tab close.
  • output_viewed fires from executionStore.handleExecuted on the first media-bearing node of a run; the seen-run set is bounded (256) to avoid unbounded growth in long sessions.
  • onboarding_routed mapping: the no-cloud-status fork (cloud-login) maps to waitlist per the documented "not yet provisioned" semantics.

Companion PRs

  • Comfy-Org/cloud#4330 — backend side of the same funnel-instrumentation effort (billing:subscription_succeeded / billing:subscription_renewed, sampled queue_state_changed).
  • Desktop (ComfyUI-Desktop-2.0-Beta) instrumentation is tracked separately and will cross-link here.

…as, output)

Closes the dark sub-steps between landing and first output that the macro
funnel hid. New PostHog events (all cloud-only):

- app:auth_method_selected / app:oauth_popup_result / app:auth_failed —
  the OAuth popup void where users abandon before auth completes.
- app:canvas_ready — canvas first interactive, with is_new_user and
  ms_since_auth, anchoring new-user activation (user_logged_in carries
  neither). Bridged across the onboarding location.href reload via a
  per-tab sessionStorage marker set at auth completion.
- app:onboarding_routed — the UserCheckView post-auth fork
  (waitlist / survey / onboarded), lighting where users vanish before
  the canvas.
- app:output_viewed — first media output of a run becomes visible (the
  activation moment); deduped per run, is_first_output flags the
  session's first.
- Checkout-failure + paywall-reason events on the subscription path.

Re-enables app:workflow_opened / app:workflow_created (previously in the
default-disabled list) and removes the dead email-verification telemetry
path. GTM and Mixpanel providers ignore the new methods via optional
dispatch; PostHog carries them.
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Extends cloud telemetry across auth, onboarding, checkout, and execution output flows by adding new metadata types, TelemetryRegistry dispatchers, and PostHogTelemetryProvider methods. Introduces a sessionStorage-backed auth activation bridge for canvas-ready attribution. Website PostHog integration gains captureCtaClick wired into navigation and product card components.

Changes

Cloud Telemetry Expansion

Layer / File(s) Summary
Telemetry types, events, and provider interface contracts
src/platform/telemetry/types.ts, src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
Adds auth funnel, checkout, onboarding, canvas-ready, and output-viewed metadata types; new TelemetryEvents constants; extends TelemetryProvider interface with 12 optional methods; extends TelemetryEventProperties union; adds SubscriptionDialogReason members.
TelemetryRegistry dispatch methods
src/platform/telemetry/TelemetryRegistry.ts, src/platform/telemetry/TelemetryRegistry.test.ts
Adds public dispatch methods for all new event families forwarding metadata to optional provider handlers; test verifies each dispatcher calls provider exactly once.
PostHog provider: new methods, super-properties, autocapture
src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.ts, ...PostHogTelemetryProvider.test.ts
12 new public tracking wrappers; removes WORKFLOW_OPENED/WORKFLOW_CREATED from disabled set; enables autocapture/pageview/pageleave; registers is_app_mode and customer_tier super-properties via watchers; sets first-touch UTM attribution. Tests cover funnel events, super-properties, and UTM attribution.
Auth activation sessionStorage bridge
src/platform/telemetry/authActivationMarker.ts, src/platform/telemetry/authActivationMarker.test.ts
markAuthForActivation writes {at, isNewUser} to sessionStorage; consumeAuthActivation reads-and-removes with JSON validation and 60s staleness check. Tests cover lifecycle, staleness, malformed input, and storage failure.
Auth store telemetry instrumentation
src/stores/authStore.ts, src/stores/authStore.test.ts
executeAuthAction gains optional telemetry context to emit trackAuthMethodSelected, trackOAuthPopupResult, and trackAuthFailed; login/register/OAuth methods replace trackAuth with markAuthForActivation.
Canvas-ready and onboarding routing call sites
src/views/GraphView.vue, src/platform/cloud/onboarding/UserCheckView.vue
GraphView.vue consumes activation marker on graph-ready and emits trackCanvasReady; UserCheckView.vue emits trackOnboardingRouted for all four routing branches.
Checkout and paywall telemetry call sites
src/platform/cloud/subscription/composables/useSubscription.ts, ...useSubscription.test.ts, src/platform/cloud/subscription/composables/useSubscriptionDialog.ts, ...useSubscriptionDialog.test.ts
useSubscription adds attempt dedup, wraps initiation with try/catch, emits checkout lifecycle events; useSubscriptionDialog emits trackPaywallViewed with tier. Tests verify all checkout return outcomes and paywall emission paths.
Subscription UI click telemetry
src/platform/cloud/subscription/components/PricingTable.vue, ...PricingTable.test.ts, SubscribeButton.vue, SubscribeToRun.vue, SubscribeToRun.test.ts
PricingTable emits trackSubscription('subscribe_clicked') and trackBillingCycleToggled; SubscribeButton adds source field; SubscribeToRun adds source:'subscribe_to_run' in cloud path.
Output-viewed and first-execution telemetry
src/stores/executionStore.ts, src/stores/executionStore.test.ts
Classifies output filenames into media types; emits trackOutputViewed once per run with session-scoped is_first_output; emits trackFirstExecutionCompleted once per profile via localStorage guard. Tests cover deduplication, media-type classification, and cloud-gate enforcement.
Template category selection telemetry
src/components/custom/widget/WorkflowTemplateSelectorDialog.vue
Adds watch on selectedNavItem that emits trackTemplateCategorySelected with category_id on category change.

Website PostHog CTA Click Tracking

Layer / File(s) Summary
captureCtaClick function and types
apps/website/src/scripts/posthog.ts, apps/website/src/scripts/posthog.test.ts
Exports CtaButton, CtaLocation union types and a gated captureCtaClick function capturing website:cta_clicked with error logging. Tests verify payload and no-op before init.
Navigation data model
apps/website/src/data/mainNavigation.ts
Adds ctaButton?: CtaButton to NavColumnItem; makes ctaButton mutually exclusive on NavItem union branches; assigns ctaButton to comfyLocal, comfyCloud, and pricing entries.
Navigation components wired with click handlers
apps/website/src/components/common/HeaderMain/HeaderMain.vue, HeaderMainDesktop.vue, HeaderMainMobile.vue, NavColumn.vue
Each component imports captureCtaClick and attaches conditional click handlers to navigation links and CTA buttons.
Product cards and hero CTA tracking
apps/website/src/components/common/ProductCardsSection.vue, ProductCard.vue, apps/website/src/components/home/HeroSection.vue
ProductCardsSection maps products to CtaButton values; ProductCard accepts ctaButton prop and calls captureCtaClick; HeroSection calls captureCtaClick('run_first_workflow', 'hero').

Sequence Diagram(s)

sequenceDiagram
  rect rgba(70, 130, 180, 0.5)
    Note over authStore,sessionStorage: Auth flow
  end
  participant authStore
  participant TelemetryRegistry
  participant sessionStorage as authActivationMarker
  participant GraphView

  authStore->>TelemetryRegistry: trackAuthMethodSelected(method, view)
  authStore->>authStore: Firebase auth + createCustomer
  authStore->>TelemetryRegistry: trackOAuthPopupResult / trackAuthFailed
  authStore->>sessionStorage: markAuthForActivation(isNewUser)
  Note over GraphView: later, on canvas ready
  GraphView->>sessionStorage: consumeAuthActivation()
  sessionStorage-->>GraphView: {at, isNewUser} or null
  GraphView->>TelemetryRegistry: trackCanvasReady(is_new_user, ms_since_auth)
Loading
sequenceDiagram
  rect rgba(100, 160, 100, 0.5)
    Note over useSubscription,TelemetryRegistry: Checkout lifecycle
  end
  participant useSubscription
  participant server as initiateSubscriptionCheckout
  participant windowOpen as window.open
  participant TelemetryRegistry

  useSubscription->>server: initiateSubscriptionCheckout()
  alt server error
    server-->>TelemetryRegistry: trackCheckoutInitiateFailed(stage=server_error)
  else no checkout_url
    server-->>TelemetryRegistry: trackCheckoutInitiateFailed(stage=no_url)
  end
  useSubscription->>windowOpen: open(checkout_url)
  alt window blocked
    windowOpen-->>TelemetryRegistry: trackCheckoutWindowBlocked()
  else opened
    useSubscription->>TelemetryRegistry: trackCheckoutViewed(attempt_id, tier, cycle)
    Note over TelemetryRegistry: on return
    useSubscription->>TelemetryRegistry: trackCheckoutReturned(success|unknown|cancelled)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Comfy-Org/ComfyUI_frontend#8354: Directly overlaps with checkout telemetry additions (begin_checkout/checkout payload attribution) and the shared TelemetryRegistry wiring for checkout events.
  • Comfy-Org/ComfyUI_frontend#12618: Both extend TelemetryRegistry with new track* dispatch methods and corresponding type/provider wiring using the same pattern.
  • Comfy-Org/ComfyUI_frontend#12878: The new TelemetryProvider interface methods and event types added here are exactly the integration surface a new Customer.io telemetry provider would implement.

Suggested labels

size:L, released:cloud, cloud/1.45, cloud/1.46

Suggested reviewers

  • benceruleanlu
  • christian-byrne
  • jtydhr88

Poem

🐇 Hop, hop! The funnel blooms,
Each click now tracked through checkout rooms.
Auth markers flash in session store,
Canvas-ready pings the PostHog shore.
CTAs in nav all ring a bell —
The rabbit counts each tale to tell! 🎉

🚥 Pre-merge checks | ✅ 6 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the main change: adding cloud funnel telemetry instrumentation for auth, onboarding, canvas, and output tracking to identify user dropoff points.
Description check ✅ Passed The PR description provides comprehensive context with a quick summary, detailed changes section, and specific review focus areas. It covers all major changes (auth events, canvas_ready, output_viewed, checkout events) and explains key design decisions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
End-To-End Regression Coverage For Fixes ✅ Passed This PR adds telemetry instrumentation (new PostHog events, "additive events; no behavior changes"), not a bug fix. E2E regression tests are only required for bug fixes per the check instructions.
Adr Compliance For Entity/Litegraph Changes ✅ Passed PR contains no changes to src/lib/litegraph/, src/ecs/, or graph entity files. ADR compliance check for entity/litegraph changes is not applicable.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch deepme987/frontend/cloud-funnel-telemetry

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/stores/executionStore.ts (2)

98-106: ⚡ Quick win

Consider moving session tracking state into the store or document the rationale.

The outputViewedRuns Set and sessionHasViewedOutput boolean are declared at module level rather than within the Pinia store. While this achieves tab-level persistence across store instances, it has tradeoffs:

  • Testing: Cannot easily reset between tests; state persists across test cases
  • Observability: Not reactive, invisible to Vue DevTools
  • Convention: Deviates from typical Pinia patterns where all state lives inside defineStore

If module-level state is intentional for session-scoped tracking (surviving component unmount/remount), consider adding a comment explaining why this state must live outside the store. Otherwise, consider moving it inside the store and resetting it on logout or app reload.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/stores/executionStore.ts` around lines 98 - 106, The module-level
variables outputViewedRuns and sessionHasViewedOutput are declared outside the
Pinia store, which makes them difficult to test and invisible to Vue DevTools.
Either move these variables inside the defineStore function as part of the
store's state object to align with Pinia conventions and enable proper test
isolation, or if session-level persistence across store instances is
intentional, add a clear code comment above these declarations explaining the
architectural rationale for keeping them at module level.

341-359: 💤 Low value

Optional: Add comment explaining Set insertion-order guarantee.

The eviction logic on lines 348-349 relies on ES2015+ Sets maintaining insertion order, so .values().next().value returns the oldest entry. While correct, this is a subtle detail that might not be immediately obvious to future maintainers.

Consider adding a brief comment:

// Sets maintain insertion order (ES2015+), so first value is oldest
const oldest = outputViewedRuns.values().next().value
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/stores/executionStore.ts` around lines 341 - 359, Add a brief comment
above the line that retrieves the oldest entry from the outputViewedRuns Set
(the line with `const oldest = outputViewedRuns.values().next().value`) to
explain that Sets maintain insertion order in ES2015+. This clarifies why
accessing the first value via `.values().next().value` reliably returns the
oldest/first-inserted entry, which is a subtle implementation detail that future
maintainers should understand.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/stores/executionStore.ts`:
- Around line 98-106: The module-level variables outputViewedRuns and
sessionHasViewedOutput are declared outside the Pinia store, which makes them
difficult to test and invisible to Vue DevTools. Either move these variables
inside the defineStore function as part of the store's state object to align
with Pinia conventions and enable proper test isolation, or if session-level
persistence across store instances is intentional, add a clear code comment
above these declarations explaining the architectural rationale for keeping them
at module level.
- Around line 341-359: Add a brief comment above the line that retrieves the
oldest entry from the outputViewedRuns Set (the line with `const oldest =
outputViewedRuns.values().next().value`) to explain that Sets maintain insertion
order in ES2015+. This clarifies why accessing the first value via
`.values().next().value` reliably returns the oldest/first-inserted entry, which
is a subtle implementation detail that future maintainers should understand.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6435d586-5020-4f95-a13e-7132aa9e7195

📥 Commits

Reviewing files that changed from the base of the PR and between e994e4d and 151b667.

📒 Files selected for processing (16)
  • src/platform/cloud/onboarding/UserCheckView.vue
  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/platform/telemetry/TelemetryRegistry.ts
  • src/platform/telemetry/authActivationMarker.ts
  • src/platform/telemetry/providers/cloud/GtmTelemetryProvider.test.ts
  • src/platform/telemetry/providers/cloud/GtmTelemetryProvider.ts
  • src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.test.ts
  • src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.ts
  • src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.test.ts
  • src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.ts
  • src/platform/telemetry/types.ts
  • src/stores/authStore.test.ts
  • src/stores/authStore.ts
  • src/stores/executionStore.ts
  • src/views/GraphView.vue
💤 Files with no reviewable changes (4)
  • src/platform/telemetry/providers/cloud/GtmTelemetryProvider.ts
  • src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.test.ts
  • src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.ts
  • src/platform/telemetry/providers/cloud/GtmTelemetryProvider.test.ts

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 17, 2026
@codecov

codecov Bot commented Jun 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.72199% with 32 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...emetry/providers/cloud/PostHogTelemetryProvider.ts 88.88% 7 Missing ⚠️
src/platform/cloud/onboarding/UserCheckView.vue 0.00% 5 Missing ⚠️
.../cloud/subscription/composables/useSubscription.ts 80.00% 5 Missing ⚠️
src/views/GraphView.vue 0.00% 5 Missing ⚠️
src/stores/authStore.ts 90.24% 4 Missing ⚠️
...s/custom/widget/WorkflowTemplateSelectorDialog.vue 0.00% 3 Missing ⚠️
src/stores/executionStore.ts 90.32% 3 Missing ⚠️
@@            Coverage Diff             @@
##             main   #12894      +/-   ##
==========================================
+ Coverage   76.21%   76.46%   +0.25%     
==========================================
  Files        1574     1574              
  Lines      102210    88251   -13959     
  Branches    32027    26674    -5353     
==========================================
- Hits        77897    67482   -10415     
+ Misses      23489    20118    -3371     
+ Partials      824      651     -173     
Flag Coverage Δ
unit 63.24% <86.72%> (+0.08%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...orm/cloud/subscription/components/PricingTable.vue 95.54% <100.00%> (+0.11%) ⬆️
.../cloud/subscription/components/SubscribeButton.vue 28.57% <ø> (ø)
...m/cloud/subscription/components/SubscribeToRun.vue 95.83% <100.00%> (+14.35%) ⬆️
.../subscription/composables/useSubscriptionDialog.ts 80.00% <100.00%> (+30.56%) ⬆️
src/platform/telemetry/TelemetryRegistry.ts 31.88% <100.00%> (+21.40%) ⬆️
src/platform/telemetry/authActivationMarker.ts 100.00% <100.00%> (ø)
src/platform/telemetry/types.ts 100.00% <ø> (ø)
...s/custom/widget/WorkflowTemplateSelectorDialog.vue 57.67% <0.00%> (+2.44%) ⬆️
src/stores/executionStore.ts 93.72% <90.32%> (+3.86%) ⬆️
src/stores/authStore.ts 85.53% <90.24%> (+12.19%) ⬆️
... and 4 more

... and 288 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…l events

- authActivationMarker: mark->consume round-trip, single-consume (clears the
  key), null on missing / corrupt / wrong-shape, and a swallowed
  sessionStorage failure.
- executionStore output_viewed: first media output of a run emits once,
  per-run dedup, is_first_output flips after the session's first, media_type
  mapping (image/video/gifs/audio), text-only skipped, isCloud-gated.
- PostHogTelemetryProvider: each new funnel method (canvas_ready,
  onboarding_routed, output_viewed, auth_method_selected, oauth_popup_result,
  auth_failed, checkout_initiate_failed, checkout_window_blocked) captures the
  right event name and forwards its metadata.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/stores/executionStore.test.ts (1)

1424-1589: ⚡ Quick win

Cover the dedupe eviction contract.

The suite verifies per-run suppression, but not the bounded eviction path that prevents outputViewedRuns from growing indefinitely. Add one case that emits more than 256 unique run IDs, then verifies the oldest ID can emit again with is_first_output: false.

As per coding guidelines, “Write tests for all changes, especially bug fixes to catch future regressions.”

🧪 Proposed regression test
   it('does not emit for a non-media (text-only) output', async () => {
     const store = await freshStore()
     startRun(store, 'run-text')
 
@@
 
     expect(mockTrackOutputViewed).not.toHaveBeenCalled()
   })
+
+  it('evicts the oldest run id from the output_viewed dedupe set', async () => {
+    const maxTrackedOutputRuns = 256
+    const store = await freshStore()
+
+    for (let index = 0; index <= maxTrackedOutputRuns; index++) {
+      const runId = `run-${index}`
+      startRun(store, runId)
+      fireExecuted({ node: 'save-1', prompt_id: runId, output: imageOutput })
+    }
+
+    expect(mockTrackOutputViewed).toHaveBeenCalledTimes(
+      maxTrackedOutputRuns + 1
+    )
+    mockTrackOutputViewed.mockClear()
+
+    startRun(store, 'run-0')
+    fireExecuted({ node: 'save-1', prompt_id: 'run-0', output: imageOutput })
+
+    expect(mockTrackOutputViewed).toHaveBeenCalledWith({
+      workflow_run_id: 'run-0',
+      media_type: 'image',
+      is_first_output: false
+    })
+  })
 
   it('does not emit anything when isCloud is false', async () => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/stores/executionStore.test.ts` around lines 1424 - 1589, Add a new test
case within the describe block that verifies the bounded eviction path for the
outputViewedRuns deduplication set. Create a test that calls freshStore(), then
uses startRun() and fireExecuted() to process more than 256 unique run IDs to
fill and exceed the capacity of the outputViewedRuns set, then verify that an
old run ID (one that should have been evicted when the set reached capacity) can
emit trackOutputViewed again with is_first_output set to false, confirming that
the eviction prevents unbounded growth of the dedup set.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/stores/executionStore.test.ts`:
- Around line 1538-1543: The test uses `it.each` which violates the
`vitest/consistent-each-for` linting rule. Import `test` from vitest at the top
of the file and replace the `it.each` call with `test.each` to comply with the
linting requirement for parameterized tests.

---

Nitpick comments:
In `@src/stores/executionStore.test.ts`:
- Around line 1424-1589: Add a new test case within the describe block that
verifies the bounded eviction path for the outputViewedRuns deduplication set.
Create a test that calls freshStore(), then uses startRun() and fireExecuted()
to process more than 256 unique run IDs to fill and exceed the capacity of the
outputViewedRuns set, then verify that an old run ID (one that should have been
evicted when the set reached capacity) can emit trackOutputViewed again with
is_first_output set to false, confirming that the eviction prevents unbounded
growth of the dedup set.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2e04fbb5-cea4-451e-9d9c-760464737ce3

📥 Commits

Reviewing files that changed from the base of the PR and between 68cd6c8 and 938609b.

📒 Files selected for processing (3)
  • src/platform/telemetry/authActivationMarker.test.ts
  • src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.test.ts
  • src/stores/executionStore.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.test.ts

Comment thread src/stores/executionStore.test.ts Outdated
- output_viewed: classify media_type via the canonical getMediaTypeFromFilename
  (reuse, not re-invent; now covers 3D), and evict-before-add in the dedup set
  so it never exceeds its bound.
- Move the output_viewed dedup state (run set + first-output flag) onto the
  store instance instead of module scope, so it resets with the store and
  tests isolate without resetModules.
- canvas_ready: stamp ms_since_auth at canvas-interactive time, before
  runWhenGlobalIdle defers, so the latency is auth->canvas not auth->idle.
- Tests: it.each -> it.for with canonical filename-based rows (+ 3D), drop a
  redundant typeof assertion, call trackCheckoutWindowBlocked with no args to
  match the real call site.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/stores/executionStore.test.ts`:
- Around line 1532-1556: The parameterized test cases in the it.for block always
use the images bucket in the fireExecuted call, but the test comment states that
bucket name should be irrelevant for media_type classification. Add at least one
additional test case (for example, filename 'a.glb' with bucket 'model_file'
instead of 'images') to the test data, and modify the fireExecuted call to use a
dynamic bucket property from the test case instead of always hardcoding 'images'
in the output object. This ensures the test validates that media_type
classification works across different output bucket types.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 352be80c-dd60-4cef-86fc-64b4661293ef

📥 Commits

Reviewing files that changed from the base of the PR and between 938609b and 2cda397.

📒 Files selected for processing (5)
  • src/platform/telemetry/authActivationMarker.test.ts
  • src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.test.ts
  • src/stores/executionStore.test.ts
  • src/stores/executionStore.ts
  • src/views/GraphView.vue
💤 Files with no reviewable changes (1)
  • src/platform/telemetry/authActivationMarker.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.test.ts
  • src/stores/executionStore.ts
  • src/views/GraphView.vue

Comment on lines +1532 to +1556
// media_type is classified by filename via getMediaTypeFromFilename, so the
// output bucket name is irrelevant (gif is an image extension; glb is 3D).
it.for([
{ filename: 'a.png', expected: 'image' },
{ filename: 'a.mp4', expected: 'video' },
{ filename: 'a.webm', expected: 'video' },
{ filename: 'a.gif', expected: 'image' },
{ filename: 'a.mp3', expected: 'audio' },
{ filename: 'a.glb', expected: '3D' }
])(
'classifies $filename as media_type $expected',
async ({ filename, expected }, { expect }) => {
const store = await freshStore()
startRun(store, 'run-media')

fireExecuted({
node: 'save-1',
prompt_id: 'run-media',
output: { images: [{ filename }] }
})

expect(mockTrackOutputViewed).toHaveBeenCalledTimes(1)
expect(mockTrackOutputViewed).toHaveBeenCalledWith(
expect.objectContaining({ media_type: expected })
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Retain one non-images bucket case to validate bucket-agnostic behavior.

Line 1550 always uses output.images, so this no longer verifies the
“bucket name is irrelevant” contract. Add one case (e.g., model_file + .glb)
to keep that behavior protected without expanding test volume much.

Suggested minimal test tweak
-  it.for([
-    { filename: 'a.png', expected: 'image' },
-    { filename: 'a.mp4', expected: 'video' },
-    { filename: 'a.webm', expected: 'video' },
-    { filename: 'a.gif', expected: 'image' },
-    { filename: 'a.mp3', expected: 'audio' },
-    { filename: 'a.glb', expected: '3D' }
-  ])(
+  it.for([
+    { output: { images: [{ filename: 'a.png' }] }, expected: 'image' },
+    { output: { images: [{ filename: 'a.mp4' }] }, expected: 'video' },
+    { output: { images: [{ filename: 'a.webm' }] }, expected: 'video' },
+    { output: { images: [{ filename: 'a.gif' }] }, expected: 'image' },
+    { output: { images: [{ filename: 'a.mp3' }] }, expected: 'audio' },
+    { output: { model_file: [{ filename: 'a.glb' }] }, expected: '3D' }
+  ])(
     'classifies $filename as media_type $expected',
-    async ({ filename, expected }, { expect }) => {
+    async ({ output, expected }, { expect }) => {
       const store = await freshStore()
       startRun(store, 'run-media')

       fireExecuted({
         node: 'save-1',
         prompt_id: 'run-media',
-        output: { images: [{ filename }] }
+        output
       })

As per coding guidelines, “Write tests for all changes, especially bug fixes to catch future regressions,” while staying “parsimonious in testing.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/stores/executionStore.test.ts` around lines 1532 - 1556, The
parameterized test cases in the it.for block always use the images bucket in the
fireExecuted call, but the test comment states that bucket name should be
irrelevant for media_type classification. Add at least one additional test case
(for example, filename 'a.glb' with bucket 'model_file' instead of 'images') to
the test data, and modify the fireExecuted call to use a dynamic bucket property
from the test case instead of always hardcoding 'images' in the output object.
This ensures the test validates that media_type classification works across
different output bucket types.

Source: Coding guidelines

deepme987 and others added 9 commits June 16, 2026 22:01
Extends the cloud funnel instrumentation (all cloud-only):

- app:paywall_viewed — fired when a subscription/paywall dialog opens, with
  the reason (run-gate wired now; member_invite / upload_model entry points
  pending billing-context reason threading) and current_tier.
- app:checkout_viewed — Stripe checkout window opened, sharing the pending
  checkout attempt id with the success event.
- app:checkout_returned — user returned from checkout (success / cancelled /
  unknown), deduped once per attempt.
- app:first_execution_completed — once-per-user activation moment, guarded by
  a durable localStorage key (private-mode safe).
- Super-properties on every cloud event: is_app_mode (graph vs app mode, via
  a watcher) and customer_tier (event-level mirror of subscription_tier), plus
  first-touch attribution ($set_once initial_utm_* on the person at init).

The super-property registrations are wrapped so a failure (e.g. Pinia not
ready at init) degrades to "property absent" instead of disabling the provider
and skipping identify/logout wiring. media_type classification reuses the
canonical getMediaTypeFromFilename.
Add a captureCtaClick helper to the website PostHog wrapper and fire
website:cta_clicked from the real CTA elements (hero, nav buttons, nav
products links, product cards) instead of relying on autocapture or
i18n text matching. Each event carries { button, location }.
app:subscribe_now_button_clicked was only fired by the legacy
SubscribeButton, never by the pricing table tier buttons or the
subscribe-to-run lock button - the surfaces users actually click. Add
the same trackSubscription('subscribe_clicked') capture to:

- PricingTable.handleSubscribe (both the new-subscriber and plan-change
  paths), before checkout opens, carrying { tier, cycle }
- SubscribeToRun.handleSubscribeToRun, alongside the existing run-button
  event

Each surface now tags a source ('pricing_table' | 'subscribe_to_run' |
'subscribe_button') so the subscribe-click funnel can be attributed by
CTA. Extend SubscriptionMetadata with tier/cycle/source; no new event
name.
…oud-funnel-telemetry

# Conflicts:
#	src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
…metry-gaps' into deepme987/frontend/cloud-funnel-telemetry

# Conflicts:
#	src/platform/telemetry/TelemetryRegistry.ts
#	src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.ts
#	src/platform/telemetry/types.ts
#	src/stores/authStore.ts
…etry' into deepme987/frontend/cloud-funnel-telemetry
- drop client-init heatmaps (RemoteConfig-only in posthog-js 1.358)
- un-export internal SubscribeClickSource (knip: unused export)
- sync provider/auth tests to the unioned config + trackAuthError mock
@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

🎭 Playwright: ✅ 1668 passed, 0 failed · 5 flaky

📊 Browser Reports
  • chromium: View Report (✅ 1647 / ❌ 0 / ⚠️ 5 / ⏭️ 5)
  • chromium-2x: View Report (✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • chromium-0.5x: View Report (✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • mobile-chrome: View Report (✅ 18 / ❌ 0 / ⚠️ 0 / ⏭️ 0)

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 06/22/2026, 09:12:43 PM UTC

Links

📦 Bundle: 7.46 MB gzip 🔴 +2.39 kB

Details

Summary

  • Raw size: 31.4 MB baseline 31.4 MB — 🔴 +10.7 kB
  • Gzip: 7.46 MB baseline 7.45 MB — 🔴 +2.39 kB
  • Brotli: 5.11 MB baseline 5.1 MB — 🔴 +2.01 kB
  • Bundles: 279 current • 279 baseline • 126 added / 126 removed

Category Glance
Utilities & Hooks 🔴 +6.79 kB (3.33 MB) · Other 🔴 +2.93 kB (10.4 MB) · Views & Navigation 🔴 +713 B (96 kB) · Graph Workspace 🔴 +283 B (1.25 MB) · UI Components 🔴 +39 B (57.2 kB) · Vendor & Third-Party ⚪ 0 B (15.3 MB) · + 5 more

App Entry Points — 46.7 kB (baseline 46.7 kB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-BsObDhqM.js (removed) 46.7 kB 🟢 -46.7 kB 🟢 -13.7 kB 🟢 -11.8 kB
assets/index-CZwMmt3u.js (new) 46.7 kB 🔴 +46.7 kB 🔴 +13.7 kB 🔴 +11.8 kB

Status: 1 added / 1 removed

Graph Workspace — 1.25 MB (baseline 1.25 MB) • 🔴 +283 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-DH_JueKi.js (new) 1.25 MB 🔴 +1.25 MB 🔴 +267 kB 🔴 +201 kB
assets/GraphView-C5lwcnzd.js (removed) 1.25 MB 🟢 -1.25 MB 🟢 -267 kB 🟢 -201 kB

Status: 1 added / 1 removed

Views & Navigation — 96 kB (baseline 95.3 kB) • 🔴 +713 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-4lZcCMGQ.js (removed) 19.5 kB 🟢 -19.5 kB 🟢 -5.06 kB 🟢 -4.49 kB
assets/CloudSurveyView-jbbvBzHw.js (new) 19.5 kB 🔴 +19.5 kB 🔴 +5.06 kB 🔴 +4.49 kB
assets/CloudLoginView-CYtdDMgr.js (new) 11.4 kB 🔴 +11.4 kB 🔴 +3.06 kB 🔴 +2.67 kB
assets/CloudLoginView-DsNcTwhI.js (removed) 11.4 kB 🟢 -11.4 kB 🟢 -3.06 kB 🟢 -2.68 kB
assets/CloudSignupView-C5pHyUrl.js (removed) 9.7 kB 🟢 -9.7 kB 🟢 -2.71 kB 🟢 -2.37 kB
assets/CloudSignupView-oPELf_-r.js (new) 9.7 kB 🔴 +9.7 kB 🔴 +2.71 kB 🔴 +2.37 kB
assets/UserCheckView-CeeAA9fr.js (new) 9.51 kB 🔴 +9.51 kB 🔴 +2.38 kB 🔴 +2.07 kB
assets/CloudLayoutView-BFV8Cqve.js (new) 9.36 kB 🔴 +9.36 kB 🔴 +2.34 kB 🔴 +2.02 kB
assets/CloudLayoutView-CWtTAOGL.js (removed) 9.36 kB 🟢 -9.36 kB 🟢 -2.34 kB 🟢 -2.02 kB
assets/UserCheckView-BBwavzOO.js (removed) 8.8 kB 🟢 -8.8 kB 🟢 -2.22 kB 🟢 -1.92 kB
assets/UserSelectView-BJeJOHJA.js (new) 6 kB 🔴 +6 kB 🔴 +2.15 kB 🔴 +1.89 kB
assets/UserSelectView-DITk0DFc.js (removed) 6 kB 🟢 -6 kB 🟢 -2.15 kB 🟢 -1.89 kB
assets/CloudForgotPasswordView-B718ZSLO.js (new) 5.15 kB 🔴 +5.15 kB 🔴 +1.76 kB 🔴 +1.53 kB
assets/CloudForgotPasswordView-F8ZhDrtK.js (removed) 5.15 kB 🟢 -5.15 kB 🟢 -1.76 kB 🟢 -1.54 kB
assets/CloudAuthTimeoutView-B5YQnHE-.js (new) 4.49 kB 🔴 +4.49 kB 🔴 +1.57 kB 🔴 +1.37 kB
assets/CloudAuthTimeoutView-BtEOcG13.js (removed) 4.49 kB 🟢 -4.49 kB 🟢 -1.57 kB 🟢 -1.37 kB
assets/CloudSubscriptionRedirectView-Bj4if86z.js (removed) 4.3 kB 🟢 -4.3 kB 🟢 -1.57 kB 🟢 -1.39 kB
assets/CloudSubscriptionRedirectView-CDwNjAOY.js (new) 4.3 kB 🔴 +4.3 kB 🔴 +1.57 kB 🔴 +1.38 kB

Status: 9 added / 9 removed / 3 unchanged

Panels & Settings — 525 kB (baseline 525 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/KeybindingPanel-DqEz2Jgf.js (new) 49.4 kB 🔴 +49.4 kB 🔴 +9.97 kB 🔴 +8.83 kB
assets/KeybindingPanel-DrMGJV90.js (removed) 49.4 kB 🟢 -49.4 kB 🟢 -9.97 kB 🟢 -8.83 kB
assets/SecretsPanel-CaZKIRWZ.js (removed) 24.2 kB 🟢 -24.2 kB 🟢 -5.77 kB 🟢 -5.07 kB
assets/SecretsPanel-Cwi7NHHl.js (new) 24.2 kB 🔴 +24.2 kB 🔴 +5.76 kB 🔴 +5.07 kB
assets/LegacyCreditsPanel-B-lx67G9.js (new) 20.9 kB 🔴 +20.9 kB 🔴 +5.52 kB 🔴 +4.86 kB
assets/LegacyCreditsPanel-C_ymPpgL.js (removed) 20.9 kB 🟢 -20.9 kB 🟢 -5.52 kB 🟢 -4.85 kB
assets/SubscriptionPanel-D__GgNrZ.js (removed) 19.2 kB 🟢 -19.2 kB 🟢 -5.04 kB 🟢 -4.41 kB
assets/SubscriptionPanel-DzIzL4f0.js (new) 19.2 kB 🔴 +19.2 kB 🔴 +5.04 kB 🔴 +4.41 kB
assets/AboutPanel-BBnbusig.js (removed) 11.7 kB 🟢 -11.7 kB 🟢 -3.22 kB 🟢 -2.89 kB
assets/AboutPanel-CLAP4bX-.js (new) 11.7 kB 🔴 +11.7 kB 🔴 +3.22 kB 🔴 +2.89 kB
assets/ExtensionPanel-BRsl0cMC.js (removed) 9.03 kB 🟢 -9.03 kB 🟢 -2.49 kB 🟢 -2.2 kB
assets/ExtensionPanel-e2OMnXv6.js (new) 9.03 kB 🔴 +9.03 kB 🔴 +2.5 kB 🔴 +2.2 kB
assets/ServerConfigPanel-BeGSx5QF.js (removed) 6.15 kB 🟢 -6.15 kB 🟢 -1.98 kB 🟢 -1.76 kB
assets/ServerConfigPanel-ebsTdHu3.js (new) 6.15 kB 🔴 +6.15 kB 🔴 +1.98 kB 🔴 +1.76 kB
assets/UserPanel-CU6nhNP4.js (new) 5.78 kB 🔴 +5.78 kB 🔴 +1.82 kB 🔴 +1.58 kB
assets/UserPanel-Dba3-iKr.js (removed) 5.78 kB 🟢 -5.78 kB 🟢 -1.82 kB 🟢 -1.58 kB
assets/refreshRemoteConfig-CcR7jB8t.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.06 kB 🟢 -944 B
assets/refreshRemoteConfig-YH9xMNGR.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.06 kB 🔴 +941 B
assets/cloudRemoteConfig-_4EY2GTn.js (new) 990 B 🔴 +990 B 🔴 +544 B 🔴 +443 B
assets/cloudRemoteConfig-DEFewhEG.js (removed) 990 B 🟢 -990 B 🟢 -542 B 🟢 -461 B
assets/refreshRemoteConfig-D5J4B-MK.js (new) 110 B 🔴 +110 B 🔴 +89 B 🔴 +78 B
assets/refreshRemoteConfig-UUenBIn7.js (removed) 110 B 🟢 -110 B 🟢 -89 B 🟢 -82 B

Status: 11 added / 11 removed / 15 unchanged

User & Accounts — 19.9 kB (baseline 19.9 kB) • ⚪ 0 B

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-BvMRmrMS.js (removed) 3.69 kB 🟢 -3.69 kB 🟢 -1.31 kB 🟢 -1.13 kB
assets/auth-CmauCgI3.js (new) 3.69 kB 🔴 +3.69 kB 🔴 +1.3 kB 🔴 +1.13 kB
assets/usePostAuthRedirect-CoAbbPSV.js (new) 3.33 kB 🔴 +3.33 kB 🔴 +1.28 kB 🔴 +1.11 kB
assets/usePostAuthRedirect-D2Z_6Flo.js (removed) 3.33 kB 🟢 -3.33 kB 🟢 -1.28 kB 🟢 -1.11 kB
assets/SignUpForm-DHC7_vaB.js (removed) 3.19 kB 🟢 -3.19 kB 🟢 -1.29 kB 🟢 -1.15 kB
assets/SignUpForm-DRdqlqzC.js (new) 3.19 kB 🔴 +3.19 kB 🔴 +1.29 kB 🔴 +1.15 kB
assets/UpdatePasswordContent-CmwsstRY.js (removed) 1.92 kB 🟢 -1.92 kB 🟢 -878 B 🟢 -769 B
assets/UpdatePasswordContent-CRZeE3N3.js (new) 1.92 kB 🔴 +1.92 kB 🔴 +878 B 🔴 +769 B
assets/authStore-CyFhavCy.js (removed) 130 B 🟢 -130 B 🟢 -109 B 🟢 -106 B
assets/authStore-vSahjjTP.js (new) 130 B 🔴 +130 B 🔴 +109 B 🔴 +105 B
assets/auth-9fjkmfMH.js (new) 105 B 🔴 +105 B 🔴 +96 B 🔴 +88 B
assets/auth-uasTvKWN.js (removed) 105 B 🟢 -105 B 🟢 -96 B 🟢 -80 B

Status: 6 added / 6 removed / 3 unchanged

Editors & Dialogs — 112 kB (baseline 112 kB) • ⚪ 0 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyHubPublishDialog-0S5wiMdQ.js (removed) 86 kB 🟢 -86 kB 🟢 -18.6 kB 🟢 -15.9 kB
assets/ComfyHubPublishDialog-Bts_7FhN.js (new) 86 kB 🔴 +86 kB 🔴 +18.6 kB 🔴 +15.9 kB
assets/useShareDialog-B8X-eQpV.js (removed) 23.3 kB 🟢 -23.3 kB 🟢 -5.53 kB 🟢 -4.91 kB
assets/useShareDialog-D6zyieO5.js (new) 23.3 kB 🔴 +23.3 kB 🔴 +5.53 kB 🔴 +4.92 kB
assets/ComfyHubPublishDialog-7umYiGUK.js (new) 143 B 🔴 +143 B 🔴 +105 B 🔴 +88 B
assets/ComfyHubPublishDialog-JJCPwH9s.js (removed) 143 B 🟢 -143 B 🟢 -105 B 🟢 -88 B
assets/useSubscriptionDialog-Bh5oHJN_.js (new) 110 B 🔴 +110 B 🔴 +102 B 🔴 +90 B
assets/useSubscriptionDialog-kzBozuSi.js (removed) 110 B 🟢 -110 B 🟢 -102 B 🟢 -88 B

Status: 4 added / 4 removed / 1 unchanged

UI Components — 57.2 kB (baseline 57.2 kB) • 🔴 +39 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-BdT6ju2p.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.82 kB 🟢 -3.42 kB
assets/ComfyQueueButton-DKs3Mj9q.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.82 kB 🔴 +3.42 kB
assets/useTerminalTabs-CCRlY8pO.js (removed) 12.1 kB 🟢 -12.1 kB 🟢 -3.84 kB 🟢 -3.39 kB
assets/useTerminalTabs-z16Qf5iq.js (new) 12.1 kB 🔴 +12.1 kB 🔴 +3.84 kB 🔴 +3.39 kB
assets/SubscribeButton-C2zH1MHF.js (new) 2.48 kB 🔴 +2.48 kB 🔴 +1.06 kB 🔴 +958 B
assets/SubscribeButton-Dmt1BwJv.js (removed) 2.44 kB 🟢 -2.44 kB 🟢 -1.05 kB 🟢 -928 B
assets/cloudFeedbackTopbarButton-CT_i5gMe.js (new) 829 B 🔴 +829 B 🔴 +498 B 🔴 +418 B
assets/cloudFeedbackTopbarButton-lfqLVb7p.js (removed) 829 B 🟢 -829 B 🟢 -498 B 🟢 -449 B
assets/ComfyQueueButton-CITeuY_t.js (new) 128 B 🔴 +128 B 🔴 +99 B 🔴 +95 B
assets/ComfyQueueButton-libaxDwa.js (removed) 128 B 🟢 -128 B 🟢 -99 B 🟢 -93 B

Status: 5 added / 5 removed / 8 unchanged

Data & Services — 269 kB (baseline 269 kB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/load3dService-CfjsOaRb.js (new) 127 kB 🔴 +127 kB 🔴 +27.9 kB 🔴 +23.6 kB
assets/load3dService-iYE3rXyr.js (removed) 127 kB 🟢 -127 kB 🟢 -27.9 kB 🟢 -23.6 kB
assets/api-BWz656VA.js (removed) 85.2 kB 🟢 -85.2 kB 🟢 -22.9 kB 🟢 -19.7 kB
assets/api-C4TTyuDH.js (new) 85.2 kB 🔴 +85.2 kB 🔴 +22.9 kB 🔴 +19.7 kB
assets/workflowShareService-BpM8DDm0.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.91 kB 🟢 -4.35 kB
assets/workflowShareService-DJrPn0jI.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.91 kB 🔴 +4.36 kB
assets/keybindingService-DOLxaEYX.js (new) 13.8 kB 🔴 +13.8 kB 🔴 +3.68 kB 🔴 +3.23 kB
assets/keybindingService-Dza5Jbpg.js (removed) 13.8 kB 🟢 -13.8 kB 🟢 -3.68 kB 🟢 -3.23 kB
assets/releaseStore-B4K19GpE.js (new) 8.29 kB 🔴 +8.29 kB 🔴 +2.34 kB 🔴 +2.04 kB
assets/releaseStore-DPl14LCY.js (removed) 8.29 kB 🟢 -8.29 kB 🟢 -2.34 kB 🟢 -2.05 kB
assets/extensionStore-C7SkGmGG.js (removed) 5.29 kB 🟢 -5.29 kB 🟢 -1.87 kB 🟢 -1.58 kB
assets/extensionStore-DokwGo3j.js (new) 5.29 kB 🔴 +5.29 kB 🔴 +1.86 kB 🔴 +1.58 kB
assets/userStore-j5cBHMN5.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -933 B 🟢 -823 B
assets/userStore-N-ZePkfm.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +931 B 🔴 +827 B
assets/audioService-TPGoW4yd.js (new) 1.76 kB 🔴 +1.76 kB 🔴 +862 B 🔴 +749 B
assets/audioService-Xqz3-qoR.js (removed) 1.76 kB 🟢 -1.76 kB 🟢 -864 B 🟢 -749 B
assets/dialogService-BEX_2Iij.js (removed) 100 B 🟢 -100 B 🟢 -99 B 🟢 -93 B
assets/dialogService-DiwMk_J_.js (new) 100 B 🔴 +100 B 🔴 +99 B 🔴 +92 B
assets/settingStore-DEQtlKzL.js (removed) 98 B 🟢 -98 B 🟢 -98 B 🟢 -89 B
assets/settingStore-PtmMxNV5.js (new) 98 B 🔴 +98 B 🔴 +98 B 🔴 +90 B
assets/assetsStore-6v4or-QV.js (removed) 96 B 🟢 -96 B 🟢 -97 B 🟢 -100 B
assets/assetsStore-CmFATqm2.js (new) 96 B 🔴 +96 B 🔴 +97 B 🔴 +100 B
assets/releaseStore-CyN81Hl2.js (new) 95 B 🔴 +95 B 🔴 +86 B 🔴 +91 B
assets/releaseStore-D2gLQDbA.js (removed) 95 B 🟢 -95 B 🟢 -86 B 🟢 -91 B
assets/api-BClVirCB.js (new) 62 B 🔴 +62 B 🔴 +74 B 🔴 +66 B
assets/api-CQDVlTpE.js (removed) 62 B 🟢 -62 B 🟢 -74 B 🟢 -66 B

Status: 13 added / 13 removed / 3 unchanged

Utilities & Hooks — 3.33 MB (baseline 3.33 MB) • 🔴 +6.79 kB

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/promotionUtils-B6A-QOHt.js (new) 2.98 MB 🔴 +2.98 MB 🔴 +689 kB 🔴 +519 kB
assets/promotionUtils-D5M2l3WW.js (removed) 2.97 MB 🟢 -2.97 MB 🟢 -687 kB 🟢 -518 kB
assets/useConflictDetection-BUz14XWT.js (removed) 233 kB 🟢 -233 kB 🟢 -52 kB 🟢 -42.4 kB
assets/useConflictDetection-D_zdjpRV.js (new) 233 kB 🔴 +233 kB 🔴 +52 kB 🔴 +42.3 kB
assets/useLoad3d-CDk72FSL.js (new) 25.5 kB 🔴 +25.5 kB 🔴 +5.76 kB 🔴 +5.1 kB
assets/useLoad3d-CwspdyP2.js (removed) 25.5 kB 🟢 -25.5 kB 🟢 -5.76 kB 🟢 -5.1 kB
assets/useLoad3dViewer-DBgAEz7u.js (new) 21.1 kB 🔴 +21.1 kB 🔴 +4.98 kB 🔴 +4.35 kB
assets/useLoad3dViewer-DrnfteIb.js (removed) 21.1 kB 🟢 -21.1 kB 🟢 -4.98 kB 🟢 -4.35 kB
assets/useFeatureFlags-Cg2zR3J8.js (removed) 5.37 kB 🟢 -5.37 kB 🟢 -1.66 kB 🟢 -1.41 kB
assets/useFeatureFlags-CQgFUK-Z.js (new) 5.37 kB 🔴 +5.37 kB 🔴 +1.65 kB 🔴 +1.41 kB
assets/useSessionCookie-CyHqAgSe.js (removed) 3.33 kB 🟢 -3.33 kB 🟢 -1.15 kB 🟢 -981 B
assets/useSessionCookie-DDOByZa5.js (new) 3.33 kB 🔴 +3.33 kB 🔴 +1.15 kB 🔴 +980 B
assets/subscriptionCheckoutUtil-BYIHMfqb.js (removed) 3.31 kB 🟢 -3.31 kB 🟢 -1.36 kB 🟢 -1.19 kB
assets/subscriptionCheckoutUtil-C_elGvxN.js (new) 3.31 kB 🔴 +3.31 kB 🔴 +1.36 kB 🔴 +1.19 kB
assets/assetPreviewUtil-Bdd2ArcJ.js (removed) 2.41 kB 🟢 -2.41 kB 🟢 -1.01 kB 🟢 -885 B
assets/assetPreviewUtil-BHbEvB5q.js (new) 2.41 kB 🔴 +2.41 kB 🔴 +1.01 kB 🔴 +876 B
assets/useUpstreamValue-BPTYXc8l.js (new) 2.04 kB 🔴 +2.04 kB 🔴 +794 B 🔴 +704 B
assets/useUpstreamValue-D28Of1-H.js (removed) 2.04 kB 🟢 -2.04 kB 🟢 -796 B 🟢 -713 B
assets/useWorkspaceSwitch-dGyPc9PV.js (removed) 748 B 🟢 -748 B 🟢 -386 B 🟢 -338 B
assets/useWorkspaceSwitch-lCXDvTu0.js (new) 748 B 🔴 +748 B 🔴 +385 B 🔴 +338 B
assets/useLoad3d-Bxt3DIeI.js (removed) 311 B 🟢 -311 B 🟢 -162 B 🟢 -147 B
assets/useLoad3d-BzS_mPgX.js (new) 311 B 🔴 +311 B 🔴 +165 B 🔴 +147 B
assets/useSessionCookie-l6jUO-f4.js (removed) 101 B 🟢 -101 B 🟢 -86 B 🟢 -84 B
assets/useSessionCookie-Ls1qzd0i.js (new) 101 B 🔴 +101 B 🔴 +86 B 🔴 +85 B
assets/useLoad3dViewer-COoIayBW.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +87 B
assets/useLoad3dViewer-DsMbOqMz.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -82 B
assets/useCurrentUser-BGlF7tiF.js (removed) 96 B 🟢 -96 B 🟢 -97 B 🟢 -92 B
assets/useCurrentUser-tzjGeLgu.js (new) 96 B 🔴 +96 B 🔴 +97 B 🔴 +84 B

Status: 14 added / 14 removed / 16 unchanged

Vendor & Third-Party — 15.3 MB (baseline 15.3 MB) • ⚪ 0 B

External libraries and shared vendor chunks

Status: 16 unchanged

Other — 10.4 MB (baseline 10.4 MB) • 🔴 +2.93 kB

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-Djd_p_Po.js (new) 118 kB 🔴 +118 kB 🔴 +30.4 kB 🔴 +25.7 kB
assets/core-gqHQC1xv.js (removed) 118 kB 🟢 -118 kB 🟢 -30.4 kB 🟢 -25.7 kB
assets/WidgetSelect-4Fl1RuiH.js (removed) 83.9 kB 🟢 -83.9 kB 🟢 -18.3 kB 🟢 -15.8 kB
assets/WidgetSelect-BJs1gHNj.js (new) 83.9 kB 🔴 +83.9 kB 🔴 +18.3 kB 🔴 +15.9 kB
assets/SubscriptionRequiredDialogContentWorkspace-0VGX9noI.js (removed) 47.8 kB 🟢 -47.8 kB 🟢 -9.08 kB 🟢 -7.85 kB
assets/SubscriptionRequiredDialogContentWorkspace-I2BuExyo.js (new) 47.8 kB 🔴 +47.8 kB 🔴 +9.08 kB 🔴 +7.84 kB
assets/Load3DControls-Bvtfs2xT.js (removed) 46.8 kB 🟢 -46.8 kB 🟢 -7.57 kB 🟢 -6.62 kB
assets/Load3DControls-Njv5Vh1N.js (new) 46.8 kB 🔴 +46.8 kB 🔴 +7.56 kB 🔴 +6.62 kB
assets/WorkspacePanelContent-CjI7Umrm.js (removed) 33.3 kB 🟢 -33.3 kB 🟢 -6.96 kB 🟢 -6.17 kB
assets/WorkspacePanelContent-DtbEYbS4.js (new) 33.3 kB 🔴 +33.3 kB 🔴 +6.96 kB 🔴 +6.17 kB
assets/WidgetPainter-BTKDXJf5.js (new) 32.6 kB 🔴 +32.6 kB 🔴 +7.87 kB 🔴 +7.01 kB
assets/WidgetPainter-BUVUcuGb.js (removed) 32.6 kB 🟢 -32.6 kB 🟢 -7.87 kB 🟢 -6.98 kB
assets/Load3dViewerContent-8oTYrH0q.js (new) 30.9 kB 🔴 +30.9 kB 🔴 +6.31 kB 🔴 +5.47 kB
assets/Load3dViewerContent-DYmifG7D.js (removed) 30.9 kB 🟢 -30.9 kB 🟢 -6.3 kB 🟢 -5.47 kB
assets/initHostTelemetry-CSWqm8Ft.js (new) 27.4 kB 🔴 +27.4 kB 🔴 +6.62 kB 🔴 +5.52 kB
assets/SubscriptionRequiredDialogContent-DUhquYOC.js (new) 27 kB 🔴 +27 kB 🔴 +6.68 kB 🔴 +5.89 kB
assets/SubscriptionRequiredDialogContent-CUWLzwlq.js (removed) 26.6 kB 🟢 -26.6 kB 🟢 -6.57 kB 🟢 -5.78 kB
assets/initHostTelemetry-GfHxFKxf.js (removed) 25 kB 🟢 -25 kB 🟢 -6.17 kB 🟢 -5.15 kB
assets/WidgetImageCrop-BWgHmkbk.js (removed) 23.3 kB 🟢 -23.3 kB 🟢 -5.75 kB 🟢 -5.04 kB
assets/WidgetImageCrop-CNJl3zKX.js (new) 23.3 kB 🔴 +23.3 kB 🔴 +5.75 kB 🔴 +5.04 kB
assets/SubscriptionPanelContentWorkspace-BRoDVljg.js (removed) 22.3 kB 🟢 -22.3 kB 🟢 -5.2 kB 🟢 -4.58 kB
assets/SubscriptionPanelContentWorkspace-BugFh3ym.js (new) 22.3 kB 🔴 +22.3 kB 🔴 +5.2 kB 🔴 +4.59 kB
assets/load3d-BD_1InAp.js (removed) 21.2 kB 🟢 -21.2 kB 🟢 -5.18 kB 🟢 -4.49 kB
assets/load3d-CmczOdvP.js (new) 21.2 kB 🔴 +21.2 kB 🔴 +5.18 kB 🔴 +4.5 kB
assets/CurrentUserPopoverWorkspace-CyYUn_4H.js (new) 20.6 kB 🔴 +20.6 kB 🔴 +4.7 kB 🔴 +4.2 kB
assets/CurrentUserPopoverWorkspace-RgKNI-Vd.js (removed) 20.6 kB 🟢 -20.6 kB 🟢 -4.7 kB 🟢 -4.21 kB
assets/SignInContent-BbMX523j.js (new) 19.9 kB 🔴 +19.9 kB 🔴 +5 kB 🔴 +4.35 kB
assets/SignInContent-C7bwc_IQ.js (removed) 19.9 kB 🟢 -19.9 kB 🟢 -4.99 kB 🟢 -4.36 kB
assets/Load3D-BY5HmWNc.js (removed) 19.1 kB 🟢 -19.1 kB 🟢 -4.51 kB 🟢 -3.94 kB
assets/Load3D-Dp-Ywh9Z.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.51 kB 🔴 +3.93 kB
assets/WidgetInputNumber-B9FS2LFf.js (new) 19 kB 🔴 +19 kB 🔴 +4.79 kB 🔴 +4.25 kB
assets/WidgetInputNumber-DRpow1pP.js (removed) 19 kB 🟢 -19 kB 🟢 -4.79 kB 🟢 -4.25 kB
assets/WidgetRecordAudio-D7csmJkU.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.63 kB 🟢 -4.14 kB
assets/WidgetRecordAudio-Dyvo-Xzx.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.63 kB 🔴 +4.14 kB
assets/WidgetRange-BGYiu-dP.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +4.17 kB 🔴 +3.73 kB
assets/WidgetRange-BZSkHuCM.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -4.17 kB 🟢 -3.73 kB
assets/WaveAudioPlayer-_UPQxN7l.js (new) 12.8 kB 🔴 +12.8 kB 🔴 +3.48 kB 🔴 +3.05 kB
assets/WaveAudioPlayer-BeNQ2qWK.js (removed) 12.8 kB 🟢 -12.8 kB 🟢 -3.48 kB 🟢 -3.06 kB
assets/WidgetCurve-BCE5h_EP.js (new) 11.3 kB 🔴 +11.3 kB 🔴 +3.51 kB 🔴 +3.18 kB
assets/WidgetCurve-BZQmPdkB.js (removed) 11.3 kB 🟢 -11.3 kB 🟢 -3.51 kB 🟢 -3.17 kB
assets/TeamWorkspacesDialogContent-3oKOIGKQ.js (new) 10.4 kB 🔴 +10.4 kB 🔴 +3.01 kB 🔴 +2.67 kB
assets/TeamWorkspacesDialogContent-Bi1pVBGG.js (removed) 10.4 kB 🟢 -10.4 kB 🟢 -3.01 kB 🟢 -2.67 kB
assets/Load3DConfiguration-CErBlOX9.js (new) 9.02 kB 🔴 +9.02 kB 🔴 +2.67 kB 🔴 +2.35 kB
assets/Load3DConfiguration-D4wsSsLd.js (removed) 9.02 kB 🟢 -9.02 kB 🟢 -2.67 kB 🟢 -2.35 kB
assets/nodeTemplates-BaxNu2Hx.js (new) 8.33 kB 🔴 +8.33 kB 🔴 +2.88 kB 🔴 +2.54 kB
assets/nodeTemplates-BLVSJkMg.js (removed) 8.33 kB 🟢 -8.33 kB 🟢 -2.88 kB 🟢 -2.54 kB
assets/onboardingCloudRoutes-8IuN7B67.js (new) 8.2 kB 🔴 +8.2 kB 🔴 +2.53 kB 🔴 +2.17 kB
assets/onboardingCloudRoutes-bOLEdnYm.js (removed) 8.2 kB 🟢 -8.2 kB 🟢 -2.54 kB 🟢 -2.19 kB
assets/NightlySurveyController-CGZV6Hym.js (new) 7.95 kB 🔴 +7.95 kB 🔴 +2.7 kB 🔴 +2.37 kB
assets/NightlySurveyController-JC4ZrIsY.js (removed) 7.95 kB 🟢 -7.95 kB 🟢 -2.7 kB 🟢 -2.4 kB
assets/InviteMemberDialogContent-B3T-AXQ9.js (new) 7.03 kB 🔴 +7.03 kB 🔴 +2.14 kB 🔴 +1.85 kB
assets/InviteMemberDialogContent-C-u3lkL1.js (removed) 7.03 kB 🟢 -7.03 kB 🟢 -2.13 kB 🟢 -1.85 kB
assets/WidgetWithControl-B6shof87.js (removed) 6.3 kB 🟢 -6.3 kB 🟢 -2.54 kB 🟢 -2.24 kB
assets/WidgetWithControl-DbtUCGvk.js (new) 6.3 kB 🔴 +6.3 kB 🔴 +2.54 kB 🔴 +2.23 kB
assets/load3dPreviewExtensions-BmUFI7xT.js (removed) 5.38 kB 🟢 -5.38 kB 🟢 -1.75 kB 🟢 -1.55 kB
assets/load3dPreviewExtensions-CYTiO19C.js (new) 5.38 kB 🔴 +5.38 kB 🔴 +1.75 kB 🔴 +1.55 kB
assets/CreateWorkspaceDialogContent-dCxlWrUU.js (removed) 5.19 kB 🟢 -5.19 kB 🟢 -1.83 kB 🟢 -1.59 kB
assets/CreateWorkspaceDialogContent-DoCQAx_8.js (new) 5.19 kB 🔴 +5.19 kB 🔴 +1.83 kB 🔴 +1.59 kB
assets/missingModelDownload-BXF64MOf.js (removed) 5.07 kB 🟢 -5.07 kB 🟢 -1.98 kB 🟢 -1.72 kB
assets/missingModelDownload-Cl0Osnzl.js (new) 5.07 kB 🔴 +5.07 kB 🔴 +1.98 kB 🔴 +1.72 kB
assets/FreeTierDialogContent-B0w_8EB4.js (new) 5.02 kB 🔴 +5.02 kB 🔴 +1.69 kB 🔴 +1.49 kB
assets/FreeTierDialogContent-D65i6FKn.js (removed) 5.02 kB 🟢 -5.02 kB 🟢 -1.69 kB 🟢 -1.49 kB
assets/EditWorkspaceDialogContent-1Mcnl3-e.js (new) 5 kB 🔴 +5 kB 🔴 +1.79 kB 🔴 +1.55 kB
assets/EditWorkspaceDialogContent-pKT7uJLK.js (removed) 5 kB 🟢 -5 kB 🟢 -1.79 kB 🟢 -1.56 kB
assets/WidgetTextarea-CghrBS_t.js (new) 4.86 kB 🔴 +4.86 kB 🔴 +1.89 kB 🔴 +1.67 kB
assets/WidgetTextarea-DZvblHRd.js (removed) 4.86 kB 🟢 -4.86 kB 🟢 -1.9 kB 🟢 -1.66 kB
assets/saveMesh-B_4NKYo4.js (removed) 4.79 kB 🟢 -4.79 kB 🟢 -1.55 kB 🟢 -1.36 kB
assets/saveMesh-Bne6hAAl.js (new) 4.79 kB 🔴 +4.79 kB 🔴 +1.54 kB 🔴 +1.36 kB
assets/Preview3d-B2zFDbYp.js (new) 4.59 kB 🔴 +4.59 kB 🔴 +1.43 kB 🔴 +1.23 kB
assets/Preview3d-C7Buhf7b.js (removed) 4.59 kB 🟢 -4.59 kB 🟢 -1.43 kB 🟢 -1.24 kB
assets/ValueControlPopover-3r5PPbCJ.js (removed) 4.55 kB 🟢 -4.55 kB 🟢 -1.59 kB 🟢 -1.41 kB
assets/ValueControlPopover-CF4gMjl0.js (new) 4.55 kB 🔴 +4.55 kB 🔴 +1.59 kB 🔴 +1.41 kB
assets/CancelSubscriptionDialogContent-DFyPyYPP.js (removed) 4.54 kB 🟢 -4.54 kB 🟢 -1.65 kB 🟢 -1.44 kB
assets/CancelSubscriptionDialogContent-DjqmNA2e.js (new) 4.54 kB 🔴 +4.54 kB 🔴 +1.65 kB 🔴 +1.44 kB
assets/tierBenefits-CHcaNg1K.js (removed) 4.46 kB 🟢 -4.46 kB 🟢 -1.58 kB 🟢 -1.37 kB
assets/tierBenefits-NWZ6tT6l.js (new) 4.46 kB 🔴 +4.46 kB 🔴 +1.58 kB 🔴 +1.37 kB
assets/DeleteWorkspaceDialogContent-D3FkElrA.js (removed) 3.91 kB 🟢 -3.91 kB 🟢 -1.47 kB 🟢 -1.27 kB
assets/DeleteWorkspaceDialogContent-Dd4EBYlD.js (new) 3.91 kB 🔴 +3.91 kB 🔴 +1.47 kB 🔴 +1.27 kB
assets/LeaveWorkspaceDialogContent-BvOmw-Mu.js (new) 3.73 kB 🔴 +3.73 kB 🔴 +1.42 kB 🔴 +1.22 kB
assets/LeaveWorkspaceDialogContent-uRdDDt0d.js (removed) 3.73 kB 🟢 -3.73 kB 🟢 -1.42 kB 🟢 -1.22 kB
assets/RemoveMemberDialogContent-BGy40BaF.js (new) 3.71 kB 🔴 +3.71 kB 🔴 +1.38 kB 🔴 +1.19 kB
assets/RemoveMemberDialogContent-DBfUmxUU.js (removed) 3.71 kB 🟢 -3.71 kB 🟢 -1.37 kB 🟢 -1.19 kB
assets/RevokeInviteDialogContent-uQmUEQIA.js (removed) 3.63 kB 🟢 -3.63 kB 🟢 -1.38 kB 🟢 -1.21 kB
assets/RevokeInviteDialogContent-xNgQACw5.js (new) 3.63 kB 🔴 +3.63 kB 🔴 +1.38 kB 🔴 +1.2 kB
assets/InviteMemberUpsellDialogContent-khQcDdDi.js (removed) 3.48 kB 🟢 -3.48 kB 🟢 -1.24 kB 🟢 -1.09 kB
assets/InviteMemberUpsellDialogContent-ubFzPe54.js (new) 3.48 kB 🔴 +3.48 kB 🔴 +1.24 kB 🔴 +1.07 kB
assets/Media3DTop-B8AHPJZf.js (removed) 3.26 kB 🟢 -3.26 kB 🟢 -1.3 kB 🟢 -1.13 kB
assets/Media3DTop-CAaZf2IL.js (new) 3.26 kB 🔴 +3.26 kB 🔴 +1.3 kB 🔴 +1.13 kB
assets/GlobalToast-B5pP0DDW.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.26 kB 🟢 -1.08 kB
assets/GlobalToast-DlyFw5Ti.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.26 kB 🔴 +1.08 kB
assets/load3dAdvanced-CJxVhoTc.js (new) 2.85 kB 🔴 +2.85 kB 🔴 +1.12 kB 🔴 +973 B
assets/load3dAdvanced-CK8zyWt4.js (removed) 2.85 kB 🟢 -2.85 kB 🟢 -1.12 kB 🟢 -973 B
assets/SubscribeToRun-CcKvWKkG.js (new) 2.69 kB 🔴 +2.69 kB 🔴 +1.15 kB 🔴 +1.02 kB
assets/SubscribeToRun-CHe0FnpE.js (removed) 2.53 kB 🟢 -2.53 kB 🟢 -1.1 kB 🟢 -979 B
assets/graphHasMissingNodes-b0fSdPVm.js (new) 1.93 kB 🔴 +1.93 kB 🔴 +907 B 🔴 +793 B
assets/graphHasMissingNodes-Culjbh8l.js (removed) 1.93 kB 🟢 -1.93 kB 🟢 -908 B 🟢 -790 B
assets/MediaAudioTop-Bigbp05b.js (removed) 1.67 kB 🟢 -1.67 kB 🟢 -838 B 🟢 -691 B
assets/MediaAudioTop-DEnKw1eL.js (new) 1.67 kB 🔴 +1.67 kB 🔴 +837 B 🔴 +692 B
assets/CloudRunButtonWrapper-CjYuwkG8.js (new) 1.13 kB 🔴 +1.13 kB 🔴 +550 B 🔴 +514 B
assets/CloudRunButtonWrapper-yFvQYjV5.js (removed) 1.13 kB 🟢 -1.13 kB 🟢 -549 B 🟢 -522 B
assets/cloudSessionCookie-DQ8Q2waW.js (removed) 991 B 🟢 -991 B 🟢 -467 B 🟢 -396 B
assets/cloudSessionCookie-tgERxqK1.js (new) 991 B 🔴 +991 B 🔴 +468 B 🔴 +412 B
assets/cloudBadges-BZ8gQ30z.js (removed) 973 B 🟢 -973 B 🟢 -551 B 🟢 -470 B
assets/cloudBadges-DkBHwnk6.js (new) 973 B 🔴 +973 B 🔴 +551 B 🔴 +476 B
assets/Load3DAdvanced-1LKma4b8.js (new) 813 B 🔴 +813 B 🔴 +455 B 🔴 +405 B
assets/Load3DAdvanced-CgwyIhJ0.js (removed) 813 B 🟢 -813 B 🟢 -456 B 🟢 -411 B
assets/nightlyBadges-BIyTa-Lx.js (removed) 464 B 🟢 -464 B 🟢 -306 B 🟢 -255 B
assets/nightlyBadges-Cm1BHLRJ.js (new) 464 B 🔴 +464 B 🔴 +306 B 🔴 +254 B
assets/missingModelDownload-2zwoqnUK.js (new) 228 B 🔴 +228 B 🔴 +147 B 🔴 +129 B
assets/missingModelDownload-DTf_tsPY.js (removed) 228 B 🟢 -228 B 🟢 -150 B 🟢 -131 B
assets/SubscriptionPanelContentWorkspace-C76u54TP.js (new) 179 B 🔴 +179 B 🔴 +117 B 🔴 +106 B
assets/SubscriptionPanelContentWorkspace-DxabvCjP.js (removed) 179 B 🟢 -179 B 🟢 -117 B 🟢 -90 B
assets/Load3dViewerContent-DqmJzX-0.js (removed) 137 B 🟢 -137 B 🟢 -103 B 🟢 -95 B
assets/Load3dViewerContent-wVtVjs8I.js (new) 137 B 🔴 +137 B 🔴 +103 B 🔴 +92 B
assets/Load3DAdvanced-DH1Sf_uI.js (removed) 122 B 🟢 -122 B 🟢 -97 B 🟢 -90 B
assets/Load3DAdvanced-WWNf3MT5.js (new) 122 B 🔴 +122 B 🔴 +97 B 🔴 +100 B
assets/WidgetLegacy-CTqqHrBL.js (new) 119 B 🔴 +119 B 🔴 +108 B 🔴 +93 B
assets/WidgetLegacy-DEMmnBvF.js (removed) 119 B 🟢 -119 B 🟢 -108 B 🟢 -93 B
assets/workflowDraftStoreV2-BiEPO57I.js (new) 113 B 🔴 +113 B 🔴 +105 B 🔴 +114 B
assets/workflowDraftStoreV2-Dclufi7_.js (removed) 113 B 🟢 -113 B 🟢 -105 B 🟢 -117 B
assets/Load3D-CA37o6YF.js (new) 98 B 🔴 +98 B 🔴 +89 B 🔴 +79 B
assets/Load3D-D-husn-w.js (removed) 98 B 🟢 -98 B 🟢 -89 B 🟢 -83 B
assets/changeTracker-C0ssG0Gr.js (new) 93 B 🔴 +93 B 🔴 +95 B 🔴 +81 B
assets/changeTracker-U8Jk_axR.js (removed) 93 B 🟢 -93 B 🟢 -95 B 🟢 -81 B

Status: 62 added / 62 removed / 88 unchanged

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 53.8 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 49.0 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 57.7 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 62.9 MB heap
large-graph-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.5 MB heap
large-graph-pan: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 71.0 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 66.2 MB heap
minimap-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.3 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 63.8 MB heap
subgraph-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 53.7 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 54.4 MB heap
subgraph-transition-enter: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 158ms TBT · 76.6 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 68.6 MB heap
vue-large-graph-idle: · 58.1 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 159.4 MB heap
vue-large-graph-pan: · 58.1 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 160.3 MB heap
workflow-execution: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 62.2 MB heap

⚠️ 1 regression detected

Show regressions
Metric Baseline PR (median) Δ Sig
large-graph-pan: style recalc duration 19ms 19ms +2% ⚠️ z=2.5
All metrics
Metric Baseline PR (median) Δ Sig
canvas-idle: avg frame time 17ms 17ms +0% z=-0.5
canvas-idle: p95 frame time 17ms 17ms +0%
canvas-idle: layout duration 0ms 0ms +0%
canvas-idle: style recalc duration 10ms 8ms -11% z=-2.6
canvas-idle: layout count 0 0 +0%
canvas-idle: style recalc count 9 9 -6% z=-4.7
canvas-idle: task duration 387ms 394ms +2% z=-0.0
canvas-idle: script duration 18ms 21ms +18% z=-2.0
canvas-idle: TBT 0ms 0ms +0%
canvas-idle: heap used 53.7 MB 53.8 MB +0%
canvas-idle: DOM nodes 18 17 -6% z=-4.4
canvas-idle: event listeners 4 4 +0% z=-1.6
canvas-mouse-sweep: avg frame time 17ms 17ms +0% z=-0.4
canvas-mouse-sweep: p95 frame time 17ms 17ms +1%
canvas-mouse-sweep: layout duration 4ms 4ms +4% z=0.5
canvas-mouse-sweep: style recalc duration 36ms 42ms +15% z=-0.2
canvas-mouse-sweep: layout count 12 12 +0%
canvas-mouse-sweep: style recalc count 73 76 +3% z=-1.4
canvas-mouse-sweep: task duration 784ms 824ms +5% z=-0.7
canvas-mouse-sweep: script duration 130ms 126ms -3% z=-1.5
canvas-mouse-sweep: TBT 0ms 0ms +0%
canvas-mouse-sweep: heap used 48.4 MB 49.0 MB +1%
canvas-mouse-sweep: DOM nodes 55 59 +6% z=-1.5
canvas-mouse-sweep: event listeners 4 4 +0% z=-1.1
canvas-zoom-sweep: avg frame time 17ms 17ms -0% z=-0.3
canvas-zoom-sweep: p95 frame time 17ms 17ms -1%
canvas-zoom-sweep: layout duration 1ms 1ms -1% z=0.8
canvas-zoom-sweep: style recalc duration 18ms 20ms +11% z=0.5
canvas-zoom-sweep: layout count 6 6 +0%
canvas-zoom-sweep: style recalc count 33 31 -6% z=-0.6
canvas-zoom-sweep: task duration 317ms 357ms +13% z=1.3
canvas-zoom-sweep: script duration 21ms 26ms +25% z=-0.3
canvas-zoom-sweep: TBT 0ms 0ms +0%
canvas-zoom-sweep: heap used 57.4 MB 57.7 MB +1%
canvas-zoom-sweep: DOM nodes 77 78 +1% z=-1.6
canvas-zoom-sweep: event listeners 19 19 +0% z=-0.9
dom-widget-clipping: avg frame time 17ms 17ms +0% z=0.1
dom-widget-clipping: p95 frame time 17ms 17ms -0%
dom-widget-clipping: layout duration 0ms 0ms +0%
dom-widget-clipping: style recalc duration 9ms 8ms -16% z=-2.8
dom-widget-clipping: layout count 0 0 +0%
dom-widget-clipping: style recalc count 13 11 -15% z=-4.2
dom-widget-clipping: task duration 352ms 337ms -4% z=-1.7
dom-widget-clipping: script duration 64ms 57ms -10% z=-3.3
dom-widget-clipping: TBT 0ms 0ms +0%
dom-widget-clipping: heap used 62.6 MB 62.9 MB +1%
dom-widget-clipping: DOM nodes 22 18 -18% z=-2.9
dom-widget-clipping: event listeners 0 1 variance too high
large-graph-idle: avg frame time 17ms 17ms +0% z=0.2
large-graph-idle: p95 frame time 17ms 17ms +0%
large-graph-idle: layout duration 0ms 0ms +0%
large-graph-idle: style recalc duration 10ms 10ms +5% z=-2.1
large-graph-idle: layout count 0 0 +0%
large-graph-idle: style recalc count 10 11 +5% z=-3.5
large-graph-idle: task duration 555ms 573ms +3% z=0.6
large-graph-idle: script duration 102ms 112ms +10% z=0.9
large-graph-idle: TBT 0ms 0ms +0%
large-graph-idle: heap used 59.8 MB 65.5 MB +9%
large-graph-idle: DOM nodes 20 21 +5% z=-4.1
large-graph-idle: event listeners 4 6 +50% z=-3.3
large-graph-pan: avg frame time 17ms 17ms -0% z=0.3
large-graph-pan: p95 frame time 17ms 17ms -0%
large-graph-pan: layout duration 0ms 0ms +0%
large-graph-pan: style recalc duration 19ms 19ms +2% ⚠️ z=2.5
large-graph-pan: layout count 0 0 +0%
large-graph-pan: style recalc count 69 70 +1% z=-0.1
large-graph-pan: task duration 1093ms 1157ms +6% z=1.7
large-graph-pan: script duration 401ms 423ms +6% z=0.7
large-graph-pan: TBT 0ms 0ms +0%
large-graph-pan: heap used 78.8 MB 71.0 MB -10%
large-graph-pan: DOM nodes 16 -124 -872% z=-86.4
large-graph-pan: event listeners 6 -62 -1133% z=-80.8
large-graph-zoom: avg frame time 17ms 17ms +0%
large-graph-zoom: p95 frame time 17ms 17ms +0%
large-graph-zoom: layout duration 8ms 8ms -1%
large-graph-zoom: style recalc duration 20ms 20ms -1%
large-graph-zoom: layout count 60 60 +0%
large-graph-zoom: style recalc count 65 65 +0%
large-graph-zoom: task duration 1320ms 1383ms +5%
large-graph-zoom: script duration 493ms 522ms +6%
large-graph-zoom: TBT 0ms 0ms +0%
large-graph-zoom: heap used 65.3 MB 66.2 MB +1%
large-graph-zoom: DOM nodes 14 13 -7%
large-graph-zoom: event listeners 8 8 +0%
minimap-idle: avg frame time 17ms 17ms -0% z=0.1
minimap-idle: p95 frame time 17ms 17ms -0%
minimap-idle: layout duration 0ms 0ms +0%
minimap-idle: style recalc duration 9ms 9ms -3% z=-0.9
minimap-idle: layout count 0 0 +0%
minimap-idle: style recalc count 9 9 +0% z=-0.8
minimap-idle: task duration 534ms 614ms +15% z=1.8
minimap-idle: script duration 101ms 112ms +12% z=1.4
minimap-idle: TBT 0ms 0ms +0%
minimap-idle: heap used 61.4 MB 61.3 MB -0%
minimap-idle: DOM nodes 18 18 +0% z=-0.8
minimap-idle: event listeners 6 6 +0% z=2.2
subgraph-dom-widget-clipping: avg frame time 17ms 17ms +0% z=0.1
subgraph-dom-widget-clipping: p95 frame time 17ms 17ms +0%
subgraph-dom-widget-clipping: layout duration 0ms 0ms +0%
subgraph-dom-widget-clipping: style recalc duration 12ms 12ms +1% z=-0.7
subgraph-dom-widget-clipping: layout count 0 0 +0%
subgraph-dom-widget-clipping: style recalc count 48 48 +0% z=0.1
subgraph-dom-widget-clipping: task duration 364ms 391ms +7% z=0.7
subgraph-dom-widget-clipping: script duration 120ms 127ms +6% z=-0.2
subgraph-dom-widget-clipping: TBT 0ms 0ms +0%
subgraph-dom-widget-clipping: heap used 63.4 MB 63.8 MB +1%
subgraph-dom-widget-clipping: DOM nodes 22 22 +0% z=-0.2
subgraph-dom-widget-clipping: event listeners 6 6 +0% z=-1.7
subgraph-idle: avg frame time 17ms 17ms -0% z=-0.2
subgraph-idle: p95 frame time 17ms 17ms +0%
subgraph-idle: layout duration 0ms 0ms +0%
subgraph-idle: style recalc duration 10ms 9ms -9% z=-2.0
subgraph-idle: layout count 0 0 +0%
subgraph-idle: style recalc count 10 10 -5% z=-2.1
subgraph-idle: task duration 373ms 407ms +9% z=1.2
subgraph-idle: script duration 19ms 21ms +8% z=0.2
subgraph-idle: TBT 0ms 0ms +0%
subgraph-idle: heap used 53.9 MB 53.7 MB -0%
subgraph-idle: DOM nodes 20 19 -5% z=-1.9
subgraph-idle: event listeners 4 4 +0% variance too high
subgraph-mouse-sweep: avg frame time 17ms 17ms +0% z=0.4
subgraph-mouse-sweep: p95 frame time 17ms 17ms -0%
subgraph-mouse-sweep: layout duration 4ms 4ms +4% z=-0.7
subgraph-mouse-sweep: style recalc duration 38ms 37ms -1% z=-1.6
subgraph-mouse-sweep: layout count 16 16 +0%
subgraph-mouse-sweep: style recalc count 76 76 -1% z=-2.4
subgraph-mouse-sweep: task duration 683ms 697ms +2% z=-1.0
subgraph-mouse-sweep: script duration 97ms 95ms -2% z=-0.9
subgraph-mouse-sweep: TBT 0ms 0ms +0%
subgraph-mouse-sweep: heap used 46.0 MB 54.4 MB +18%
subgraph-mouse-sweep: DOM nodes 65 62 -5% z=-2.2
subgraph-mouse-sweep: event listeners 4 4 +0% variance too high
subgraph-transition-enter: avg frame time 17ms 17ms +0%
subgraph-transition-enter: p95 frame time 17ms 17ms +1%
subgraph-transition-enter: layout duration 14ms 14ms -3%
subgraph-transition-enter: style recalc duration 28ms 28ms -2%
subgraph-transition-enter: layout count 4 4 +0%
subgraph-transition-enter: style recalc count 16 17 +6%
subgraph-transition-enter: task duration 724ms 817ms +13%
subgraph-transition-enter: script duration 29ms 40ms +41%
subgraph-transition-enter: TBT 159ms 158ms -1%
subgraph-transition-enter: heap used 76.2 MB 76.6 MB +1%
subgraph-transition-enter: DOM nodes 13833 13833 +0%
subgraph-transition-enter: event listeners 2527 2529 +0%
viewport-pan-sweep: avg frame time 17ms 17ms +0%
viewport-pan-sweep: p95 frame time 17ms 17ms -1%
viewport-pan-sweep: layout duration 0ms 0ms +0%
viewport-pan-sweep: style recalc duration 56ms 57ms +1%
viewport-pan-sweep: layout count 0 0 +0%
viewport-pan-sweep: style recalc count 251 252 +0%
viewport-pan-sweep: task duration 3853ms 4124ms +7%
viewport-pan-sweep: script duration 1275ms 1408ms +10%
viewport-pan-sweep: TBT 0ms 0ms +0%
viewport-pan-sweep: heap used 64.4 MB 68.6 MB +6%
viewport-pan-sweep: DOM nodes 20 21 +5%
viewport-pan-sweep: event listeners 20 21 +5%
vue-large-graph-idle: avg frame time 17ms 17ms +0%
vue-large-graph-idle: p95 frame time 17ms 17ms +0%
vue-large-graph-idle: layout duration 3ms 0ms -100%
vue-large-graph-idle: style recalc duration 2ms 0ms -100%
vue-large-graph-idle: layout count 1 0 -100%
vue-large-graph-idle: style recalc count 1 0 -100%
vue-large-graph-idle: task duration 12952ms 12869ms -1%
vue-large-graph-idle: script duration 644ms 626ms -3%
vue-large-graph-idle: TBT 942ms 0ms -100%
vue-large-graph-idle: heap used 161.9 MB 159.4 MB -2%
vue-large-graph-idle: DOM nodes -3308 -5821 +76%
vue-large-graph-idle: event listeners -16472 -16471 -0%
vue-large-graph-pan: avg frame time 18ms 17ms -3%
vue-large-graph-pan: p95 frame time 17ms 17ms -0%
vue-large-graph-pan: layout duration 0ms 0ms +0%
vue-large-graph-pan: style recalc duration 18ms 18ms +0%
vue-large-graph-pan: layout count 0 0 +0%
vue-large-graph-pan: style recalc count 71 69 -4%
vue-large-graph-pan: task duration 14948ms 14853ms -1%
vue-large-graph-pan: script duration 876ms 894ms +2%
vue-large-graph-pan: TBT 0ms 0ms +0%
vue-large-graph-pan: heap used 165.6 MB 160.3 MB -3%
vue-large-graph-pan: DOM nodes -3308 -5837 +76%
vue-large-graph-pan: event listeners -16470 -16494 +0%
workflow-execution: avg frame time 17ms 17ms +0% z=0.6
workflow-execution: p95 frame time 17ms 17ms -0%
workflow-execution: layout duration 1ms 2ms +11% z=-0.2
workflow-execution: style recalc duration 26ms 23ms -10% z=-0.5
workflow-execution: layout count 5 5 +0% z=0.1
workflow-execution: style recalc count 20 17 -15% z=-0.4
workflow-execution: task duration 136ms 122ms -10% z=-0.1
workflow-execution: script duration 19ms 21ms +10% z=-2.7
workflow-execution: TBT 0ms 0ms +0%
workflow-execution: heap used 52.4 MB 62.2 MB +19%
workflow-execution: DOM nodes 159 162 +2% z=0.1
workflow-execution: event listeners 69 69 +0% z=3.9
Historical variance (last 15 runs)
Metric μ σ CV
canvas-idle: avg frame time 17ms 0ms 0.0%
canvas-idle: layout duration 0ms 0ms 0.0%
canvas-idle: style recalc duration 11ms 1ms 8.2%
canvas-idle: layout count 0 0 0.0%
canvas-idle: style recalc count 11 1 5.0%
canvas-idle: task duration 395ms 31ms 7.9%
canvas-idle: script duration 25ms 2ms 8.8%
canvas-idle: TBT 0ms 0ms 0.0%
canvas-idle: DOM nodes 23 1 5.6%
canvas-idle: event listeners 12 5 40.9%
canvas-mouse-sweep: avg frame time 17ms 0ms 0.0%
canvas-mouse-sweep: layout duration 4ms 0ms 5.4%
canvas-mouse-sweep: style recalc duration 43ms 3ms 7.4%
canvas-mouse-sweep: layout count 12 0 0.0%
canvas-mouse-sweep: style recalc count 79 2 3.0%
canvas-mouse-sweep: task duration 865ms 58ms 6.7%
canvas-mouse-sweep: script duration 136ms 6ms 4.8%
canvas-mouse-sweep: TBT 0ms 0ms 0.0%
canvas-mouse-sweep: DOM nodes 62 3 4.2%
canvas-mouse-sweep: event listeners 8 4 49.4%
canvas-zoom-sweep: avg frame time 17ms 0ms 0.0%
canvas-zoom-sweep: layout duration 1ms 0ms 7.0%
canvas-zoom-sweep: style recalc duration 19ms 2ms 8.0%
canvas-zoom-sweep: layout count 6 0 0.0%
canvas-zoom-sweep: style recalc count 31 0 1.5%
canvas-zoom-sweep: task duration 327ms 23ms 7.1%
canvas-zoom-sweep: script duration 27ms 3ms 11.1%
canvas-zoom-sweep: TBT 0ms 0ms 0.0%
canvas-zoom-sweep: DOM nodes 79 1 1.0%
canvas-zoom-sweep: event listeners 24 5 21.8%
dom-widget-clipping: avg frame time 17ms 0ms 0.0%
dom-widget-clipping: layout duration 0ms 0ms 0.0%
dom-widget-clipping: style recalc duration 10ms 1ms 8.0%
dom-widget-clipping: layout count 0 0 0.0%
dom-widget-clipping: style recalc count 13 0 3.8%
dom-widget-clipping: task duration 365ms 16ms 4.5%
dom-widget-clipping: script duration 68ms 3ms 4.8%
dom-widget-clipping: TBT 0ms 0ms 0.0%
dom-widget-clipping: DOM nodes 22 1 6.4%
dom-widget-clipping: event listeners 8 6 81.2%
large-graph-idle: avg frame time 17ms 0ms 0.0%
large-graph-idle: layout duration 0ms 0ms 0.0%
large-graph-idle: style recalc duration 12ms 1ms 8.6%
large-graph-idle: layout count 0 0 0.0%
large-graph-idle: style recalc count 12 0 2.7%
large-graph-idle: task duration 542ms 54ms 10.0%
large-graph-idle: script duration 102ms 11ms 10.3%
large-graph-idle: TBT 0ms 0ms 0.0%
large-graph-idle: DOM nodes 25 1 3.7%
large-graph-idle: event listeners 26 6 23.2%
large-graph-pan: avg frame time 17ms 0ms 0.0%
large-graph-pan: layout duration 0ms 0ms 0.0%
large-graph-pan: style recalc duration 17ms 1ms 4.6%
large-graph-pan: layout count 0 0 0.0%
large-graph-pan: style recalc count 70 1 0.9%
large-graph-pan: task duration 1082ms 43ms 4.0%
large-graph-pan: script duration 408ms 20ms 4.8%
large-graph-pan: TBT 0ms 0ms 0.0%
large-graph-pan: DOM nodes 19 2 8.7%
large-graph-pan: event listeners 5 1 16.8%
minimap-idle: avg frame time 17ms 0ms 0.0%
minimap-idle: layout duration 0ms 0ms 0.0%
minimap-idle: style recalc duration 10ms 1ms 8.6%
minimap-idle: layout count 0 0 0.0%
minimap-idle: style recalc count 10 1 7.1%
minimap-idle: task duration 527ms 47ms 9.0%
minimap-idle: script duration 98ms 10ms 10.1%
minimap-idle: TBT 0ms 0ms 0.0%
minimap-idle: DOM nodes 19 1 7.1%
minimap-idle: event listeners 5 1 14.4%
subgraph-dom-widget-clipping: avg frame time 17ms 0ms 0.0%
subgraph-dom-widget-clipping: layout duration 0ms 0ms 0.0%
subgraph-dom-widget-clipping: style recalc duration 13ms 1ms 7.4%
subgraph-dom-widget-clipping: layout count 0 0 0.0%
subgraph-dom-widget-clipping: style recalc count 48 1 1.2%
subgraph-dom-widget-clipping: task duration 378ms 18ms 4.9%
subgraph-dom-widget-clipping: script duration 128ms 6ms 4.9%
subgraph-dom-widget-clipping: TBT 0ms 0ms 0.0%
subgraph-dom-widget-clipping: DOM nodes 22 1 5.0%
subgraph-dom-widget-clipping: event listeners 16 6 36.0%
subgraph-idle: avg frame time 17ms 0ms 0.0%
subgraph-idle: layout duration 0ms 0ms 0.0%
subgraph-idle: style recalc duration 10ms 1ms 7.5%
subgraph-idle: layout count 0 0 0.0%
subgraph-idle: style recalc count 11 1 6.0%
subgraph-idle: task duration 370ms 31ms 8.5%
subgraph-idle: script duration 20ms 3ms 13.2%
subgraph-idle: TBT 0ms 0ms 0.0%
subgraph-idle: DOM nodes 22 1 6.9%
subgraph-idle: event listeners 10 7 64.5%
subgraph-mouse-sweep: avg frame time 17ms 0ms 0.0%
subgraph-mouse-sweep: layout duration 5ms 0ms 6.8%
subgraph-mouse-sweep: style recalc duration 42ms 3ms 7.8%
subgraph-mouse-sweep: layout count 16 0 0.0%
subgraph-mouse-sweep: style recalc count 80 2 2.4%
subgraph-mouse-sweep: task duration 766ms 69ms 9.0%
subgraph-mouse-sweep: script duration 101ms 7ms 6.5%
subgraph-mouse-sweep: TBT 0ms 0ms 0.0%
subgraph-mouse-sweep: DOM nodes 67 2 3.3%
subgraph-mouse-sweep: event listeners 8 4 52.6%
workflow-execution: avg frame time 17ms 0ms 0.0%
workflow-execution: layout duration 2ms 0ms 9.4%
workflow-execution: style recalc duration 24ms 2ms 9.1%
workflow-execution: layout count 5 1 11.0%
workflow-execution: style recalc count 18 2 11.5%
workflow-execution: task duration 123ms 11ms 8.8%
workflow-execution: script duration 29ms 3ms 10.2%
workflow-execution: TBT 0ms 0ms 0.0%
workflow-execution: DOM nodes 161 7 4.4%
workflow-execution: event listeners 52 4 8.4%
Trend (last 15 commits on main)
Metric Trend Dir Latest
canvas-idle: avg frame time ▆▃▆▁▆▃▆█▆▆▄▃▃▄▃ ➡️ 17ms
canvas-idle: p95 frame time ➡️ NaNms
canvas-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: style recalc duration ▇▇▆▆▃█▄▃▄▃▇▄▁▆▇ ➡️ 11ms
canvas-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
canvas-idle: style recalc count █▃▅▂▅▆▃▁▂▁▂▅▆▅▆ ➡️ 12
canvas-idle: task duration ▃▃▃▆▂▃▃▅▆▂█▃▁▃▃ ➡️ 391ms
canvas-idle: script duration ▄▃▅▇▂▅▃▆▇▅█▄▁▅▆ ➡️ 27ms
canvas-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: heap used ➡️ NaN MB
canvas-idle: DOM nodes █▇▆▅▃▇▃▁▂▂▅▆▆▆▇ ➡️ 24
canvas-idle: event listeners ▅█▅▄▁▅▁▁▁▄▅▅▁▅▄ 📉 11
canvas-mouse-sweep: avg frame time ▆█▆▃▁▃▁▆▆▁▃▆▆▃▃ ➡️ 17ms
canvas-mouse-sweep: p95 frame time ➡️ NaNms
canvas-mouse-sweep: layout duration ▁▃▂▄▁▂▁▃▆▂█▇▆▄▃ ➡️ 4ms
canvas-mouse-sweep: style recalc duration ▄▄▂▄▁▂▃▃▅▄█▆▂▄▄ ➡️ 43ms
canvas-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 12
canvas-mouse-sweep: style recalc count █▅▄▃▂▂▁▄▄▅▆▅▂▇▄ ➡️ 79
canvas-mouse-sweep: task duration █▆▄▂▂▃▂▄▄▅█▆▁▆▄ ➡️ 868ms
canvas-mouse-sweep: script duration ▄▅▄▆▄▆▆▆▅▅█▆▁▅▆ ➡️ 139ms
canvas-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-mouse-sweep: heap used ➡️ NaN MB
canvas-mouse-sweep: DOM nodes █▅▃▃▁▂▂▃▂▄▆▅▃▅▅ ➡️ 64
canvas-mouse-sweep: event listeners █▁▁▁▁▁▇▁▁▁██▇▁█ 📈 13
canvas-zoom-sweep: avg frame time ▅▅█▄▅▁▁▁▅▁▁▅▄▅▁ ➡️ 17ms
canvas-zoom-sweep: p95 frame time ➡️ NaNms
canvas-zoom-sweep: layout duration ▆▅▅▄▁▁█▅▃▅▇▆▁▂▆ ➡️ 1ms
canvas-zoom-sweep: style recalc duration ▆▅▄▆▅▃█▆▇▅▇▄▁▃▅ ➡️ 20ms
canvas-zoom-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 6
canvas-zoom-sweep: style recalc count ▁▁▃▄▆▃▆█▄▄▆▁▆▁▆ ➡️ 32
canvas-zoom-sweep: task duration ▄▂▁▇▂▂▄▅▆▃█▄▁▁▅ ➡️ 338ms
canvas-zoom-sweep: script duration ▃▃▂▇▂▂▅▇▆▅█▄▁▂▆ ➡️ 30ms
canvas-zoom-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-zoom-sweep: heap used ➡️ NaN MB
canvas-zoom-sweep: DOM nodes ▄▃▁▅█▁▃▆▄▅▅▃▃▄▃ ➡️ 79
canvas-zoom-sweep: event listeners ▁▁▂▅█▂▁▅▁▅▅▄▁▅▁ ➡️ 19
dom-widget-clipping: avg frame time ▂▄▅▅▂▄█▇▅▇▇▅▅▁▇ ➡️ 17ms
dom-widget-clipping: p95 frame time ➡️ NaNms
dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: style recalc duration ▆▆▂▆▄▃██▄▁▆▇▆▃▅ ➡️ 10ms
dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
dom-widget-clipping: style recalc count ▇█▅█▅▄█▇▇▁▇▄▇▂▅ ➡️ 13
dom-widget-clipping: task duration ▃▃▁▅▄▃▅▆▅▂▇█▁▅▅ ➡️ 371ms
dom-widget-clipping: script duration ▅▄▄▆▆▅▇▇▆▃█▇▁▇▇ ➡️ 71ms
dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: heap used ➡️ NaN MB
dom-widget-clipping: DOM nodes ▇▇▄▇▅▄█▇▅▁▅▄▇▃▄ ➡️ 21
dom-widget-clipping: event listeners ▅▅▅▅▁▅██▁▁▁▁█▁▁ 📉 2
large-graph-idle: avg frame time ▅▅▅▅▅▂▁▂▄▅▄▂▂▅█ ➡️ 17ms
large-graph-idle: p95 frame time ➡️ NaNms
large-graph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: style recalc duration ▅▅▅▆▄▅▃▄▅▅▆█▁▄▆ ➡️ 13ms
large-graph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-idle: style recalc count █▆█▃▃▁▃▆▃▆▆▃▆██ ➡️ 12
large-graph-idle: task duration ▂▃▂▆▂▃▃▇▅▃██▁▂▅ ➡️ 569ms
large-graph-idle: script duration ▄▅▄▆▄▅▅▇▆▅█▆▁▃▆ ➡️ 110ms
large-graph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: heap used ➡️ NaN MB
large-graph-idle: DOM nodes ▆█▅▂▅▃▁▂▃▅▅▆▂▆▅ ➡️ 25
large-graph-idle: event listeners ███▇██▄▁▄▇▇█▂█▇ ➡️ 29
large-graph-pan: avg frame time ▆▃▃▆█▃▁█▆▆▆▆█▁▆ ➡️ 17ms
large-graph-pan: p95 frame time ➡️ NaNms
large-graph-pan: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: style recalc duration ▃▂▄▄▁▅▂▂▁▄▄█▃▁▂ ➡️ 17ms
large-graph-pan: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-pan: style recalc count ▆▃█▂▃▂▂▂▁▇▅▃█▆▃ ➡️ 69
large-graph-pan: task duration ▄▃▄▆▄▄▄▆▄▄█▆▁▂▅ ➡️ 1100ms
large-graph-pan: script duration ▅▄▅▆▆▅▄▆▄▅█▄▁▄▅ ➡️ 413ms
large-graph-pan: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: heap used ➡️ NaN MB
large-graph-pan: DOM nodes ▅▃▆▂▄▁▃▁▁▅▁▂█▅▂ ➡️ 18
large-graph-pan: event listeners █▆█▁▁▆▁▁▃▆▁▃██▃ ➡️ 5
minimap-idle: avg frame time ▃▆▆▃█▁█▆▆▃▃▆█▆█ ➡️ 17ms
minimap-idle: p95 frame time ➡️ NaNms
minimap-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: style recalc duration ▄█▁█▅▅█▅▅▃▅▁▁▄▆ ➡️ 10ms
minimap-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
minimap-idle: style recalc count ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 9
minimap-idle: task duration ▃▄▁▅▁▃▄▅▇▃█▅▁▁▅ ➡️ 547ms
minimap-idle: script duration ▄▆▃▇▃▅▆▆▇▅█▅▁▃▆ ➡️ 106ms
minimap-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: heap used ➡️ NaN MB
minimap-idle: DOM nodes ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 19
minimap-idle: event listeners ▃▃▆▁▁▁▃▁▁▆▁▃█▆▁ ➡️ 4
subgraph-dom-widget-clipping: avg frame time ▅▄▄▄▄▄█▄▄▄▃▁▆▃▃ ➡️ 17ms
subgraph-dom-widget-clipping: p95 frame time ➡️ NaNms
subgraph-dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: style recalc duration ▂▄▃▅▅▃▂▅▇▃▄█▁▄▆ ➡️ 14ms
subgraph-dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-dom-widget-clipping: style recalc count ▇█▆▃▆▃▁▆█▇▃▆▇█▅ ➡️ 48
subgraph-dom-widget-clipping: task duration ▂▃▃▆▅▅▂▅█▂▆█▁▂▇ ➡️ 398ms
subgraph-dom-widget-clipping: script duration ▃▃▃▄▅▅▂▄█▂▅▇▁▂▅ ➡️ 131ms
subgraph-dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: heap used ➡️ NaN MB
subgraph-dom-widget-clipping: DOM nodes ▅▇▅▂▅▂▁▅▅▅▁▇▅█▄ ➡️ 22
subgraph-dom-widget-clipping: event listeners ▅▅▅▂▅▁▅██▁▁█▅█▅ 📈 16
subgraph-idle: avg frame time ▆▆█▁▆▃▆▆▆▃▆▁▃▆█ ➡️ 17ms
subgraph-idle: p95 frame time ➡️ NaNms
subgraph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: style recalc duration ▁▇▃▆▂▄▂▃▃▆▆▄▃▇█ ➡️ 12ms
subgraph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-idle: style recalc count ▃▆▃▃▂▅▁▂▁▆▃▃██▇ ➡️ 12
subgraph-idle: task duration ▁▃▁▇▁▁▃▆▅▂█▅▁▁▄ ➡️ 378ms
subgraph-idle: script duration ▁▃▂▇▁▂▃▇▆▂█▅▂▁▅ ➡️ 22ms
subgraph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: heap used ➡️ NaN MB
subgraph-idle: DOM nodes ▃▅▃▂▁▄▁▂▁▅▃▂▇█▇ ➡️ 24
subgraph-idle: event listeners ▁▅▁▁▁▁▁▁▁▅▄▁███ 📈 21
subgraph-mouse-sweep: avg frame time ▅▄▁▃▃▄▆▄▆▃▃█▁▃▃ ➡️ 17ms
subgraph-mouse-sweep: p95 frame time ➡️ NaNms
subgraph-mouse-sweep: layout duration ▁▄▄▄▃▃▅▅▅▂█▇▂▃▆ ➡️ 5ms
subgraph-mouse-sweep: style recalc duration ▃▂▄▅▂▃▄▅█▃█▆▁▂▅ ➡️ 43ms
subgraph-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 16
subgraph-mouse-sweep: style recalc count ▅▂▅▅▁▄▃▅█▅▆▄▂▄▅ ➡️ 81
subgraph-mouse-sweep: task duration ▃▂▄▅▂▄▄▅▇▄█▆▁▃▅ ➡️ 785ms
subgraph-mouse-sweep: script duration ▄▅▄▇▅▅▆▇▆▅██▁▄▆ ➡️ 105ms
subgraph-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-mouse-sweep: heap used ➡️ NaN MB
subgraph-mouse-sweep: DOM nodes ▅▁▄▅▁▄▃▃█▅▅▄▂▅▃ ➡️ 66
subgraph-mouse-sweep: event listeners ▇▁▂▇▁▂▂▂█▇▂▂▇▇▂ 📈 5
workflow-execution: avg frame time ▆▆▆▄▆▆▃▄▁▄█▆▅▄▆ ➡️ 17ms
workflow-execution: p95 frame time ➡️ NaNms
workflow-execution: layout duration ▁▆▁▃▂▄▃▂▃▃▅█▄▂▅ ➡️ 2ms
workflow-execution: style recalc duration ▃▇▅▇▁▅▆▇█▁██▂▄▆ ➡️ 25ms
workflow-execution: layout count ▁█▂▃▂▃▃▁▃▃▄▃▂▃▂ ➡️ 5
workflow-execution: style recalc count ▃█▅▇▁▄▅▆▅▅▅▅▄▄▂ ➡️ 15
workflow-execution: task duration ▂▅▄▅▁▄▆▆▆▁▇█▁▃▃ ➡️ 120ms
workflow-execution: script duration ▄▃▄▄▃▅▄▅▆▂▇█▁▃▄ ➡️ 29ms
workflow-execution: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
workflow-execution: heap used ➡️ NaN MB
workflow-execution: DOM nodes ▂█▃▆▁▄▃▅▃█▃▃▄▃▁ ➡️ 152
workflow-execution: event listeners ▅███▁▅███▁██▅█▅ ➡️ 49
Raw data
{
  "timestamp": "2026-06-22T21:22:31.404Z",
  "gitSha": "032edad77e5ea21b1507735bb75e53111a77948e",
  "branch": "deepme987/frontend/cloud-funnel-telemetry",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2014.285000000001,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 9.540999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 371.694,
      "heapDeltaBytes": -2108812,
      "heapUsedBytes": 56436920,
      "domNodes": 20,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 19.285,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-idle",
      "durationMs": 2017.0679999999948,
      "styleRecalcs": 7,
      "styleRecalcDurationMs": 7.438999999999997,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 415.5799999999999,
      "heapDeltaBytes": -2349792,
      "heapUsedBytes": 56431936,
      "domNodes": 14,
      "jsHeapTotalBytes": 24641536,
      "scriptDurationMs": 22.547,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1915.5739999999923,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 46.093,
      "layouts": 12,
      "layoutDurationMs": 3.8190000000000004,
      "taskDurationMs": 866.552,
      "heapDeltaBytes": -7101568,
      "heapUsedBytes": 51474320,
      "domNodes": 61,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 127.20100000000001,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1798.5090000000241,
      "styleRecalcs": 74,
      "styleRecalcDurationMs": 38.003,
      "layouts": 12,
      "layoutDurationMs": 3.6049999999999995,
      "taskDurationMs": 782.147,
      "heapDeltaBytes": -7427408,
      "heapUsedBytes": 51284000,
      "domNodes": 56,
      "jsHeapTotalBytes": 25427968,
      "scriptDurationMs": 124.489,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1726.902999999993,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 18.686,
      "layouts": 6,
      "layoutDurationMs": 0.6330000000000001,
      "taskDurationMs": 334.67999999999995,
      "heapDeltaBytes": 1710032,
      "heapUsedBytes": 60789268,
      "domNodes": 77,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 22.853,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1733.082999999965,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 21.240999999999996,
      "layouts": 6,
      "layoutDurationMs": 0.727,
      "taskDurationMs": 378.326,
      "heapDeltaBytes": 4313728,
      "heapUsedBytes": 60247020,
      "domNodes": 79,
      "jsHeapTotalBytes": 18612224,
      "scriptDurationMs": 29.673,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 552.9200000000287,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 7.609000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 326.544,
      "heapDeltaBytes": 7182204,
      "heapUsedBytes": 65950092,
      "domNodes": 18,
      "jsHeapTotalBytes": 18874368,
      "scriptDurationMs": 55.511,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 569.1039999999816,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 7.741,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 347.04999999999995,
      "heapDeltaBytes": 7267240,
      "heapUsedBytes": 65993516,
      "domNodes": 18,
      "jsHeapTotalBytes": 18874368,
      "scriptDurationMs": 58.473000000000006,
      "eventListeners": 0,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999727
    },
    {
      "name": "large-graph-idle",
      "durationMs": 1994.5549999999912,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 9.987,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 538.4369999999999,
      "heapDeltaBytes": -8076484,
      "heapUsedBytes": 62064700,
      "domNodes": 22,
      "jsHeapTotalBytes": 10891264,
      "scriptDurationMs": 104.55199999999999,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2014.2260000000078,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 10.103,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 607.9590000000001,
      "heapDeltaBytes": 13101816,
      "heapUsedBytes": 75339420,
      "domNodes": 20,
      "jsHeapTotalBytes": 6348800,
      "scriptDurationMs": 119.08100000000002,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2140.512000000001,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 19.266000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1178.641,
      "heapDeltaBytes": 2852444,
      "heapUsedBytes": 64813288,
      "domNodes": -265,
      "jsHeapTotalBytes": 7294976,
      "scriptDurationMs": 438.515,
      "eventListeners": -130,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2162.351000000001,
      "styleRecalcs": 70,
      "styleRecalcDurationMs": 19.264,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1134.8690000000001,
      "heapDeltaBytes": 11235244,
      "heapUsedBytes": 84024384,
      "domNodes": 18,
      "jsHeapTotalBytes": 10280960,
      "scriptDurationMs": 407.03700000000003,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3088.628999999969,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 18.438999999999997,
      "layouts": 60,
      "layoutDurationMs": 7.5729999999999995,
      "taskDurationMs": 1292.317,
      "heapDeltaBytes": 13471948,
      "heapUsedBytes": 68320356,
      "domNodes": 12,
      "jsHeapTotalBytes": 6815744,
      "scriptDurationMs": 479.7009999999999,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3185.3320000000167,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 21.188,
      "layouts": 60,
      "layoutDurationMs": 7.902000000000001,
      "taskDurationMs": 1474.2640000000001,
      "heapDeltaBytes": 15376120,
      "heapUsedBytes": 70505908,
      "domNodes": 14,
      "jsHeapTotalBytes": 7340032,
      "scriptDurationMs": 564.012,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2000.7059999999797,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.033000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 566.1030000000001,
      "heapDeltaBytes": -9249484,
      "heapUsedBytes": 64576928,
      "domNodes": 16,
      "jsHeapTotalBytes": 7745536,
      "scriptDurationMs": 109.13000000000001,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2004.3729999999869,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 9.554,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 661.098,
      "heapDeltaBytes": -9514828,
      "heapUsedBytes": 64072364,
      "domNodes": 20,
      "jsHeapTotalBytes": 7483392,
      "scriptDurationMs": 115.77699999999999,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 579.4859999999744,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 11.918000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 373.711,
      "heapDeltaBytes": 8063516,
      "heapUsedBytes": 66980828,
      "domNodes": 22,
      "jsHeapTotalBytes": 19136512,
      "scriptDurationMs": 122.668,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 593.0359999999837,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 12.108999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 407.957,
      "heapDeltaBytes": 8062508,
      "heapUsedBytes": 66750112,
      "domNodes": 22,
      "jsHeapTotalBytes": 19136512,
      "scriptDurationMs": 131.23100000000002,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2006.8129999999655,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 9.585,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 377.25399999999996,
      "heapDeltaBytes": -2631096,
      "heapUsedBytes": 56096328,
      "domNodes": 20,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 19.560000000000002,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 1997.8060000000255,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 8.190999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 436.01900000000006,
      "heapDeltaBytes": -2281880,
      "heapUsedBytes": 56596708,
      "domNodes": 18,
      "jsHeapTotalBytes": 25952256,
      "scriptDurationMs": 21.717,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1683.2009999999968,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 38.479,
      "layouts": 16,
      "layoutDurationMs": 4.849,
      "taskDurationMs": 662.841,
      "heapDeltaBytes": 14811152,
      "heapUsedBytes": 66503628,
      "domNodes": 62,
      "jsHeapTotalBytes": 15466496,
      "scriptDurationMs": 91.684,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1702.891999999963,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 35.948,
      "layouts": 16,
      "layoutDurationMs": 4.081,
      "taskDurationMs": 731.4150000000001,
      "heapDeltaBytes": -11123860,
      "heapUsedBytes": 47682212,
      "domNodes": 62,
      "jsHeapTotalBytes": 26476544,
      "scriptDurationMs": 97.80900000000001,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "subgraph-transition-enter",
      "durationMs": 1298.2589999999732,
      "styleRecalcs": 17,
      "styleRecalcDurationMs": 27.615000000000002,
      "layouts": 4,
      "layoutDurationMs": 13.717000000000004,
      "taskDurationMs": 817.1189999999999,
      "heapDeltaBytes": 4555672,
      "heapUsedBytes": 80324160,
      "domNodes": 13833,
      "jsHeapTotalBytes": 17563648,
      "scriptDurationMs": 40.329,
      "eventListeners": 2529,
      "totalBlockingTimeMs": 158,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8201.729,
      "styleRecalcs": 251,
      "styleRecalcDurationMs": 55.614999999999995,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 3919.0080000000003,
      "heapDeltaBytes": -2484384,
      "heapUsedBytes": 67594404,
      "domNodes": 20,
      "jsHeapTotalBytes": 17096704,
      "scriptDurationMs": 1303.055,
      "eventListeners": 20,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8306.912999999895,
      "styleRecalcs": 252,
      "styleRecalcDurationMs": 57.519000000000005,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4328.966,
      "heapDeltaBytes": 5764796,
      "heapUsedBytes": 76214612,
      "domNodes": 22,
      "jsHeapTotalBytes": 22601728,
      "scriptDurationMs": 1513.6970000000001,
      "eventListeners": 22,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 13255.900999999994,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 13222.01,
      "heapDeltaBytes": -40491144,
      "heapUsedBytes": 172534320,
      "domNodes": -3310,
      "jsHeapTotalBytes": 25399296,
      "scriptDurationMs": 663.805,
      "eventListeners": -16473,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.219999999999953,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 12531.799999999976,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12516.478000000001,
      "heapDeltaBytes": -52289900,
      "heapUsedBytes": 161758276,
      "domNodes": -8331,
      "jsHeapTotalBytes": 14745600,
      "scriptDurationMs": 589.136,
      "eventListeners": -16468,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.223333333333358,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 15032.003000000032,
      "styleRecalcs": 71,
      "styleRecalcDurationMs": 18.83499999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 14994.462,
      "heapDeltaBytes": -44626676,
      "heapUsedBytes": 165087756,
      "domNodes": -3308,
      "jsHeapTotalBytes": 17272832,
      "scriptDurationMs": 902.8600000000001,
      "eventListeners": -16474,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.220000000000073,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 14735.352000000035,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 18.04899999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 14711.247,
      "heapDeltaBytes": -54836660,
      "heapUsedBytes": 171047200,
      "domNodes": -8365,
      "jsHeapTotalBytes": 17891328,
      "scriptDurationMs": 884.411,
      "eventListeners": -16514,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.220000000000073,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 470.72299999996403,
      "styleRecalcs": 18,
      "styleRecalcDurationMs": 26.317,
      "layouts": 5,
      "layoutDurationMs": 1.509,
      "taskDurationMs": 132.63199999999998,
      "heapDeltaBytes": 5490980,
      "heapUsedBytes": 65219384,
      "domNodes": 168,
      "jsHeapTotalBytes": 3407872,
      "scriptDurationMs": 24.870000000000005,
      "eventListeners": 69,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 444.7010000000091,
      "styleRecalcs": 16,
      "styleRecalcDurationMs": 20.056000000000004,
      "layouts": 5,
      "layoutDurationMs": 1.5250000000000001,
      "taskDurationMs": 111.101,
      "heapDeltaBytes": 5108928,
      "heapUsedBytes": 65176504,
      "domNodes": 155,
      "jsHeapTotalBytes": 2883584,
      "scriptDurationMs": 17.116000000000003,
      "eventListeners": 69,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.663333333333338,
      "p95FrameDurationMs": 16.700000000000273
    }
  ]
}

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

🌐 Website E2E

Tip

All tests passed.

Status ✅ Passed
Report View Report

🔗 Website Preview

Website Preview: https://comfy-website-preview-pr-12894.vercel.app

This commit: https://website-frontend-3xafz3i0s-comfyui.vercel.app

Last updated: 2026-06-22T21:12:30Z for 2b27182

@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
comfyui-frontend-node-search-preview Error Error Jun 19, 2026 12:04am

@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/uy-tieu-s-projects?upgradeToPro=build-rate-limit

@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

Deployment failed with the following error:

Resource is limited - try again in 1 day (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/uy-tieu-s-projects?upgradeToPro=build-rate-limit

Resolve conflicts with #12861 (navbar -> shadcn) and #12925 (decouple run telemetry): rewire website CTA telemetry into the new HeaderMain components, adopt trackRunButton(RunButtonProperties), keep is_app_mode super-property.
Restore trackEmailVerification + USER_EMAIL_VERIFY_* (main's new HostTelemetrySink sink consumes them; keeps PR additive). Gate first_execution_completed behind isCloud after Ben's executionStore refactor.
@deepme987
deepme987 requested a review from a team June 22, 2026 00:03
@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Jun 22, 2026
Address review findings on the cloud funnel:
- Login-time subscription enforcement was mislabeled reason 'run_workflow' (it only fires on the isLoggedIn watch); tag 'subscription_required' so the run-gate cohort isn't polluted.
- Deliberate OAuth popup cancels no longer emit auth_failed (already captured as oauth_popup_result 'cancelled'); add auth-funnel tests locking in the cancel-vs-failure distinction.
- Correct the output_viewed doc (fires on output PRODUCED, not visibility).
- Drop stale auth-activation markers (>60s) so an unrelated reload can't report a bogus ms_since_auth.
- Replace the duplicated VIEWED_MEDIA_TYPES set with isPreviewableMediaType.
@deepme987

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/components/custom/widget/WorkflowTemplateSelectorDialog.vue (1)

547-552: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Consider including category_label in the telemetry payload.

The TemplateCategorySelectedMetadata interface supports an optional category_label field. Including the human-readable label alongside category_id would improve analytics readability and reduce the need for post-processing lookups. You can derive the label from pageTitle computed or by looking up the selected nav item in navItems.

📊 Example: add category_label
 watch(selectedNavItem, (to, from) => {
   if (!to || to === from) return
-  useTelemetry()?.trackTemplateCategorySelected({ category_id: to })
+  const label = pageTitle.value
+  useTelemetry()?.trackTemplateCategorySelected({
+    category_id: to,
+    category_label: label
+  })
 })

Alternatively, look up the label directly from navItems.value if you want the raw label instead of the computed title.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/custom/widget/WorkflowTemplateSelectorDialog.vue` around lines
547 - 552, The watch function for selectedNavItem only includes category_id in
the trackTemplateCategorySelected telemetry call, but should also include
category_label for improved analytics readability. Modify the
useTelemetry()?.trackTemplateCategorySelected() call to add a category_label
field alongside category_id. You can derive the label from the pageTitle
computed property or by looking up the selected nav item in the navItems array
to get its human-readable label.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/custom/widget/WorkflowTemplateSelectorDialog.vue`:
- Around line 547-552: The telemetry call within the selectedNavItem watch
handler uses optional chaining but lacks the explicit isCloud guard that is used
consistently elsewhere in the file (such as with the trackTemplateLibraryClosed
call). Wrap the useTelemetry()?.trackTemplateCategorySelected() call inside an
if (isCloud) conditional check to align with the existing cloud gating pattern
used throughout this component.

In `@src/platform/cloud/subscription/composables/useSubscription.ts`:
- Around line 133-139: The `lastCheckoutAttempt` variable in the useSubscription
composable is not being reset after terminal checkout outcomes (success,
failure, or cancellation), which causes stale attempt information to persist and
be incorrectly reused by subsequent status syncs. This results in incorrect
cancelled events being emitted for old attempts. Reset `lastCheckoutAttempt` to
null at all terminal outcome paths where checkout completes or fails, ensuring
the variable does not carry over stale data to later status sync operations.
Review both the initial declaration around line 133-139 and the related code
sections around lines 200-215 to identify all terminal outcome paths where this
reset should be applied.

---

Nitpick comments:
In `@src/components/custom/widget/WorkflowTemplateSelectorDialog.vue`:
- Around line 547-552: The watch function for selectedNavItem only includes
category_id in the trackTemplateCategorySelected telemetry call, but should also
include category_label for improved analytics readability. Modify the
useTelemetry()?.trackTemplateCategorySelected() call to add a category_label
field alongside category_id. You can derive the label from the pageTitle
computed property or by looking up the selected nav item in the navItems array
to get its human-readable label.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0b00fce5-d9e5-462a-bb50-81d680f178e4

📥 Commits

Reviewing files that changed from the base of the PR and between 2cda397 and f4b1c19.

📒 Files selected for processing (27)
  • apps/website/src/components/common/HeaderMain/HeaderMain.vue
  • apps/website/src/components/common/HeaderMain/HeaderMainDesktop.vue
  • apps/website/src/components/common/HeaderMain/HeaderMainMobile.vue
  • apps/website/src/components/common/HeaderMain/NavColumn.vue
  • apps/website/src/components/common/ProductCard.vue
  • apps/website/src/components/common/ProductCardsSection.vue
  • apps/website/src/components/home/HeroSection.vue
  • apps/website/src/data/mainNavigation.ts
  • apps/website/src/scripts/posthog.test.ts
  • apps/website/src/scripts/posthog.ts
  • src/components/custom/widget/WorkflowTemplateSelectorDialog.vue
  • src/platform/cloud/subscription/components/PricingTable.test.ts
  • src/platform/cloud/subscription/components/PricingTable.vue
  • src/platform/cloud/subscription/components/SubscribeButton.vue
  • src/platform/cloud/subscription/components/SubscribeToRun.test.ts
  • src/platform/cloud/subscription/components/SubscribeToRun.vue
  • src/platform/cloud/subscription/composables/useSubscription.test.ts
  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.test.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/platform/telemetry/TelemetryRegistry.test.ts
  • src/platform/telemetry/TelemetryRegistry.ts
  • src/platform/telemetry/authActivationMarker.test.ts
  • src/platform/telemetry/authActivationMarker.ts
  • src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.test.ts
  • src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.ts
  • src/platform/telemetry/types.ts
💤 Files with no reviewable changes (2)
  • src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.ts
  • src/platform/telemetry/types.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.test.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/platform/telemetry/authActivationMarker.ts
  • src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.test.ts
  • src/platform/telemetry/authActivationMarker.test.ts

Comment on lines +547 to +552
// Track category/tab switches (e.g. "Getting Started" vs "All") so we can see
// which curated entry points users browse before opening a template.
watch(selectedNavItem, (to, from) => {
if (!to || to === from) return
useTelemetry()?.trackTemplateCategorySelected({ category_id: to })
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Align cloud gating with the existing pattern in this file.

The existing telemetry call at lines 456-465 wraps useTelemetry()?.trackTemplateLibraryClosed(...) inside an explicit if (isCloud) check, but the new category-selection telemetry uses only optional chaining. For consistency within this file, wrap the telemetry call in an if (isCloud) guard.

♻️ Align cloud gating pattern
 watch(selectedNavItem, (to, from) => {
   if (!to || to === from) return
-  useTelemetry()?.trackTemplateCategorySelected({ category_id: to })
+  if (isCloud) {
+    useTelemetry()?.trackTemplateCategorySelected({ category_id: to })
+  }
 })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/custom/widget/WorkflowTemplateSelectorDialog.vue` around lines
547 - 552, The telemetry call within the selectedNavItem watch handler uses
optional chaining but lacks the explicit isCloud guard that is used consistently
elsewhere in the file (such as with the trackTemplateLibraryClosed call). Wrap
the useTelemetry()?.trackTemplateCategorySelected() call inside an if (isCloud)
conditional check to align with the existing cloud gating pattern used
throughout this component.

Comment on lines +133 to +139
// In-session checkout attempt (attempt_id/tier/cycle) for attributing a non-success
// checkout_returned; success outcomes source the id from metadata instead (cross-session).
let lastCheckoutAttempt: {
attempt_id: string
tier: string
cycle: string
} | null = null

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reset lastCheckoutAttempt after terminal outcomes to avoid stale cancellation attribution.

lastCheckoutAttempt is used to emit checkout_returned: cancelled, but it is never cleared in these paths. A stale in-session attempt can be reused by later status synces and emit an incorrect cancelled event for an old attempt.

Suggested fix
   if (!metadata) {
     if (hasPendingSubscriptionCheckoutAttempt()) {
       if (lastCheckoutAttempt) {
         reportCheckoutReturned(lastCheckoutAttempt.attempt_id, 'unknown')
       }
       schedulePendingCheckoutRecovery()
     } else {
       if (lastCheckoutAttempt) {
         reportCheckoutReturned(lastCheckoutAttempt.attempt_id, 'cancelled')
+        lastCheckoutAttempt = null
       }
       stopPendingCheckoutRecovery()
     }
     return
   }

   reportCheckoutReturned(metadata.checkout_attempt_id, 'success')
+  if (lastCheckoutAttempt?.attempt_id === metadata.checkout_attempt_id) {
+    lastCheckoutAttempt = null
+  }

Also applies to: 200-215

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/cloud/subscription/composables/useSubscription.ts` around lines
133 - 139, The `lastCheckoutAttempt` variable in the useSubscription composable
is not being reset after terminal checkout outcomes (success, failure, or
cancellation), which causes stale attempt information to persist and be
incorrectly reused by subsequent status syncs. This results in incorrect
cancelled events being emitted for old attempts. Reset `lastCheckoutAttempt` to
null at all terminal outcome paths where checkout completes or fails, ensuring
the variable does not carry over stale data to later status sync operations.
Review both the initial declaration around line 133-139 and the related code
sections around lines 200-215 to identify all terminal outcome paths where this
reset should be applied.

…oud-funnel-telemetry

# Conflicts:
#	src/stores/executionStore.test.ts
#	src/stores/executionStore.ts

@christian-byrne christian-byrne left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 13/33 pausing briefly

// Track category/tab switches (e.g. "Getting Started" vs "All") so we can see
// which curated entry points users browse before opening a template.
watch(selectedNavItem, (to, from) => {
if (!to || to === from) return

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First, to === from is not necessary. See https://github.com/vuejs/core/blob/main/packages/reactivity/src/watch.ts.

I also personally don't think !to is necessary if the lifecycle semantics of the nav item ref don't allow for a falsy value outside of initial mount.

Comment on lines +547 to +548
// Track category/tab switches (e.g. "Getting Started" vs "All") so we can see
// which curated entry points users browse before opening a template.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove these comments that explain things already apparent from the code itself? Then keep only comments explaining something that's truly not inferrable from the code?

const onboardingSurveyEnabled = computed(
() => flags.onboardingSurveyEnabled ?? true
)
const telemetry = isCloud ? useTelemetry() : undefined

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should stay consistent with the rest of the codebase and just inline all useTelemetry calls. The performance diff is not detectable and generally we should avoid eager import side effects.

Comment on lines +76 to +80
telemetry?.trackOnboardingRouted({
destination: 'waitlist',
survey_completed: !!surveyStatus,
has_cloud_status: false
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is necessary as the waitlist doesn't exist anymore.

// captures intent even if the checkout window is blocked or abandoned.
// Covers both the 'change' (existing paid subscriber) and 'new' paths.
telemetry?.trackSubscription('subscribe_clicked', {
current_tier: subscriptionTier.value?.toLowerCase(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For these events, are they expected to always be lower case? Does that apply to all? We should build that into the types if it's the case so that no future agent can slip up. See https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html#lowercasestringtype

Comment on lines +133 to +155
// Non-success returns attribute via this; success outcomes use the id from metadata (cross-session).
let lastCheckoutAttempt: {
attempt_id: string
tier: string
cycle: string
} | null = null
// Fire checkout_returned once per attempt despite pageshow/visibilitychange firing repeatedly.
const reportedReturnedAttemptIds = new Set<string>()

const reportCheckoutReturned = (
checkoutAttemptId: string,
outcome: 'success' | 'cancelled' | 'unknown'
) => {
if (reportedReturnedAttemptIds.has(checkoutAttemptId)) {
return
}
reportedReturnedAttemptIds.add(checkoutAttemptId)
telemetry?.trackCheckoutReturned({
checkout_attempt_id: checkoutAttemptId,
outcome
})
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A larger thing: there was always a constraint for FE telem whereby the BE never sent an event indicating the subscription succeeded. To allow us to see "user subscribed" we had to use hacks like recording the state and then once seeing the state change on the user/customer object, we inferred a subscription success. It's really not good and has a lot of failure modes. One of the major benefits of unifying data and doing identity stitching and ETL and everything was that we wouldn't have to do that anymore. That is, we would have the subscribe event owned by the BE and the user behaviors owned by the FE and then we ETL and stitch. This PR is adding more FE code to try to infer subscription success. Thoughts?

| 'subscription_required'
| 'out_of_credits'
| 'top_up_blocked'
// Non-activation cohort: the activation funnel must be able to exclude these.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this mean exactly?

Comment on lines 65 to 73
const DEFAULT_DISABLED_EVENTS = [
TelemetryEvents.WORKFLOW_OPENED,
TelemetryEvents.PAGE_VISIBILITY_CHANGED,
TelemetryEvents.TAB_COUNT_TRACKING,
TelemetryEvents.NODE_SEARCH,
TelemetryEvents.NODE_SEARCH_RESULT_SELECTED,
TelemetryEvents.HELP_CENTER_OPENED,
TelemetryEvents.HELP_RESOURCE_CLICKED,
TelemetryEvents.HELP_CENTER_CLOSED,
TelemetryEvents.WORKFLOW_CREATED
TelemetryEvents.HELP_CENTER_CLOSED
] as const satisfies TelemetryEventName[]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea was that if we wanted to disable/enable these events, we would do it in the feature flags -- rather than changing the defaults.

autocapture: false,
capture_pageview: false,
capture_pageleave: false,
autocapture: true,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For autocapture, I don't think it aligns with our overall analytics strategy.

Our approach is to maintain a deliberate, manually-defined event taxonomy that stays consistent across codebases and surfaces. Those events are ETL'd into a shared warehouse, and much of our analysis relies on agents reasoning over that data.

Autocapture introduces a large volume of implementation-derived events that exist outside that taxonomy. Unlike product events, these events are often tied to UI details such as DOM structure, element labels, CSS classes, and interaction patterns. As the product evolves, those implementation details can change even when the underlying user behavior has not, creating discontinuities in the data and potentially leading to incorrect conclusions. For example, an apparent drop-off in an autocaptured flow may simply reflect a UI refactor rather than an actual change in user behavior.

It also significantly increases the amount of low-signal data in the warehouse. Given that our downstream analysis relies heavily on agents, maintaining a high signal-to-noise ratio is important. A curated set of stable, intentional product events provides a much stronger foundation for analysis than a mix of curated events and a large volume of automatically generated interaction events. In practice, I would expect autocapture to make it harder for both humans and agents to identify meaningful patterns and draw reliable conclusions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm aligned to not use autocapture to avoid noisy signal bloat (if we can precisely define the events we want to capture with product team).

My hope is we should be able to be more explicit and use glary / @PostHog code to help us define precise event tracking and avoid noisy event bloat. We want to understand activation and conversion and usage intents that drive retained users and who drive growth. cc @deepme987 @stevenltran @benceruleanlu

Does that make sense?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for flagging

Comment on lines +374 to +390
private setFirstTouchAttribution(): void {
if (!this.posthog) return
const params = new URLSearchParams(window.location.search)
const firstTouch: Record<string, string> = {}
const source = params.get('utm_source')
const medium = params.get('utm_medium')
const campaign = params.get('utm_campaign')
if (source) firstTouch.initial_utm_source = source
if (medium) firstTouch.initial_utm_medium = medium
if (campaign) firstTouch.initial_utm_campaign = campaign
if (Object.keys(firstTouch).length === 0) return
try {
this.posthog.people.set_once(firstTouch)
} catch (error) {
console.error('Failed to set first-touch attribution:', error)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should be done automatically by the library, are you certain it's needed? If the lib is already doing it, we are potentially adding redundant events that may in some cases conflict with the lib.

…tidy funnel call sites

- Stop emitting subscription_success from the FE inference in useSubscription;
  the backend now owns it via billing:subscription_created (Stripe webhook).
  Keep the checkout_returned funnel event and pending-attempt state-sync.
- Inline useTelemetry()?.trackOnboardingRouted in UserCheckView and remove the
  dead waitlist skeleton branch; relabel the user-not-found destination 'login'.
- Simplify the template-category watcher (redundant same-value guard).
@deepme987

Copy link
Copy Markdown
Contributor Author

closing - super-seeded

@deepme987 deepme987 closed this Jul 15, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 15, 2026
@deepme987 deepme987 removed their assignment Jul 15, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants