Skip to content

fix: derive subgraph preview promotion for any interior node type - #14551

Closed
claude[bot] wants to merge 8 commits into
mainfrom
fix/subgraph-preview-allowlist-gap
Closed

fix: derive subgraph preview promotion for any interior node type#14551
claude[bot] wants to merge 8 commits into
mainfrom
fix/subgraph-preview-allowlist-gap

Conversation

@claude

@claude claude Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Requested by Christian Byrne · Slack thread

Summary

Fixes a regression where a mid-execution sampler preview inside a subgraph only bubbled up to the outer SubgraphNode for a hardcoded set of node types (KSampler, KSamplerAdvanced, PreviewImage, SaveImage, GLSLShader). Any other sampler variant — e.g. SamplerCustomAdvanced, or a third-party custom sampler — never showed a live preview on the collapsed subgraph.

Renderer scope: this fix applies only to the Vue Nodes ("Nodes 2.0") renderer. It does not change the classic canvas renderer's preview behavior at all — see "Fix" below.

Root cause

PR #12197 (Subgraph Link Only Promotion, ADR 0009) replaced the old universal live-preview bubbling with an exposure allowlist: autoExposeKnownPreviewNodes (src/core/graph/subgraph/promotionUtils.ts) only registered a persisted preview exposure for interior node types in CANVAS_IMAGE_PREVIEW_NODE_TYPES (src/composables/node/canvasImagePreviewTypes.ts). Every other node type never got an exposure at all, so a real preview arriving later over the websocket had nothing to promote through.

Fix

autoExposeKnownPreviewNodes is unchanged from main — it still only eagerly persists an exposure for allowlisted node types. (An earlier version of this fix made it register an exposure for every interior node unconditionally; that wrote spurious entries into properties.previewExposures regardless of whether a node ever produced a preview, and was reverted.)

Instead, the actual fix lives in usePromotedPreviews (src/composables/node/usePromotedPreviews.ts), which now derives previews for non-exposed interior nodes directly from live store state on every read, without persisting anything:

  • Explicit previews (pre-existing): sources with a persisted previewExposureStore entry.
  • Implicit previews (new): any interior node that isn't a nested SubgraphNode and isn't already exposed gets a derived preview once nodeOutputStore.nodePreviewImages has live progress-preview data for it — no allowlist, no persisted state, so it renders once real preview data arrives for any node type. Gated to live preview blobs only (not committed nodeOutputs), so a restored LoadImage thumbnail from a saved workflow doesn't leak through as an undismissable preview on load. If the user explicitly removes a preview (real or virtual), it stays removed and won't be re-derived on the next recompute.

Only the Vue node renderer reads this composable. The classic canvas renderer (LGraphCanvas.drawNode / getPseudoWidgetPreviewTargets in litegraphService.ts) is untouched by this PR and continues to resolve preview targets purely from previewExposureStore. Nodes 2.0 and the classic canvas are mutually exclusive renderers (Comfy.VueNodes.Enabled), so classic canvas does not benefit from this fix — that's a deliberate scope boundary, not a gap.

Changes

  • src/composables/node/usePromotedPreviews.ts: adds the derived/implicit preview branch described above (this is where the actual fix lives); derives media type (image/video/audio) from the output payload instead of the mutable node.previewMediaType field, which is never set for an interior node the user hasn't visually entered.
  • src/composables/node/usePromotedPreviews.test.ts: regression coverage for the above — an explicitly-removed preview doesn't reappear, a committed input-preview output isn't implicitly promoted, gaining a canvas-image-preview pseudo-widget doesn't kill the implicit preview, and video type is derived correctly without previewMediaType.
  • src/stores/previewExposureStore.ts: tracks sources explicitly demoted while they had no exposure entry to remove (a virtual/implicit preview), so removal actually sticks instead of being re-derived on the next recompute.
  • src/stores/previewExposureStore.test.ts: regression coverage for the new isSourceExplicitlyRemoved tracking — a source is flagged only after removeExposure demotes it, the flag clears once the source is re-exposed via addExposure, and clearGraph resets it for the whole graph.
  • src/stores/nodeOutputStore.ts: exposes the existing isInputPreviewOutput helper for reuse.
  • src/core/graph/subgraph/promotionUtils.ts: autoExposeKnownPreviewNodes reverted to the allowlist-gated behavior on main (minus the dead requestAnimationFrame fallback).
  • src/core/graph/subgraph/promotionUtils.test.ts: keeps the existing unlisted-node-type test, which asserts autoExposeKnownPreviewNodes does not eagerly persist an exposure for an unlisted type (SamplerCustomAdvanced) — useful for catching a future over-exposure regression, but it also passes unmodified against promotionUtils.ts on main, so it isn't itself coverage for this PR's fix (that's usePromotedPreviews.test.ts, above). Also removes a dead useLitegraphService mock and its now-vacuous not.toHaveBeenCalled() assertions (promotionUtils.ts no longer imports useLitegraphService), and rewrites the test that depended on it to assert the real preview-widget exposure behavior instead.
  • browser_tests/tests/subgraph/subgraphPreviewAllowlistGap.spec.ts + browser_tests/assets/nodes/sampler_custom_advanced_in_subgraph.json: e2e regression test simulating a mid-execution websocket preview for a SamplerCustomAdvanced node nested in a subgraph, asserting the preview renders on the outer SubgraphNode.
  • browser_tests/tests/vueNodes/interactions/node/imagePreview.spec.ts + src/renderer/extensions/vueNodes/components/LGraphNode.test.ts: expected-fail regression tests for a separate, still-open bug found while investigating this incident — the !lgraphNode?.isSubgraphNode() guard at LGraphNode.vue:172 — each test.fail()/it.fails() marker is now commented with the guard line to fix and a reminder to remove the marker (not just delete the test) once it's addressed.

Breaking: None.

Fixes #14597
Refs Comfy-Org/ComfyUI#15264

(Not linking #9859: that report is explicitly about the classic canvas renderer with Nodes 2.0 already working for the reporter, which is out of scope here — see "Renderer scope" above.)

autoExposeKnownPreviewNodes only auto-exposes previews for interior node
types hardcoded in CANVAS_IMAGE_PREVIEW_NODE_TYPES. Node types not on that
list (e.g. SamplerCustomAdvanced) fall back to a one-shot
requestAnimationFrame check that runs before the node has produced any
output and is never retried, so a real preview arriving later over the
websocket never reaches the outer SubgraphNode.

Adds a unit test exercising autoExposeKnownPreviewNodes directly and an
e2e test simulating a mid-execution websocket preview for a
SamplerCustomAdvanced node nested in a subgraph. Both currently fail.
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 08/04/2026, 03:03:23 AM UTC

Links

🎭 Playwright: ✅ 1783 passed, 0 failed · 2 flaky

📊 Browser Reports
  • chromium: View Report (✅ 1762 / ❌ 0 / ⚠️ 2 / ⏭️ 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)

📦 Bundle: 8.24 MB gzip 🔴 +545 B

Details

Summary

  • Raw size: 34.6 MB baseline 34.6 MB — 🔴 +2.58 kB
  • Gzip: 8.24 MB baseline 8.24 MB — 🔴 +545 B
  • Brotli: 5.7 MB baseline 5.7 MB — 🔴 +416 B
  • Bundles: 427 current • 427 baseline • 144 added / 144 removed

Category Glance
Graph Workspace 🔴 +1.51 kB (1.34 MB) · Data & Services 🔴 +1.07 kB (3.46 MB) · Vendor & Third-Party ⚪ 0 B (15.7 MB) · Other ⚪ 0 B (12.8 MB) · Panels & Settings ⚪ 0 B (551 kB) · Utilities & Hooks ⚪ 0 B (386 kB) · + 5 more

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

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-_SMf1HLD.js (removed) 3.64 kB 🟢 -3.64 kB 🟢 -1.82 kB 🟢 -1.58 kB
assets/index-BKRbgmqa.js (new) 3.64 kB 🔴 +3.64 kB 🔴 +1.82 kB 🔴 +1.58 kB

Status: 1 added / 1 removed

Graph Workspace — 1.34 MB (baseline 1.34 MB) • 🔴 +1.51 kB

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-BxZ7SXDT.js (new) 1.34 MB 🔴 +1.34 MB 🔴 +291 kB 🔴 +219 kB
assets/GraphView-DIm7TnlG.js (removed) 1.34 MB 🟢 -1.34 MB 🟢 -290 kB 🟢 -218 kB

Status: 1 added / 1 removed / 1 unchanged

Views & Navigation — 111 kB (baseline 111 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-CavHRV3a.js (removed) 24.9 kB 🟢 -24.9 kB 🟢 -6.23 kB 🟢 -5.51 kB
assets/CloudSurveyView-O3JaT5UA.js (new) 24.9 kB 🔴 +24.9 kB 🔴 +6.22 kB 🔴 +5.51 kB
assets/CloudLoginView-D_SCMFlr.js (removed) 11.6 kB 🟢 -11.6 kB 🟢 -3.11 kB 🟢 -2.72 kB
assets/CloudLoginView-DN3eRYgx.js (new) 11.6 kB 🔴 +11.6 kB 🔴 +3.11 kB 🔴 +2.72 kB
assets/CloudSignupView-BzeD6NVN.js (removed) 9.9 kB 🟢 -9.9 kB 🟢 -2.77 kB 🟢 -2.42 kB
assets/CloudSignupView-CXjUoDA5.js (new) 9.9 kB 🔴 +9.9 kB 🔴 +2.77 kB 🔴 +2.43 kB
assets/CloudLayoutView-CSanBZBt.js (removed) 9.48 kB 🟢 -9.48 kB 🟢 -2.31 kB 🟢 -1.99 kB
assets/CloudLayoutView-DZMIRUuq.js (new) 9.48 kB 🔴 +9.48 kB 🔴 +2.31 kB 🔴 +1.99 kB
assets/UserCheckView-DL4CGcSc.js (new) 8.75 kB 🔴 +8.75 kB 🔴 +2.19 kB 🔴 +1.9 kB
assets/UserCheckView-DziXd2_w.js (removed) 8.75 kB 🟢 -8.75 kB 🟢 -2.19 kB 🟢 -1.91 kB
assets/WidgetTextPreview-BSidoeTn.js (new) 6.07 kB 🔴 +6.07 kB 🔴 +2.13 kB 🔴 +1.89 kB
assets/WidgetTextPreview-Cbn33yd-.js (removed) 6.07 kB 🟢 -6.07 kB 🟢 -2.13 kB 🟢 -1.89 kB
assets/CloudSubscriptionRedirectView-CGLykBL5.js (new) 5.99 kB 🔴 +5.99 kB 🔴 +2.23 kB 🔴 +1.94 kB
assets/CloudSubscriptionRedirectView-cqIpmmkn.js (removed) 5.99 kB 🟢 -5.99 kB 🟢 -2.23 kB 🟢 -1.94 kB
assets/UserSelectView-CmZ8R-ld.js (new) 5.49 kB 🔴 +5.49 kB 🔴 +1.96 kB 🔴 +1.72 kB
assets/UserSelectView-zzWrByu_.js (removed) 5.49 kB 🟢 -5.49 kB 🟢 -1.95 kB 🟢 -1.71 kB
assets/CloudForgotPasswordView-9Bkwt0Tv.js (removed) 5.09 kB 🟢 -5.09 kB 🟢 -1.73 kB 🟢 -1.51 kB
assets/CloudForgotPasswordView-BlWW_81c.js (new) 5.09 kB 🔴 +5.09 kB 🔴 +1.72 kB 🔴 +1.51 kB
assets/CloudAuthTimeoutView-B_DE6lRn.js (removed) 4.43 kB 🟢 -4.43 kB 🟢 -1.54 kB 🟢 -1.35 kB
assets/CloudAuthTimeoutView-D_ig4jrT.js (new) 4.43 kB 🔴 +4.43 kB 🔴 +1.54 kB 🔴 +1.35 kB
assets/OAuthLayoutView-CtAEdgtX.js (removed) 1.31 kB 🟢 -1.31 kB 🟢 -700 B 🟢 -594 B
assets/OAuthLayoutView-DWimPU5g.js (new) 1.31 kB 🔴 +1.31 kB 🔴 +700 B 🔴 +594 B
assets/WidgetTextPreview-D2XEwj7Z.js (new) 131 B 🔴 +131 B 🔴 +100 B 🔴 +91 B
assets/WidgetTextPreview-DbHIiTmR.js (removed) 131 B 🟢 -131 B 🟢 -100 B 🟢 -88 B

Status: 12 added / 12 removed / 4 unchanged

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

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/KeybindingPanel-CkT1XRQi.js (new) 49.4 kB 🔴 +49.4 kB 🔴 +9.94 kB 🔴 +8.82 kB
assets/KeybindingPanel-D2GexMx5.js (removed) 49.4 kB 🟢 -49.4 kB 🟢 -9.95 kB 🟢 -8.8 kB
assets/SecretsPanel-B7y3diq0.js (new) 33.7 kB 🔴 +33.7 kB 🔴 +7.86 kB 🔴 +6.9 kB
assets/SecretsPanel-Bk87JOAH.js (removed) 33.7 kB 🟢 -33.7 kB 🟢 -7.86 kB 🟢 -6.89 kB
assets/CreditsPanel-Ba5qd26i.js (removed) 15.9 kB 🟢 -15.9 kB 🟢 -4.63 kB 🟢 -4.07 kB
assets/CreditsPanel-BV4OIUxs.js (new) 15.9 kB 🔴 +15.9 kB 🔴 +4.63 kB 🔴 +4.07 kB
assets/SubscriptionPanel-BwrybxPw.js (removed) 11.5 kB 🟢 -11.5 kB 🟢 -3.64 kB 🟢 -3.19 kB
assets/SubscriptionPanel-DiotxuIL.js (new) 11.5 kB 🔴 +11.5 kB 🔴 +3.65 kB 🔴 +3.2 kB
assets/AboutPanel-BgN2JtFJ.js (removed) 11.2 kB 🟢 -11.2 kB 🟢 -3.03 kB 🟢 -2.71 kB
assets/AboutPanel-CCvT39nA.js (new) 11.2 kB 🔴 +11.2 kB 🔴 +3.03 kB 🔴 +2.71 kB
assets/ExtensionPanel-DjTrrG7I.js (new) 9.19 kB 🔴 +9.19 kB 🔴 +2.51 kB 🔴 +2.23 kB
assets/ExtensionPanel-DrwwKD4g.js (removed) 9.19 kB 🟢 -9.19 kB 🟢 -2.51 kB 🟢 -2.22 kB
assets/ServerConfigPanel-cAlqDNcj.js (new) 6.09 kB 🔴 +6.09 kB 🔴 +1.94 kB 🔴 +1.72 kB
assets/ServerConfigPanel-FHMo--8f.js (removed) 6.09 kB 🟢 -6.09 kB 🟢 -1.94 kB 🟢 -1.72 kB
assets/UserPanel-CnC_vbqm.js (removed) 5.73 kB 🟢 -5.73 kB 🟢 -1.78 kB 🟢 -1.54 kB
assets/UserPanel-DNljPPUA.js (new) 5.73 kB 🔴 +5.73 kB 🔴 +1.78 kB 🔴 +1.54 kB
assets/refreshRemoteConfig-CMDS2ycT.js (new) 2.94 kB 🔴 +2.94 kB 🔴 +1.25 kB 🔴 +1.11 kB
assets/refreshRemoteConfig-DTVy_qr_.js (removed) 2.94 kB 🟢 -2.94 kB 🟢 -1.25 kB 🟢 -1.11 kB
assets/cloudRemoteConfig-BRrheGP2.js (new) 933 B 🔴 +933 B 🔴 +502 B 🔴 +416 B
assets/cloudRemoteConfig-BwaN7amH.js (removed) 933 B 🟢 -933 B 🟢 -505 B 🟢 -417 B
assets/refreshRemoteConfig-CDrH7Ug2.js (removed) 110 B 🟢 -110 B 🟢 -89 B 🟢 -82 B
assets/refreshRemoteConfig-CGlPAv8j.js (new) 110 B 🔴 +110 B 🔴 +89 B 🔴 +90 B

Status: 11 added / 11 removed / 15 unchanged

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

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/SignUpForm-CDq1p9-s.js (new) 12.2 kB 🔴 +12.2 kB 🔴 +4.15 kB 🔴 +3.62 kB
assets/SignUpForm-Z7YNsxeJ.js (removed) 12.2 kB 🟢 -12.2 kB 🟢 -4.15 kB 🟢 -3.62 kB
assets/auth-8wY8fBbv.js (new) 3.65 kB 🔴 +3.65 kB 🔴 +1.27 kB 🔴 +1.1 kB
assets/auth-UFQn8VwR.js (removed) 3.65 kB 🟢 -3.65 kB 🟢 -1.27 kB 🟢 -1.1 kB
assets/usePostAuthRedirect-CX9opad6.js (removed) 3.28 kB 🟢 -3.28 kB 🟢 -1.24 kB 🟢 -1.08 kB
assets/usePostAuthRedirect-D-DxdmiX.js (new) 3.28 kB 🔴 +3.28 kB 🔴 +1.24 kB 🔴 +1.08 kB
assets/UpdatePasswordContent-ClvcTs5t.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -839 B 🟢 -728 B
assets/UpdatePasswordContent-Dd_n85zM.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +839 B 🔴 +726 B
assets/authStore-BXNdCYRA.js (removed) 128 B 🟢 -128 B 🟢 -104 B 🟢 -104 B
assets/authStore-D_mCDghq.js (new) 128 B 🔴 +128 B 🔴 +104 B 🔴 +106 B
assets/workspaceAuthStore-CSKyo6jH.js (removed) 108 B 🟢 -108 B 🟢 -99 B 🟢 -102 B
assets/workspaceAuthStore-DA0ogMDj.js (new) 108 B 🔴 +108 B 🔴 +99 B 🔴 +105 B
assets/auth-Bac8ewQR.js (removed) 105 B 🟢 -105 B 🟢 -96 B 🟢 -96 B
assets/auth-DIK6uqyX.js (new) 105 B 🔴 +105 B 🔴 +96 B 🔴 +82 B

Status: 7 added / 7 removed / 3 unchanged

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

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyHubPublishDialog-r82p1Mc7.js (removed) 90 kB 🟢 -90 kB 🟢 -19.2 kB 🟢 -16.4 kB
assets/ComfyHubPublishDialog-yD2AwG0T.js (new) 90 kB 🔴 +90 kB 🔴 +19.2 kB 🔴 +16.5 kB
assets/useShareDialog-B3z4AE_0.js (removed) 23.9 kB 🟢 -23.9 kB 🟢 -5.7 kB 🟢 -5.03 kB
assets/useShareDialog-E0FY_aQ1.js (new) 23.9 kB 🔴 +23.9 kB 🔴 +5.7 kB 🔴 +5.03 kB
assets/feedbackDialog-C_LSx3ZW.js (new) 4.45 kB 🔴 +4.45 kB 🔴 +1.87 kB 🔴 +1.59 kB
assets/feedbackDialog-SGQwXFa4.js (removed) 4.45 kB 🟢 -4.45 kB 🟢 -1.87 kB 🟢 -1.59 kB
assets/useRangeEditor-BzEkGYkl.js (new) 3.23 kB 🔴 +3.23 kB 🔴 +1.13 kB 🔴 +1.02 kB
assets/useRangeEditor-DW4QYaor.js (removed) 3.23 kB 🟢 -3.23 kB 🟢 -1.13 kB 🟢 -1.04 kB
assets/ComfyHubPublishDialog-pR6Ij8FJ.js (new) 143 B 🔴 +143 B 🔴 +105 B 🔴 +91 B
assets/ComfyHubPublishDialog-vXNeAM9J.js (removed) 143 B 🟢 -143 B 🟢 -105 B 🟢 -88 B
assets/useSubscriptionDialog-BKzlj1gP.js (removed) 108 B 🟢 -108 B 🟢 -102 B 🟢 -88 B
assets/useSubscriptionDialog-CbIDOFqB.js (new) 108 B 🔴 +108 B 🔴 +102 B 🔴 +89 B

Status: 6 added / 6 removed / 1 unchanged

UI Components — 70 kB (baseline 70 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-CYnmvV7l.js (new) 13.5 kB 🔴 +13.5 kB 🔴 +3.73 kB 🔴 +3.31 kB
assets/ComfyQueueButton-nccie_i3.js (removed) 13.5 kB 🟢 -13.5 kB 🟢 -3.73 kB 🟢 -3.32 kB
assets/useTerminalTabs-Bfu1GNX9.js (new) 11.8 kB 🔴 +11.8 kB 🔴 +3.69 kB 🔴 +3.28 kB
assets/useTerminalTabs-E5XNGPDZ.js (removed) 11.8 kB 🟢 -11.8 kB 🟢 -3.69 kB 🟢 -3.26 kB
assets/InviteMembersForm-B1dTy_3H.js (removed) 7.96 kB 🟢 -7.96 kB 🟢 -2.64 kB 🟢 -2.36 kB
assets/InviteMembersForm-CdUFVaC8.js (new) 7.96 kB 🔴 +7.96 kB 🔴 +2.64 kB 🔴 +2.36 kB
assets/SubscribeButton-C9EHulNe.js (new) 2.13 kB 🔴 +2.13 kB 🔴 +954 B 🔴 +830 B
assets/SubscribeButton-DlE_43WY.js (removed) 2.13 kB 🟢 -2.13 kB 🟢 -954 B 🟢 -831 B
assets/cloudFeedbackTopbarButton-B33aQwQM.js (new) 705 B 🔴 +705 B 🔴 +420 B 🔴 +361 B
assets/cloudFeedbackTopbarButton-Dk47lTbR.js (removed) 705 B 🟢 -705 B 🟢 -421 B 🟢 -361 B
assets/ComfyQueueButton-DS_ScxaN.js (removed) 128 B 🟢 -128 B 🟢 -99 B 🟢 -90 B
assets/ComfyQueueButton-TCALoi7R.js (new) 128 B 🔴 +128 B 🔴 +99 B 🔴 +90 B

Status: 6 added / 6 removed / 9 unchanged

Data & Services — 3.46 MB (baseline 3.46 MB) • 🔴 +1.07 kB

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/settingStore-CwnMeP-n.js (new) 3.19 MB 🔴 +3.19 MB 🔴 +737 kB 🔴 +555 kB
assets/settingStore-BzRzonzc.js (removed) 3.19 MB 🟢 -3.19 MB 🟢 -737 kB 🟢 -555 kB
assets/load3dService-BQzgfrlT.js (removed) 132 kB 🟢 -132 kB 🟢 -29.3 kB 🟢 -24.6 kB
assets/load3dService-DksQYEi0.js (new) 132 kB 🔴 +132 kB 🔴 +29.3 kB 🔴 +24.6 kB
assets/api-Bf9CcEmK.js (new) 97.1 kB 🔴 +97.1 kB 🔴 +26.8 kB 🔴 +23 kB
assets/api-S7Da-Sqi.js (removed) 97.1 kB 🟢 -97.1 kB 🟢 -26.8 kB 🟢 -23 kB
assets/workflowShareService-DC8MSVjJ.js (removed) 16.4 kB 🟢 -16.4 kB 🟢 -4.89 kB 🟢 -4.33 kB
assets/workflowShareService-EOvX19ee.js (new) 16.4 kB 🔴 +16.4 kB 🔴 +4.89 kB 🔴 +4.33 kB
assets/keybindingService-B05EMTTH.js (new) 7.16 kB 🔴 +7.16 kB 🔴 +1.83 kB 🔴 +1.59 kB
assets/keybindingService-DdrYmF9G.js (removed) 7.16 kB 🟢 -7.16 kB 🟢 -1.83 kB 🟢 -1.6 kB
assets/releaseStore-CkK1K3qk.js (removed) 6.72 kB 🟢 -6.72 kB 🟢 -2.03 kB 🟢 -1.78 kB
assets/releaseStore-CuOfiV7t.js (new) 6.72 kB 🔴 +6.72 kB 🔴 +2.03 kB 🔴 +1.77 kB
assets/systemStatsStore-BqE5a2A6.js (new) 4.93 kB 🔴 +4.93 kB 🔴 +1.74 kB 🔴 +1.47 kB
assets/systemStatsStore-Bvmh2ZcG.js (removed) 4.93 kB 🟢 -4.93 kB 🟢 -1.74 kB 🟢 -1.47 kB
assets/userStore-BIZLvdxG.js (new) 2.38 kB 🔴 +2.38 kB 🔴 +897 B 🔴 +792 B
assets/userStore-CX-cxaBz.js (removed) 2.38 kB 🟢 -2.38 kB 🟢 -898 B 🟢 -795 B
assets/audioService-C6tFNvNi.js (new) 1.71 kB 🔴 +1.71 kB 🔴 +829 B 🔴 +725 B
assets/audioService-DVgIJ7Pp.js (removed) 1.71 kB 🟢 -1.71 kB 🟢 -827 B 🟢 -723 B
assets/dialogService-B-KJqQi0.js (new) 98 B 🔴 +98 B 🔴 +97 B 🔴 +87 B
assets/dialogService-qVQ4Oah0.js (removed) 98 B 🟢 -98 B 🟢 -97 B 🟢 -84 B
assets/releaseStore-BlBKRBSd.js (removed) 95 B 🟢 -95 B 🟢 -86 B 🟢 -78 B
assets/releaseStore-CXF7RRez.js (new) 95 B 🔴 +95 B 🔴 +86 B 🔴 +86 B
assets/settingStore-Be89Du35.js (new) 95 B 🔴 +95 B 🔴 +86 B 🔴 +85 B
assets/settingStore-Bvx5amyH.js (removed) 95 B 🟢 -95 B 🟢 -86 B 🟢 -82 B
assets/assetsStore-BFN84G7X.js (removed) 94 B 🟢 -94 B 🟢 -92 B 🟢 -84 B
assets/assetsStore-DmegWgLq.js (new) 94 B 🔴 +94 B 🔴 +92 B 🔴 +88 B
assets/api-CS5Mhzqs.js (removed) 62 B 🟢 -62 B 🟢 -74 B 🟢 -66 B
assets/api-Cv7xgU8D.js (new) 62 B 🔴 +62 B 🔴 +74 B 🔴 +66 B

Status: 14 added / 14 removed / 3 unchanged

Utilities & Hooks — 386 kB (baseline 386 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useConflictDetection-BOYY5HvK.js (removed) 235 kB 🟢 -235 kB 🟢 -52.5 kB 🟢 -42.7 kB
assets/useConflictDetection-CmUhaRVo.js (new) 235 kB 🔴 +235 kB 🔴 +52.5 kB 🔴 +42.7 kB
assets/useLoad3d-DsIsK9Oe.js (removed) 25.7 kB 🟢 -25.7 kB 🟢 -5.79 kB 🟢 -5.13 kB
assets/useLoad3d-qy0BWzlP.js (new) 25.7 kB 🔴 +25.7 kB 🔴 +5.79 kB 🔴 +5.13 kB
assets/useLoad3dViewer-CJTnilc4.js (removed) 21.2 kB 🟢 -21.2 kB 🟢 -4.98 kB 🟢 -4.36 kB
assets/useLoad3dViewer-QwVThHW_.js (new) 21.2 kB 🔴 +21.2 kB 🔴 +4.98 kB 🔴 +4.38 kB
assets/useImageCrop-CXB5ylSY.js (removed) 15 kB 🟢 -15 kB 🟢 -3.42 kB 🟢 -2.99 kB
assets/useImageCrop-FslpJMw8.js (new) 15 kB 🔴 +15 kB 🔴 +3.42 kB 🔴 +2.98 kB
assets/useDowngradeToPersonal-Bl0pABCc.js (removed) 8.85 kB 🟢 -8.85 kB 🟢 -2.54 kB 🟢 -2.17 kB
assets/useDowngradeToPersonal-DNSD1dbl.js (new) 8.85 kB 🔴 +8.85 kB 🔴 +2.53 kB 🔴 +2.17 kB
assets/useFeatureFlags-CAIiViRe.js (new) 7.52 kB 🔴 +7.52 kB 🔴 +2.21 kB 🔴 +1.85 kB
assets/useFeatureFlags-CKYorjYO.js (removed) 7.52 kB 🟢 -7.52 kB 🟢 -2.21 kB 🟢 -1.85 kB
assets/assetPreviewUtil-BZoaf3yk.js (new) 2.35 kB 🔴 +2.35 kB 🔴 +967 B 🔴 +835 B
assets/assetPreviewUtil-CJ22j8NF.js (removed) 2.35 kB 🟢 -2.35 kB 🟢 -968 B 🟢 -842 B
assets/useUpstreamValue-Bth4uVAT.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +756 B 🔴 +666 B
assets/useUpstreamValue-BvEMDKvi.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -757 B 🟢 -675 B
assets/useWorkspaceTierLabel-B5WyuPkN.js (new) 1.93 kB 🔴 +1.93 kB 🔴 +813 B 🔴 +693 B
assets/useWorkspaceTierLabel-uFpA47cU.js (removed) 1.93 kB 🟢 -1.93 kB 🟢 -815 B 🟢 -698 B
assets/subscriptionCheckoutUtil-D1t5D1r5.js (new) 841 B 🔴 +841 B 🔴 +500 B 🔴 +425 B
assets/subscriptionCheckoutUtil-zrFCBOnq.js (removed) 841 B 🟢 -841 B 🟢 -502 B 🟢 -425 B
assets/useSessionCookie-B0AHWKem.js (new) 692 B 🔴 +692 B 🔴 +351 B 🔴 +314 B
assets/useSessionCookie-CkN2ua8L.js (removed) 692 B 🟢 -692 B 🟢 -354 B 🟢 -331 B
assets/useLoad3d-B9Bj0x6Z.js (new) 311 B 🔴 +311 B 🔴 +164 B 🔴 +147 B
assets/useLoad3d-DxO7IhQX.js (removed) 311 B 🟢 -311 B 🟢 -163 B 🟢 -148 B
assets/useSessionCookie-DYtOuGQC.js (removed) 101 B 🟢 -101 B 🟢 -86 B 🟢 -85 B
assets/useSessionCookie-syGQLJnj.js (new) 101 B 🔴 +101 B 🔴 +86 B 🔴 +80 B
assets/useFeatureFlags-BHYyQAaz.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +83 B
assets/useFeatureFlags-Dsh5UEru.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -83 B
assets/useLoad3dViewer-BFHX6mzD.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -85 B
assets/useLoad3dViewer-DCtxngV-.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +89 B
assets/useCurrentUser-BrNOwc94.js (removed) 94 B 🟢 -94 B 🟢 -95 B 🟢 -85 B
assets/useCurrentUser-DULWVPMd.js (new) 94 B 🔴 +94 B 🔴 +95 B 🔴 +83 B

Status: 16 added / 16 removed / 20 unchanged

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

External libraries and shared vendor chunks

Status: 16 unchanged

Other — 12.8 MB (baseline 12.8 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-BdUYtalI.js (new) 111 kB 🔴 +111 kB 🔴 +28.7 kB 🔴 +24.3 kB
assets/core-CtdnLAk1.js (removed) 111 kB 🟢 -111 kB 🟢 -28.7 kB 🟢 -24.3 kB
assets/WidgetSelect-0Ew1jBTF.js (removed) 88 kB 🟢 -88 kB 🟢 -19.9 kB 🟢 -17 kB
assets/WidgetSelect-BG9cjPNU.js (new) 88 kB 🔴 +88 kB 🔴 +19.9 kB 🔴 +17 kB
assets/Load3D-BOwaWfa7.js (removed) 71.3 kB 🟢 -71.3 kB 🟢 -11.7 kB 🟢 -9.98 kB
assets/Load3D-CeJEGcHc.js (new) 71.3 kB 🔴 +71.3 kB 🔴 +11.7 kB 🔴 +9.96 kB
assets/WidgetVideoEdit-BqJxcngo.js (removed) 63.4 kB 🟢 -63.4 kB 🟢 -14.6 kB 🟢 -12.8 kB
assets/WidgetVideoEdit-n7dQxZOI.js (new) 63.4 kB 🔴 +63.4 kB 🔴 +14.6 kB 🔴 +12.9 kB
assets/SubscriptionTransitionPreviewWorkspace-BTHb-nvB.js (new) 63.1 kB 🔴 +63.1 kB 🔴 +13 kB 🔴 +11.4 kB
assets/SubscriptionTransitionPreviewWorkspace-DZPtZSjR.js (removed) 63.1 kB 🟢 -63.1 kB 🟢 -13 kB 🟢 -11.3 kB
assets/WorkspaceSettingsPanelContent-DabU7ofe.js (new) 61.6 kB 🔴 +61.6 kB 🔴 +13.1 kB 🔴 +11.4 kB
assets/WorkspaceSettingsPanelContent-QtlPVDgk.js (removed) 61.6 kB 🟢 -61.6 kB 🟢 -13.1 kB 🟢 -11.5 kB
assets/Preview3d-C5XbbcBU.js (removed) 50.9 kB 🟢 -50.9 kB 🟢 -8.31 kB 🟢 -7.26 kB
assets/Preview3d-CUmMTkS2.js (new) 50.9 kB 🔴 +50.9 kB 🔴 +8.31 kB 🔴 +7.25 kB
assets/main-Cp0DsCsI.js (new) 47 kB 🔴 +47 kB 🔴 +13.9 kB 🔴 +12 kB
assets/main-DmUWS9pz.js (removed) 47 kB 🟢 -47 kB 🟢 -13.9 kB 🟢 -12 kB
assets/SubscriptionRequiredDialogContentUnified-CAvqmEtg.js (removed) 42.9 kB 🟢 -42.9 kB 🟢 -9.46 kB 🟢 -8.25 kB
assets/SubscriptionRequiredDialogContentUnified-CCCHpKwG.js (new) 42.9 kB 🔴 +42.9 kB 🔴 +9.46 kB 🔴 +8.24 kB
assets/MembersPanelContent-CpFt7JBf.js (new) 41.8 kB 🔴 +41.8 kB 🔴 +8.79 kB 🔴 +7.82 kB
assets/MembersPanelContent-FsAKkg9Y.js (removed) 41.8 kB 🟢 -41.8 kB 🟢 -8.79 kB 🟢 -7.82 kB
assets/WidgetBoundingBoxes-BNpWrb1V.js (new) 33.7 kB 🔴 +33.7 kB 🔴 +9.16 kB 🔴 +8.12 kB
assets/WidgetBoundingBoxes-CfRzoLdf.js (removed) 33.7 kB 🟢 -33.7 kB 🟢 -9.16 kB 🟢 -8.12 kB
assets/WidgetPainter-Bu9GDL_z.js (new) 32.6 kB 🔴 +32.6 kB 🔴 +7.87 kB 🔴 +6.97 kB
assets/WidgetPainter-Gd6F_nvy.js (removed) 32.6 kB 🟢 -32.6 kB 🟢 -7.87 kB 🟢 -6.95 kB
assets/SubscriptionPanelContentWorkspace-CBADsYG6.js (new) 31.8 kB 🔴 +31.8 kB 🔴 +7.05 kB 🔴 +6.21 kB
assets/SubscriptionPanelContentWorkspace-CQVnyiTc.js (removed) 31.8 kB 🟢 -31.8 kB 🟢 -7.05 kB 🟢 -6.2 kB
assets/Load3dViewerContent-BWDg1XwU.js (new) 30.8 kB 🔴 +30.8 kB 🔴 +6.27 kB 🔴 +5.44 kB
assets/Load3dViewerContent-C7-eg9JX.js (removed) 30.8 kB 🟢 -30.8 kB 🟢 -6.26 kB 🟢 -5.44 kB
assets/SubscriptionRequiredDialogContent-CZDwE3sq.js (new) 26.1 kB 🔴 +26.1 kB 🔴 +6.14 kB 🔴 +5.4 kB
assets/SubscriptionRequiredDialogContent-D925sDtL.js (removed) 26.1 kB 🟢 -26.1 kB 🟢 -6.14 kB 🟢 -5.41 kB
assets/SubscriptionRequiredDialogContentWorkspace-6co7bVbv.js (removed) 25.1 kB 🟢 -25.1 kB 🟢 -5.8 kB 🟢 -5.1 kB
assets/SubscriptionRequiredDialogContentWorkspace-D8skiiez.js (new) 25.1 kB 🔴 +25.1 kB 🔴 +5.8 kB 🔴 +5.1 kB
assets/load3d-Dg3eWY4w.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -5.4 kB 🟢 -4.67 kB
assets/load3d-DN2uYjzz.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +5.41 kB 🔴 +4.67 kB
assets/CurrentUserPopoverWorkspace-CR5LtbC6.js (removed) 20.6 kB 🟢 -20.6 kB 🟢 -4.72 kB 🟢 -4.2 kB
assets/CurrentUserPopoverWorkspace-DD9nSuC4.js (new) 20.6 kB 🔴 +20.6 kB 🔴 +4.72 kB 🔴 +4.2 kB
assets/SignInContent-CrKsgjUl.js (new) 20.2 kB 🔴 +20.2 kB 🔴 +5.1 kB 🔴 +4.45 kB
assets/SignInContent-DdnbvQg3.js (removed) 20.2 kB 🟢 -20.2 kB 🟢 -5.1 kB 🟢 -4.45 kB
assets/CreditsTile-Cnz2awvS.js (removed) 19 kB 🟢 -19 kB 🟢 -4.79 kB 🟢 -4.22 kB
assets/CreditsTile-OIHyw5fm.js (new) 19 kB 🔴 +19 kB 🔴 +4.79 kB 🔴 +4.23 kB
assets/WidgetRecordAudio-BELH6BPL.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.59 kB 🔴 +4.09 kB
assets/WidgetRecordAudio-CJRAvKms.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.6 kB 🟢 -4.09 kB
assets/WidgetInputNumber-BFxMI6MY.js (new) 13.9 kB 🔴 +13.9 kB 🔴 +3.63 kB 🔴 +3.22 kB
assets/WidgetInputNumber-DOBiLYv_.js (removed) 13.9 kB 🟢 -13.9 kB 🟢 -3.63 kB 🟢 -3.21 kB
assets/WidgetRange-e0YhLeBe.js (new) 13.7 kB 🔴 +13.7 kB 🔴 +3.53 kB 🔴 +3.12 kB
assets/WidgetRange-IclDtlt3.js (removed) 13.7 kB 🟢 -13.7 kB 🟢 -3.53 kB 🟢 -3.11 kB
assets/WaveAudioPlayer-2Wqj-lvP.js (new) 12.8 kB 🔴 +12.8 kB 🔴 +3.46 kB 🔴 +3.04 kB
assets/WaveAudioPlayer-DJjFGuls.js (removed) 12.8 kB 🟢 -12.8 kB 🟢 -3.46 kB 🟢 -3.04 kB
assets/WidgetCurve-Bi2tZl4T.js (removed) 11.2 kB 🟢 -11.2 kB 🟢 -3.47 kB 🟢 -3.13 kB
assets/WidgetCurve-CbAumm2T.js (new) 11.2 kB 🔴 +11.2 kB 🔴 +3.47 kB 🔴 +3.15 kB
assets/TeamWorkspacesDialogContent-Brg6-ZxN.js (new) 10.3 kB 🔴 +10.3 kB 🔴 +2.97 kB 🔴 +2.63 kB
assets/TeamWorkspacesDialogContent-DrWDu0oS.js (removed) 10.3 kB 🟢 -10.3 kB 🟢 -2.97 kB 🟢 -2.63 kB
assets/onboardingCloudRoutes-CbkKPiCQ.js (removed) 9.13 kB 🟢 -9.13 kB 🟢 -2.79 kB 🟢 -2.41 kB
assets/onboardingCloudRoutes-e2WJHHk8.js (new) 9.13 kB 🔴 +9.13 kB 🔴 +2.79 kB 🔴 +2.41 kB
assets/Load3DConfiguration-DCVcVYfk.js (removed) 8.91 kB 🟢 -8.91 kB 🟢 -2.6 kB 🟢 -2.29 kB
assets/Load3DConfiguration-Dpz5Z6d8.js (new) 8.91 kB 🔴 +8.91 kB 🔴 +2.61 kB 🔴 +2.3 kB
assets/WidgetImageCrop-B3HkaL9S.js (new) 8.49 kB 🔴 +8.49 kB 🔴 +2.65 kB 🔴 +2.34 kB
assets/WidgetImageCrop-Ce49yhW-.js (removed) 8.49 kB 🟢 -8.49 kB 🟢 -2.65 kB 🟢 -2.34 kB
assets/SetMemberCreditLimitDialogContent-BQOEj6NP.js (removed) 8.47 kB 🟢 -8.47 kB 🟢 -2.34 kB 🟢 -2.06 kB
assets/SetMemberCreditLimitDialogContent-MQcrBNdd.js (new) 8.47 kB 🔴 +8.47 kB 🔴 +2.33 kB 🔴 +2.04 kB
assets/nodeTemplates-B0Yd0y7V.js (new) 8.28 kB 🔴 +8.28 kB 🔴 +2.84 kB 🔴 +2.51 kB
assets/nodeTemplates-CvvsQMea.js (removed) 8.28 kB 🟢 -8.28 kB 🟢 -2.84 kB 🟢 -2.51 kB
assets/NightlySurveyController-BGfEWrOB.js (new) 7.5 kB 🔴 +7.5 kB 🔴 +2.55 kB 🔴 +2.24 kB
assets/NightlySurveyController-C3T8EahC.js (removed) 7.5 kB 🟢 -7.5 kB 🟢 -2.55 kB 🟢 -2.24 kB
assets/WidgetWithControl-B2vIO1Zt.js (removed) 6.37 kB 🟢 -6.37 kB 🟢 -2.59 kB 🟢 -2.29 kB
assets/WidgetWithControl-CZHmtG4u.js (new) 6.37 kB 🔴 +6.37 kB 🔴 +2.59 kB 🔴 +2.29 kB
assets/tierBenefits-DFVNz6Q-.js (new) 6.2 kB 🔴 +6.2 kB 🔴 +1.97 kB 🔴 +1.72 kB
assets/tierBenefits-Dgk1iKgt.js (removed) 6.2 kB 🟢 -6.2 kB 🟢 -1.97 kB 🟢 -1.71 kB
assets/CancelSubscriptionDialogContent-3xmAhfo-.js (removed) 5.97 kB 🟢 -5.97 kB 🟢 -1.98 kB 🟢 -1.74 kB
assets/CancelSubscriptionDialogContent-BDNnHGFv.js (new) 5.97 kB 🔴 +5.97 kB 🔴 +1.98 kB 🔴 +1.74 kB
assets/load3dPreviewExtensions-BgZWlyl2.js (removed) 5.88 kB 🟢 -5.88 kB 🟢 -1.81 kB 🟢 -1.6 kB
assets/load3dPreviewExtensions-CGCH0feI.js (new) 5.88 kB 🔴 +5.88 kB 🔴 +1.81 kB 🔴 +1.6 kB
assets/missingModelDownload-BSnHuNCy.js (removed) 5.88 kB 🟢 -5.88 kB 🟢 -2.07 kB 🟢 -1.81 kB
assets/missingModelDownload-DJGGfrIp.js (new) 5.88 kB 🔴 +5.88 kB 🔴 +2.07 kB 🔴 +1.81 kB
assets/launchCancellationFlow-BCnxyp_a.js (removed) 5.18 kB 🟢 -5.18 kB 🟢 -1.78 kB 🟢 -1.56 kB
assets/launchCancellationFlow-pUO3OVzl.js (new) 5.18 kB 🔴 +5.18 kB 🔴 +1.77 kB 🔴 +1.55 kB
assets/CreateWorkspaceDialogContent-Bpaf-jO-.js (removed) 5.12 kB 🟢 -5.12 kB 🟢 -1.79 kB 🟢 -1.55 kB
assets/CreateWorkspaceDialogContent-tGQ4HL8g.js (new) 5.12 kB 🔴 +5.12 kB 🔴 +1.79 kB 🔴 +1.55 kB
assets/ChangeMemberRoleDialogContent-704_XTuE.js (new) 4.97 kB 🔴 +4.97 kB 🔴 +1.63 kB 🔴 +1.42 kB
assets/ChangeMemberRoleDialogContent-DQ3FzCqf.js (removed) 4.97 kB 🟢 -4.97 kB 🟢 -1.63 kB 🟢 -1.43 kB
assets/EditWorkspaceDialogContent-Bmrt3Kux.js (new) 4.93 kB 🔴 +4.93 kB 🔴 +1.76 kB 🔴 +1.52 kB
assets/EditWorkspaceDialogContent-D69D-h1t.js (removed) 4.93 kB 🟢 -4.93 kB 🟢 -1.76 kB 🟢 -1.53 kB
assets/WidgetTextarea-CgyMZM5S.js (removed) 4.81 kB 🟢 -4.81 kB 🟢 -1.87 kB 🟢 -1.63 kB
assets/WidgetTextarea-CW4jJqRP.js (new) 4.81 kB 🔴 +4.81 kB 🔴 +1.87 kB 🔴 +1.63 kB
assets/saveMesh-BaAa1bRp.js (removed) 4.76 kB 🟢 -4.76 kB 🟢 -1.52 kB 🟢 -1.35 kB
assets/saveMesh-CiORS301.js (new) 4.76 kB 🔴 +4.76 kB 🔴 +1.52 kB 🔴 +1.34 kB
assets/WorkspacePanelContent-7wdxa1IR.js (new) 4.72 kB 🔴 +4.72 kB 🔴 +1.6 kB 🔴 +1.4 kB
assets/WorkspacePanelContent-B-NMQ2_T.js (removed) 4.72 kB 🟢 -4.72 kB 🟢 -1.6 kB 🟢 -1.4 kB
assets/InviteMemberDialogContent-B-cug2Gh.js (new) 4.68 kB 🔴 +4.68 kB 🔴 +1.58 kB 🔴 +1.37 kB
assets/InviteMemberDialogContent-DJf2QKMa.js (removed) 4.68 kB 🟢 -4.68 kB 🟢 -1.58 kB 🟢 -1.38 kB
assets/ValueControlPopover-Bi1UkZcu.js (removed) 4.49 kB 🟢 -4.49 kB 🟢 -1.55 kB 🟢 -1.38 kB
assets/ValueControlPopover-Bs4zpJjC.js (new) 4.49 kB 🔴 +4.49 kB 🔴 +1.54 kB 🔴 +1.38 kB
assets/DeleteWorkspaceDialogContent-Biq3IKg3.js (new) 3.84 kB 🔴 +3.84 kB 🔴 +1.44 kB 🔴 +1.23 kB
assets/DeleteWorkspaceDialogContent-DmLco0yt.js (removed) 3.84 kB 🟢 -3.84 kB 🟢 -1.44 kB 🟢 -1.23 kB
assets/LeaveWorkspaceDialogContent-CQ8fhwIC.js (new) 3.67 kB 🔴 +3.67 kB 🔴 +1.38 kB 🔴 +1.18 kB
assets/LeaveWorkspaceDialogContent-DpWyprqS.js (removed) 3.67 kB 🟢 -3.67 kB 🟢 -1.38 kB 🟢 -1.18 kB
assets/RemoveMemberDialogContent-DCLz9B42.js (removed) 3.65 kB 🟢 -3.65 kB 🟢 -1.33 kB 🟢 -1.15 kB
assets/RemoveMemberDialogContent-DTqY0wTi.js (new) 3.65 kB 🔴 +3.65 kB 🔴 +1.33 kB 🔴 +1.15 kB
assets/RevokeInviteDialogContent-B4UU1Hc3.js (new) 3.56 kB 🔴 +3.56 kB 🔴 +1.34 kB 🔴 +1.17 kB
assets/RevokeInviteDialogContent-DGwTxEP0.js (removed) 3.56 kB 🟢 -3.56 kB 🟢 -1.35 kB 🟢 -1.17 kB
assets/InviteMemberUpsellDialogContent-ClAUNj0e.js (new) 3.44 kB 🔴 +3.44 kB 🔴 +1.23 kB 🔴 +1.08 kB
assets/InviteMemberUpsellDialogContent-D4ODfA_n.js (removed) 3.44 kB 🟢 -3.44 kB 🟢 -1.23 kB 🟢 -1.08 kB
assets/workspaceCheckoutTelemetry-D1d2KARc.js (removed) 3.4 kB 🟢 -3.4 kB 🟢 -1.52 kB 🟢 -1.33 kB
assets/workspaceCheckoutTelemetry-DTBUqLS8.js (new) 3.4 kB 🔴 +3.4 kB 🔴 +1.52 kB 🔴 +1.32 kB
assets/Media3DTop-DOf2E1aK.js (removed) 3.21 kB 🟢 -3.21 kB 🟢 -1.27 kB 🟢 -1.1 kB
assets/Media3DTop-DRnyze6y.js (new) 3.21 kB 🔴 +3.21 kB 🔴 +1.26 kB 🔴 +1.1 kB
assets/GlobalToast-CdNDZysn.js (removed) 3 kB 🟢 -3 kB 🟢 -1.22 kB 🟢 -1.04 kB
assets/GlobalToast-t4FFvWMu.js (new) 3 kB 🔴 +3 kB 🔴 +1.22 kB 🔴 +1.06 kB
assets/load3dAdvanced-CnxNHHZy.js (new) 2.82 kB 🔴 +2.82 kB 🔴 +1.09 kB 🔴 +954 B
assets/load3dAdvanced-D7RbQqsB.js (removed) 2.82 kB 🟢 -2.82 kB 🟢 -1.09 kB 🟢 -955 B
assets/SubscribeToRun-CGMgFQFH.js (new) 2.39 kB 🔴 +2.39 kB 🔴 +1.03 kB 🔴 +924 B
assets/SubscribeToRun-CmgZUvX8.js (removed) 2.39 kB 🟢 -2.39 kB 🟢 -1.03 kB 🟢 -900 B
assets/MediaAudioTop-BsNQms5f.js (removed) 1.62 kB 🟢 -1.62 kB 🟢 -806 B 🟢 -667 B
assets/MediaAudioTop-CDnSwCZQ.js (new) 1.62 kB 🔴 +1.62 kB 🔴 +805 B 🔴 +664 B
assets/CloudRunButtonWrapper-CgR9-wor.js (new) 1.05 kB 🔴 +1.05 kB 🔴 +512 B 🔴 +450 B
assets/CloudRunButtonWrapper-Dgmuzghp.js (removed) 1.05 kB 🟢 -1.05 kB 🟢 -511 B 🟢 -450 B
assets/cloudSessionCookie-Bp1AoK84.js (removed) 933 B 🟢 -933 B 🟢 -430 B 🟢 -375 B
assets/cloudSessionCookie-Cmqs1gyB.js (new) 933 B 🔴 +933 B 🔴 +430 B 🔴 +376 B
assets/cloudBadges-BeYGGB_C.js (removed) 922 B 🟢 -922 B 🟢 -512 B 🟢 -434 B
assets/cloudBadges-Y2SHsJSb.js (new) 922 B 🔴 +922 B 🔴 +512 B 🔴 +434 B
assets/Load3DAdvanced-BIUi_BuF.js (removed) 761 B 🟢 -761 B 🟢 -423 B 🟢 -356 B
assets/Load3DAdvanced-BjD9Ogvs.js (new) 761 B 🔴 +761 B 🔴 +422 B 🔴 +356 B
assets/nightlyBadges-DjRNdtD7.js (new) 411 B 🔴 +411 B 🔴 +270 B 🔴 +229 B
assets/nightlyBadges-MRE7I6Ej.js (removed) 411 B 🟢 -411 B 🟢 -271 B 🟢 -258 B
assets/missingModelDownload-BLFQiU8z.js (new) 371 B 🔴 +371 B 🔴 +202 B 🔴 +173 B
assets/missingModelDownload-CKc4j80a.js (removed) 371 B 🟢 -371 B 🟢 -203 B 🟢 -173 B
assets/SubscriptionPanelContentWorkspace-C4q-FHGv.js (removed) 179 B 🟢 -179 B 🟢 -117 B 🟢 -92 B
assets/SubscriptionPanelContentWorkspace-nAsbW_VY.js (new) 179 B 🔴 +179 B 🔴 +117 B 🔴 +105 B
assets/Load3dViewerContent-DcN1YGl0.js (new) 137 B 🔴 +137 B 🔴 +103 B 🔴 +85 B
assets/Load3dViewerContent-f4vmHL1v.js (removed) 137 B 🟢 -137 B 🟢 -103 B 🟢 -106 B
assets/Load3DAdvanced-CUMkb8NW.js (removed) 122 B 🟢 -122 B 🟢 -97 B 🟢 -91 B
assets/Load3DAdvanced-CuQD_0lO.js (new) 122 B 🔴 +122 B 🔴 +97 B 🔴 +97 B
assets/WidgetLegacy-BDb1dZS9.js (new) 117 B 🔴 +117 B 🔴 +106 B 🔴 +103 B
assets/WidgetLegacy-COU0qvsC.js (removed) 117 B 🟢 -117 B 🟢 -106 B 🟢 -96 B
assets/workflowDraftStoreV2-722H6mfd.js (removed) 112 B 🟢 -112 B 🟢 -101 B 🟢 -110 B
assets/workflowDraftStoreV2-DkLHTSp5.js (new) 112 B 🔴 +112 B 🔴 +101 B 🔴 +110 B
assets/Load3D-BIKYTwkC.js (new) 98 B 🔴 +98 B 🔴 +89 B 🔴 +78 B
assets/Load3D-ClKMbJIS.js (removed) 98 B 🟢 -98 B 🟢 -89 B 🟢 -93 B
assets/changeTracker-3Wdb0SbZ.js (new) 91 B 🔴 +91 B 🔴 +93 B 🔴 +86 B
assets/changeTracker-CAwRENa2.js (removed) 91 B 🟢 -91 B 🟢 -93 B 🟢 -75 B

Status: 70 added / 70 removed / 211 unchanged

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 66.3 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 51.8 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 69.1 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 49.8 MB heap
large-graph-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 63.3 MB heap
large-graph-pan: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.4 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 52.3 MB heap
minimap-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.9 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 51.0 MB heap
subgraph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 66.0 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 57.0 MB heap
subgraph-transition-enter: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 100ms TBT · 95.5 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 67.0 MB heap
vue-large-graph-idle: · 58.1 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 152.1 MB heap
vue-large-graph-pan: · 57.1 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 21ms TBT · 162.7 MB heap
workflow-execution: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.3 MB heap

✅ No regressions detected.

All metrics
Metric Baseline PR (median) Δ Sig
canvas-idle: avg frame time 17ms 17ms +0% z=0.4
canvas-idle: p95 frame time 17ms 17ms +0%
canvas-idle: layout duration 0ms 0ms +0%
canvas-idle: style recalc duration 7ms 6ms -20% z=-5.7
canvas-idle: layout count 0 0 +0%
canvas-idle: style recalc count 9 10 +6% z=-2.9
canvas-idle: task duration 443ms 420ms -5% z=0.8
canvas-idle: script duration 14ms 14ms -3% z=-5.0
canvas-idle: TBT 0ms 0ms +0%
canvas-idle: heap used 66.2 MB 66.3 MB +0%
canvas-idle: DOM nodes 18 19 +6% z=-2.8
canvas-idle: event listeners 4 5 +25% z=-1.4
canvas-mouse-sweep: avg frame time 17ms 17ms -0% z=-0.9
canvas-mouse-sweep: p95 frame time 17ms 17ms +0%
canvas-mouse-sweep: layout duration 3ms 3ms -10% z=-3.7
canvas-mouse-sweep: style recalc duration 37ms 26ms -29% z=-5.3
canvas-mouse-sweep: layout count 12 12 +0%
canvas-mouse-sweep: style recalc count 75 74 -2% z=-2.2
canvas-mouse-sweep: task duration 891ms 693ms -22% z=-3.0
canvas-mouse-sweep: script duration 121ms 89ms -27% z=-7.2
canvas-mouse-sweep: TBT 0ms 0ms +0%
canvas-mouse-sweep: heap used 44.2 MB 51.8 MB +17%
canvas-mouse-sweep: DOM nodes -278 39 -114% z=-9.0
canvas-mouse-sweep: event listeners -153 -71 -54% z=-19.1
canvas-zoom-sweep: avg frame time 17ms 17ms +0% z=-0.3
canvas-zoom-sweep: p95 frame time 17ms 17ms +0%
canvas-zoom-sweep: layout duration 1ms 1ms -8% z=-2.0
canvas-zoom-sweep: style recalc duration 17ms 12ms -25% z=-4.3
canvas-zoom-sweep: layout count 6 6 +0%
canvas-zoom-sweep: style recalc count 32 31 -5% z=-1.7
canvas-zoom-sweep: task duration 373ms 309ms -17% z=-0.8
canvas-zoom-sweep: script duration 18ms 15ms -15% z=-4.0
canvas-zoom-sweep: TBT 0ms 0ms +0%
canvas-zoom-sweep: heap used 69.0 MB 69.1 MB +0%
canvas-zoom-sweep: DOM nodes 78 79 +1% z=-0.9
canvas-zoom-sweep: event listeners 19 20 +5% z=-0.7
dom-widget-clipping: avg frame time 17ms 17ms +0% z=0.9
dom-widget-clipping: p95 frame time 17ms 17ms -0%
dom-widget-clipping: layout duration 0ms 0ms +0%
dom-widget-clipping: style recalc duration 8ms 6ms -33% z=-5.3
dom-widget-clipping: layout count 0 0 +0%
dom-widget-clipping: style recalc count 12 13 +8% z=-0.2
dom-widget-clipping: task duration 390ms 285ms -27% z=-4.9
dom-widget-clipping: script duration 59ms 39ms -34% z=-8.9
dom-widget-clipping: TBT 0ms 0ms +0%
dom-widget-clipping: heap used 50.5 MB 49.8 MB -1%
dom-widget-clipping: DOM nodes 20 22 +10% z=-0.1
dom-widget-clipping: event listeners 0 2 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 7ms 5ms -24% z=-6.5
large-graph-idle: layout count 0 0 +0%
large-graph-idle: style recalc count 8 10 +25% z=-5.1
large-graph-idle: task duration 662ms 563ms -15% z=0.4
large-graph-idle: script duration 104ms 69ms -33% z=-3.1
large-graph-idle: TBT 0ms 0ms +0%
large-graph-idle: heap used 62.6 MB 63.3 MB +1%
large-graph-idle: DOM nodes -282 -279 -1% z=-336.0
large-graph-idle: event listeners -147 -164 +12% z=-31.2
large-graph-pan: avg frame time 17ms 17ms +0% z=0.8
large-graph-pan: p95 frame time 17ms 17ms -0%
large-graph-pan: layout duration 0ms 0ms +0%
large-graph-pan: style recalc duration 13ms 10ms -21% z=-8.6
large-graph-pan: layout count 0 0 +0%
large-graph-pan: style recalc count 68 68 +0% z=-2.4
large-graph-pan: task duration 1251ms 1006ms -20% z=-1.8
large-graph-pan: script duration 423ms 316ms -25% z=-4.7
large-graph-pan: TBT 0ms 0ms +0%
large-graph-pan: heap used 61.1 MB 61.4 MB +0%
large-graph-pan: DOM nodes -284 -282 -1% z=-182.1
large-graph-pan: event listeners -151 -148 -2% z=-184.7
large-graph-zoom: avg frame time 17ms 17ms -0%
large-graph-zoom: p95 frame time 17ms 17ms +0%
large-graph-zoom: layout duration 7ms 7ms +1%
large-graph-zoom: style recalc duration 14ms 13ms -5%
large-graph-zoom: layout count 60 60 +0%
large-graph-zoom: style recalc count 65 66 +1%
large-graph-zoom: task duration 1453ms 1202ms -17%
large-graph-zoom: script duration 511ms 378ms -26%
large-graph-zoom: TBT 0ms 0ms +0%
large-graph-zoom: heap used 53.8 MB 52.3 MB -3%
large-graph-zoom: DOM nodes -287 -137 -52%
large-graph-zoom: event listeners -153 -166 +8%
minimap-idle: avg frame time 17ms 17ms -0% z=-0.4
minimap-idle: p95 frame time 17ms 17ms -0%
minimap-idle: layout duration 0ms 0ms +0%
minimap-idle: style recalc duration 7ms 6ms -18% z=-4.8
minimap-idle: layout count 0 0 +0%
minimap-idle: style recalc count 8 9 +13% z=-0.8
minimap-idle: task duration 660ms 556ms -16% z=0.6
minimap-idle: script duration 102ms 69ms -32% z=-3.0
minimap-idle: TBT 0ms 0ms +0%
minimap-idle: heap used 64.4 MB 65.9 MB +2%
minimap-idle: DOM nodes -285 -284 -0% z=-221.6
minimap-idle: event listeners -149 -149 +0% z=-232.6
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 10ms 8ms -26% z=-5.3
subgraph-dom-widget-clipping: layout count 0 0 +0%
subgraph-dom-widget-clipping: style recalc count 46 48 +4% z=0.1
subgraph-dom-widget-clipping: task duration 402ms 310ms -23% z=-3.7
subgraph-dom-widget-clipping: script duration 121ms 86ms -29% z=-6.6
subgraph-dom-widget-clipping: TBT 0ms 0ms +0%
subgraph-dom-widget-clipping: heap used 50.8 MB 51.0 MB +0%
subgraph-dom-widget-clipping: DOM nodes 18 22 +22% z=-0.2
subgraph-dom-widget-clipping: event listeners 6 7 +17% z=-1.6
subgraph-idle: avg frame time 17ms 17ms +0% z=0.9
subgraph-idle: p95 frame time 17ms 17ms -1%
subgraph-idle: layout duration 0ms 0ms +0%
subgraph-idle: style recalc duration 8ms 6ms -30% z=-5.9
subgraph-idle: layout count 0 0 +0%
subgraph-idle: style recalc count 10 10 +0% z=-1.4
subgraph-idle: task duration 440ms 392ms -11% z=0.7
subgraph-idle: script duration 13ms 12ms -5% z=-3.1
subgraph-idle: TBT 0ms 0ms +0%
subgraph-idle: heap used 66.1 MB 66.0 MB -0%
subgraph-idle: DOM nodes 20 20 +0% z=-1.2
subgraph-idle: event listeners 4 6 +50% 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 3ms -17% z=-4.2
subgraph-mouse-sweep: style recalc duration 36ms 28ms -22% z=-4.3
subgraph-mouse-sweep: layout count 16 16 +0%
subgraph-mouse-sweep: style recalc count 75 76 +1% z=-2.1
subgraph-mouse-sweep: task duration 754ms 611ms -19% z=-2.2
subgraph-mouse-sweep: script duration 89ms 65ms -28% z=-5.5
subgraph-mouse-sweep: TBT 0ms 0ms +0%
subgraph-mouse-sweep: heap used 57.0 MB 57.0 MB -0%
subgraph-mouse-sweep: DOM nodes 63 64 +1% z=-1.5
subgraph-mouse-sweep: event listeners 4 5 +25% variance too high
subgraph-transition-enter: avg frame time 17ms 17ms +0%
subgraph-transition-enter: p95 frame time 17ms 17ms +0%
subgraph-transition-enter: layout duration 13ms 9ms -33%
subgraph-transition-enter: style recalc duration 30ms 23ms -24%
subgraph-transition-enter: layout count 14 15 +7%
subgraph-transition-enter: style recalc count 18 19 +6%
subgraph-transition-enter: task duration 705ms 717ms +2%
subgraph-transition-enter: script duration 25ms 21ms -16%
subgraph-transition-enter: TBT 132ms 100ms -24%
subgraph-transition-enter: heap used 92.5 MB 95.5 MB +3%
subgraph-transition-enter: DOM nodes 13673 13673 +0%
subgraph-transition-enter: event listeners 2371 2369 -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 35ms 29ms -18%
viewport-pan-sweep: layout count 0 0 +0%
viewport-pan-sweep: style recalc count 250 250 -0%
viewport-pan-sweep: task duration 4356ms 3386ms -22%
viewport-pan-sweep: script duration 1363ms 957ms -30%
viewport-pan-sweep: TBT 0ms 0ms +0%
viewport-pan-sweep: heap used 65.6 MB 67.0 MB +2%
viewport-pan-sweep: DOM nodes -281 -279 -1%
viewport-pan-sweep: event listeners -133 -133 +0%
vue-large-graph-idle: avg frame time 18ms 17ms -3%
vue-large-graph-idle: p95 frame time 17ms 17ms -0%
vue-large-graph-idle: layout duration 0ms 0ms +0%
vue-large-graph-idle: style recalc duration 0ms 0ms +0%
vue-large-graph-idle: layout count 0 0 +0%
vue-large-graph-idle: style recalc count 0 0 +0%
vue-large-graph-idle: task duration 16111ms 11956ms -26%
vue-large-graph-idle: script duration 523ms 435ms -17%
vue-large-graph-idle: TBT 0ms 0ms +0%
vue-large-graph-idle: heap used 158.6 MB 152.1 MB -4%
vue-large-graph-idle: DOM nodes -8312 -8312 +0%
vue-large-graph-idle: event listeners -16387 -16390 +0%
vue-large-graph-pan: avg frame time 18ms 17ms -2%
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 15ms 13ms -13%
vue-large-graph-pan: layout count 0 0 +0%
vue-large-graph-pan: style recalc count 135 73 -46%
vue-large-graph-pan: task duration 20087ms 14654ms -27%
vue-large-graph-pan: script duration 889ms 714ms -20%
vue-large-graph-pan: TBT 119ms 21ms -83%
vue-large-graph-pan: heap used 156.8 MB 162.7 MB +4%
vue-large-graph-pan: DOM nodes -8312 -8312 +0%
vue-large-graph-pan: event listeners -16383 -16388 +0%
workflow-execution: avg frame time 17ms 17ms +0% z=1.1
workflow-execution: p95 frame time 17ms 17ms +0%
workflow-execution: layout duration 1ms 0ms -69% z=-7.7
workflow-execution: style recalc duration 20ms 14ms -33% z=-4.8
workflow-execution: layout count 3 3 -17% z=-4.5
workflow-execution: style recalc count 14 14 +0% z=-1.9
workflow-execution: task duration 107ms 88ms -17% z=-3.2
workflow-execution: script duration 9ms 7ms -15% z=-7.3
workflow-execution: TBT 0ms 0ms +0%
workflow-execution: heap used 65.0 MB 65.3 MB +1%
workflow-execution: DOM nodes 133 131 -2% z=-4.3
workflow-execution: event listeners 97 98 +1% z=10.6
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-08-04T03:12:52.371Z",
  "gitSha": "2bfa3f0a87ab25570efcf3a2a3bf3ea2d3c90f0c",
  "branch": "fix/subgraph-preview-allowlist-gap",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2021.1309999999685,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 5.281999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 453.36199999999997,
      "heapDeltaBytes": 5381736,
      "heapUsedBytes": 69290936,
      "domNodes": 18,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 14.692000000000002,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-idle",
      "durationMs": 2014.0240000000063,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 6.179,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 386.20500000000004,
      "heapDeltaBytes": 5592124,
      "heapUsedBytes": 69697864,
      "domNodes": 20,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 13.383000000000001,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1751.2869999999907,
      "styleRecalcs": 72,
      "styleRecalcDurationMs": 24.945,
      "layouts": 12,
      "layoutDurationMs": 2.8930000000000002,
      "taskDurationMs": 667.5920000000001,
      "heapDeltaBytes": -654360,
      "heapUsedBytes": 63249000,
      "domNodes": 54,
      "jsHeapTotalBytes": 26214400,
      "scriptDurationMs": 88.27399999999999,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1779.9759999999765,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 26.991,
      "layouts": 12,
      "layoutDurationMs": 2.8600000000000003,
      "taskDurationMs": 719.308,
      "heapDeltaBytes": -18635724,
      "heapUsedBytes": 45409116,
      "domNodes": 24,
      "jsHeapTotalBytes": 23576576,
      "scriptDurationMs": 89.426,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1684.0610000000424,
      "styleRecalcs": 30,
      "styleRecalcDurationMs": 11.988999999999997,
      "layouts": 6,
      "layoutDurationMs": 0.582,
      "taskDurationMs": 299.70199999999994,
      "heapDeltaBytes": 8213436,
      "heapUsedBytes": 72241392,
      "domNodes": 79,
      "jsHeapTotalBytes": 24641536,
      "scriptDurationMs": 14.371000000000002,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1710.3399999999738,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 12.972000000000001,
      "layouts": 6,
      "layoutDurationMs": 0.52,
      "taskDurationMs": 317.791,
      "heapDeltaBytes": 8673864,
      "heapUsedBytes": 72738380,
      "domNodes": 78,
      "jsHeapTotalBytes": 24379392,
      "scriptDurationMs": 15.888,
      "eventListeners": 21,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 501.9790000000057,
      "styleRecalcs": 14,
      "styleRecalcDurationMs": 6.005,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 286.216,
      "heapDeltaBytes": -11004992,
      "heapUsedBytes": 52999808,
      "domNodes": 24,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 38.528,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.669999999999998,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 480.5029999999988,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 5.396,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 283.335,
      "heapDeltaBytes": -12436256,
      "heapUsedBytes": 51402060,
      "domNodes": 20,
      "jsHeapTotalBytes": 27000832,
      "scriptDurationMs": 39.111999999999995,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.669999999999998,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2010.5049999999665,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 5.667,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 568.8910000000001,
      "heapDeltaBytes": 7057412,
      "heapUsedBytes": 68563200,
      "domNodes": -278,
      "jsHeapTotalBytes": 3256320,
      "scriptDurationMs": 68.84899999999999,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2011.9290000000092,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 5.165999999999997,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 556.514,
      "heapDeltaBytes": 3821260,
      "heapUsedBytes": 64242956,
      "domNodes": -280,
      "jsHeapTotalBytes": 3780608,
      "scriptDurationMs": 70,
      "eventListeners": -179,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2104.2269999999803,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 10.499,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 975.4110000000001,
      "heapDeltaBytes": 3616752,
      "heapUsedBytes": 64258200,
      "domNodes": -281,
      "jsHeapTotalBytes": 3448832,
      "scriptDurationMs": 303.57099999999997,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2088.97300000001,
      "styleRecalcs": 67,
      "styleRecalcDurationMs": 10.390999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1037.0879999999997,
      "heapDeltaBytes": 3282628,
      "heapUsedBytes": 64441020,
      "domNodes": -282,
      "jsHeapTotalBytes": 3710976,
      "scriptDurationMs": 328.287,
      "eventListeners": -147,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3105.1109999999653,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 11.575999999999999,
      "layouts": 60,
      "layoutDurationMs": 6.292999999999999,
      "taskDurationMs": 1149.8919999999998,
      "heapDeltaBytes": -10667332,
      "heapUsedBytes": 53905708,
      "domNodes": 14,
      "jsHeapTotalBytes": 6926336,
      "scriptDurationMs": 361.28,
      "eventListeners": -151,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3134.13300000002,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 14.510000000000002,
      "layouts": 60,
      "layoutDurationMs": 7.882,
      "taskDurationMs": 1254.81,
      "heapDeltaBytes": -8448692,
      "heapUsedBytes": 55681404,
      "domNodes": -287,
      "jsHeapTotalBytes": 6926336,
      "scriptDurationMs": 394.743,
      "eventListeners": -181,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "minimap-idle",
      "durationMs": 2027.6450000000068,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 5.813000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 553.3209999999999,
      "heapDeltaBytes": 7386252,
      "heapUsedBytes": 70307984,
      "domNodes": -281,
      "jsHeapTotalBytes": 3256320,
      "scriptDurationMs": 67.593,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "minimap-idle",
      "durationMs": 2007.7820000000202,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 5.3790000000000004,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 557.706,
      "heapDeltaBytes": 7197684,
      "heapUsedBytes": 67956172,
      "domNodes": -287,
      "jsHeapTotalBytes": 2994176,
      "scriptDurationMs": 70.187,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 520.0999999999567,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 7.542,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 303.485,
      "heapDeltaBytes": -10800104,
      "heapUsedBytes": 53344492,
      "domNodes": 22,
      "jsHeapTotalBytes": 26476544,
      "scriptDurationMs": 84.553,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 505.8210000000827,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 7.9049999999999985,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 317.353,
      "heapDeltaBytes": -10284556,
      "heapUsedBytes": 53667476,
      "domNodes": 22,
      "jsHeapTotalBytes": 25427968,
      "scriptDurationMs": 88.424,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999727
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2021.3830000000144,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 5.767000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 401.95300000000003,
      "heapDeltaBytes": 5214740,
      "heapUsedBytes": 69104056,
      "domNodes": 20,
      "jsHeapTotalBytes": 25690112,
      "scriptDurationMs": 11.941,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2011.9359999999915,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 5.773000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 381.579,
      "heapDeltaBytes": 5084612,
      "heapUsedBytes": 69204316,
      "domNodes": 20,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 11.874999999999998,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1696.111999999971,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 26.576,
      "layouts": 16,
      "layoutDurationMs": 3.2300000000000004,
      "taskDurationMs": 600.815,
      "heapDeltaBytes": -4173884,
      "heapUsedBytes": 59767492,
      "domNodes": 62,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 62.68,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1680.7799999999133,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 29.471999999999998,
      "layouts": 16,
      "layoutDurationMs": 3.441,
      "taskDurationMs": 621.559,
      "heapDeltaBytes": -4177416,
      "heapUsedBytes": 59780252,
      "domNodes": 65,
      "jsHeapTotalBytes": 25427968,
      "scriptDurationMs": 66.389,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-transition-enter",
      "durationMs": 965.780000000052,
      "styleRecalcs": 19,
      "styleRecalcDurationMs": 22.703,
      "layouts": 15,
      "layoutDurationMs": 8.639000000000001,
      "taskDurationMs": 716.858,
      "heapDeltaBytes": 8377080,
      "heapUsedBytes": 100188936,
      "domNodes": 13673,
      "jsHeapTotalBytes": 11796480,
      "scriptDurationMs": 21.134,
      "eventListeners": 2369,
      "totalBlockingTimeMs": 100,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8136.45299999996,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 26.809000000000005,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 3309.378,
      "heapDeltaBytes": 10545332,
      "heapUsedBytes": 70145300,
      "domNodes": -278,
      "jsHeapTotalBytes": 5545984,
      "scriptDurationMs": 929.458,
      "eventListeners": -133,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8094.715000000065,
      "styleRecalcs": 249,
      "styleRecalcDurationMs": 31.496000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 3461.8729999999996,
      "heapDeltaBytes": 10146404,
      "heapUsedBytes": 70319188,
      "domNodes": -280,
      "jsHeapTotalBytes": 5545984,
      "scriptDurationMs": 985.185,
      "eventListeners": -133,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 11506.342000000019,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 11486.862000000001,
      "heapDeltaBytes": -40938828,
      "heapUsedBytes": 166910992,
      "domNodes": -8312,
      "jsHeapTotalBytes": -8855552,
      "scriptDurationMs": 426.941,
      "eventListeners": -16391,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.220000000000073,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 12439.706000000002,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12425.296,
      "heapDeltaBytes": -55116192,
      "heapUsedBytes": 151970448,
      "domNodes": -8312,
      "jsHeapTotalBytes": -9904128,
      "scriptDurationMs": 443.17900000000003,
      "eventListeners": -16389,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.220000000000073,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 13907.670999999993,
      "styleRecalcs": 68,
      "styleRecalcDurationMs": 12.408999999999976,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 13874.641,
      "heapDeltaBytes": -58254792,
      "heapUsedBytes": 164223008,
      "domNodes": -8312,
      "jsHeapTotalBytes": -13049856,
      "scriptDurationMs": 678.245,
      "eventListeners": -16389,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.223333333333237,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 15457.535000000007,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 13.799000000000007,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 15433.942000000003,
      "heapDeltaBytes": -34592124,
      "heapUsedBytes": 177025532,
      "domNodes": -8312,
      "jsHeapTotalBytes": -10235904,
      "scriptDurationMs": 749.9409999999999,
      "eventListeners": -16387,
      "totalBlockingTimeMs": 41,
      "frameDurationMs": 17.77333333333336,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 441.73299999999927,
      "styleRecalcs": 14,
      "styleRecalcDurationMs": 14.108999999999998,
      "layouts": 2,
      "layoutDurationMs": 0.3939999999999999,
      "taskDurationMs": 92.109,
      "heapDeltaBytes": 5332788,
      "heapUsedBytes": 68770540,
      "domNodes": 136,
      "jsHeapTotalBytes": 5242880,
      "scriptDurationMs": 7.656,
      "eventListeners": 97,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 433.8510000000042,
      "styleRecalcs": 14,
      "styleRecalcDurationMs": 13.230000000000002,
      "layouts": 3,
      "layoutDurationMs": 0.476,
      "taskDurationMs": 84.57199999999999,
      "heapDeltaBytes": 5098584,
      "heapUsedBytes": 68171108,
      "domNodes": 125,
      "jsHeapTotalBytes": 5242880,
      "scriptDurationMs": 7.322,
      "eventListeners": 99,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    }
  ]
}

@claude
claude Bot marked this pull request as ready for review August 2, 2026 01:14
@claude
claude Bot requested a review from a team August 2, 2026 01:14
@dosubot dosubot Bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Aug 2, 2026
@dosubot

dosubot Bot commented Aug 2, 2026

Copy link
Copy Markdown

📄 Knowledge review

Dosu skipped reviewing this PR because your organization has used its 200 included credits for the month. Your usage will reset on 2026-09-01. To have Dosu review this PR before then, ask your organization admin to upgrade to a pro account.


Leave Feedback Ask Dosu about ComfyUI_frontend Add Dosu to your team

@codecov

codecov Bot commented Aug 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

@@            Coverage Diff             @@
##             main   #14551      +/-   ##
==========================================
+ Coverage   78.14%   78.16%   +0.02%     
==========================================
  Files        1768     1785      +17     
  Lines      105794   107755    +1961     
  Branches    32899    33961    +1062     
==========================================
+ Hits        82669    84225    +1556     
- Misses      22659    23045     +386     
- Partials      466      485      +19     
Flag Coverage Δ
unit 70.66% <100.00%> (+0.39%) ⬆️

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

Files with missing lines Coverage Δ
src/composables/node/usePromotedPreviews.ts 100.00% <100.00%> (ø)
src/core/graph/subgraph/promotionUtils.ts 83.17% <100.00%> (-0.39%) ⬇️
src/stores/nodeOutputStore.ts 81.61% <ø> (ø)
src/stores/previewExposureStore.ts 100.00% <100.00%> (ø)

... and 76 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.

…fixture

The regression fixture gave the interior SamplerCustomAdvanced node the same
id (1) as the outer SubgraphNode. LiteGraph's deduplicateSubgraphNodeIds
treats the loading workflow's own root node ids as reserved, so it silently
remapped the interior node's id to 2 on load. The test's composite execution
id ("1:1") therefore targeted a node locator that no longer existed, so the
websocket-driven preview never reached the watcher registered in
autoExposeKnownPreviewNodes for the real (remapped) locator, and the
assertion timed out. Giving the interior node a non-colliding id (2) avoids
the remap entirely and keeps the test's assumed execution id in sync with
the id LiteGraph actually assigns.
Drop the CANVAS_IMAGE_PREVIEW_NODE_TYPES allowlist and the
nodeOutputStore watcher from autoExposeKnownPreviewNodes. Every
interior node without a real preview widget now gets a virtual
preview exposure registered unconditionally; whether it actually
renders on the host SubgraphNode is already fully derived from live
store state by usePromotedPreviews and the canvas draw-loop preview
poller, so no per-type gating or one-shot watch is needed.

The allowlist itself stays in canvasImagePreviewTypes.ts, used only
by getPromotableWidgets for the manual widget-promotion menu.
@claude claude Bot changed the title test: add failing coverage for subgraph preview allowlist gap fix: derive subgraph preview promotion for any interior node type Aug 2, 2026
…ures

autoExposeKnownPreviewNodes goes back to allowlist-gated eager
registration (matching main, minus the dead RAF fallback) so it no
longer writes exposure entries for arbitrary node types into the
persisted previewExposures list.

The actual fix moves into usePromotedPreviews: alongside explicitly
exposed sources, it now also derives a preview for any interior node
that isn't already exposed, isn't a nested SubgraphNode, and has no
real preview widget, purely by reading live nodeOutputStore state.
Nothing is persisted for this path, so it renders once real preview
data arrives without affecting exposure counts or serialized state.
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. and removed size:S This PR changes 10-29 lines, ignoring generated files. labels Aug 2, 2026
…ident-94)

Adds an e2e test and a unit test that reproduce a distinct subgraph
live-preview bug: LGraphNode.vue unconditionally hides the LivePreview
element on any SubgraphNode via a `!lgraphNode?.isSubgraphNode()` guard
(added in #12197 / 0157b47), so a
mid-execution sampler preview never reaches the outer, non-entered
SubgraphNode.

This is separate from the allowlist gap fixed in this PR: that fix
promotes previews through usePromotedPreviews/NodeContent, a rendering
path that is not gated by isSubgraphNode(). It does not touch or
bypass the LivePreview guard, so it does not fix this scenario -
verified empirically: this unit test still fails on top of this
branch's fix with the same "Unable to find an accessible element with
the role img" error as on main.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@claude

claude Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

I looked into whether this PR's fix also covers the regression tracked in incident-94 (a mid-execution sampler preview inside a subgraph not appearing on the outer, non-entered SubgraphNode), since the symptom sounded related.

It's a distinct bug, on a separate rendering path, so I've added the regression tests here as commit e252352 rather than duplicating effort in a second PR:

  • Root cause: LGraphNode.vue has v-if="shouldShowPreviewImg && !lgraphNode?.isSubgraphNode()" on LivePreview (added in feat(subgraph): Subgraph Link Only Promotion (ADR 0009) + migration/store hygiene #12197 / 0157b47), which unconditionally hides that component on any SubgraphNode, regardless of the preview-exposure/allowlist logic this PR touches.
  • This PR's fix operates entirely in usePromotedPreviews/autoExposeKnownPreviewNodes, feeding the separate, unguarded NodeContent v-for="preview in promotedPreviews" rendering path — it never touches or bypasses the LivePreview guard above.
  • Verified empirically: applying just the new unit test (LGraphNode.test.ts, "Subgraph live preview promotion (incident-94 regression)") on top of this branch's tip (before my commit) still fails with the same Unable to find an accessible element with the role "img" error as on main.

Added:

  • browser_tests/tests/vueNodes/interactions/node/imagePreview.spec.ts — e2e regression test using a plain KSampler nested in a subgraph, asserting the outer SubgraphNode shows the live preview by alt text.
  • src/renderer/extensions/vueNodes/components/LGraphNode.test.ts — unit test isolating the isSubgraphNode() guard directly.

Closing #14548 (which had these as draft tests) in favor of this PR now carrying them.

Requested by Christian Byrne · Slack thread


Generated by Claude Code

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@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.

Review from a multi-agent pass over this diff, with a verification gate and two adversarial refutation passes on top. Findings that did not survive verification were dropped, including a claim that deleting the requestAnimationFrame(updatePreviews) fallback regressed the classic canvas: git blame plus a mechanism trace show that callback could never fire (it is handed only to useNodeImage(...).showPreview(), whose onLoaded runs after the synchronous section already returned), so removing it is safe.

Two items that do not anchor to a specific line:

issue: the PR description documents commit a1d0a45b43, which d247aa33f6 reverted. autoExposeKnownPreviewNodes does still consult the allowlist (promotionUtils.ts:595), nothing is registered or persisted, and the promotionUtils test the body cites asserts the opposite of what the body says it asserts (the committed test asserts toEqual([])). The Changes list names 4 of the 8 changed files and omits usePromotedPreviews.ts, where the fix actually lives. Worth stating the Vue-renderer-only scope explicitly too, and adding Fixes #14597, Fixes #9859, Refs Comfy-Org/ComfyUI#15264, none of which are currently linked.

note: #14569 adds an equivalent ambient rollup (useAmbientSubgraphPreviews) over the same computed. Its version keeps usePromotedPreviews a pure exposure projection and already carries the input-preview and hideOutputImages guards this PR lacks, but its e2e fixture is two KSamplers, so it has no regression coverage for the node type this was reported against. Landing #14569's composable and porting this PR's sampler_custom_advanced_in_subgraph.json and subgraphPreviewAllowlistGap.spec.ts onto it would avoid shipping two rollups over the same state. This also looks like it needs needs-backport: the unfixed code is live on core/1.46 through core/1.49 and cloud/1.46 through cloud/1.49, and 1.46 predates appendNodeExecutionId, so that branch needs a hand-written variant rather than a cherry-pick.

const exposedSourceIds = new Set(
exposures.map((exposure) => exposure.sourceNodeId)
)
const unexposed = node.subgraph.nodes.filter(

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.

issue: the implicit branch keys off hasAnySource, which accepts committed nodeOutputs and not only live preview blobs. useImageUploadWidget.ts:128 writes folder: 'input' outputs inside a requestAnimationFrame on workflow load, so opening any saved workflow whose subgraph contains a LoadImage now paints a thumbnail on the host before the user runs anything. There is no exposure behind it, so SubgraphEditor.getActivePreviewRows cannot enumerate it and there is no way to dismiss it. ImagePreview.vue carries min-h-55, and useVueNodeResizeTracking syncs the resulting growth back into layoutStore bounds, so this also changes persisted node geometry on already-saved workflows.

Gating on nodePreviewImages only would match the stated intent ("a mid-execution sampler preview") and drop this case out. isInputPreviewOutput already exists at nodeOutputStore.ts:157, and #14569 applies both that guard and hideOutputImages.

(interiorNode) =>
!exposedSourceIds.has(interiorNode.id) &&
!interiorNode.isSubgraphNode() &&
!interiorNode.widgets?.some(isPreviewPseudoWidget)

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.

issue: this filter is self-defeating. showCanvasImagePreview (useNodeCanvasImagePreview.ts:20) pushes a $$canvas-image-preview widget onto node.widgets once node.imgs is populated, and SubgraphEditor.vue:156-164 calls updatePreviews on every interior node inside its interiorWidgets computed. Once that widget exists the node leaves unexposed, has no exposure to fall back on, and the promoted preview is gone for the rest of the session.

Reproduced against the real composable and fixtures: preview present, widget added, next store write yields []. The trigger needs a second selection change after the image loads rather than merely opening the panel, but the effect is permanent once it happens (removeCanvasImagePreview only runs for animated outputs).

exposedSourceIds already handles the double-render case this filter was presumably meant to prevent.

]
})

const exposedSourceIds = new Set(

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.

issue: removing a preview exposure no longer sticks. SubgraphEditor.vue:292 calls removeExposure, the node then falls into unexposed, and the same preview is re-derived on the next recompute. It also bypasses the persisted cleared state: autoExposeKnownPreviewNodes deliberately honours properties.previewExposures === [] (there is an existing test for "user cleared"), but the implicit branch never reads that property, so a cleared host re-populates after save and reload.

ADR 0009 says preview exposures are "removed only by explicit user action or by destruction/unpacking of the owning host".

Worth noting the canvas context-menu demote path is not affected: demoteWidget only fires for a real widget, and such a node is excluded by the isPreviewPseudoWidget filter above, so removal does stick there. It is specifically the side-panel removal of a virtual exposure that becomes a no-op.


if (hasPreviewWidget()) continue

if (supportsVirtualCanvasImagePreview(node)) {

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.

issue: the fix does not reach the classic canvas renderer. getPseudoWidgetPreviewTargets (litegraphService.ts:193) resolves its targets from previewExposureStore alone, and this allowlist gate is unchanged, so a SamplerCustomAdvanced still gets no exposure and still shows nothing there.

Comfy.VueNodes.Enabled is defaultValue: false with defaultsByInstallVersion: { '1.41.0': isCloud || isDesktop } (coreSettings.ts:1207), so OSS local installs are on the unfixed path, and LGraphCanvas.drawNode returns before onDrawBackground in Vue mode, meaning the two renderers are mutually exclusive rather than layered. Both new e2e specs are tagged @vue-nodes.

Either cover the classic path or scope it out explicitly in the description and file the follow-up, since the body currently claims the legacy renderer polls the same store state.

})
})

describe('autoExposeKnownPreviewNodes — unlisted node types', () => {

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.

suggestion (non-blocking): this test passes with the entire promotionUtils.ts change reverted to origin/main, verified by copying it into a detached main worktree and running it there. On main, unlisted types went down the requestAnimationFrame branch, which never flushes under vitest, so no exposure was persisted on main either. It does catch over-exposure (forcing every node down the eager branch makes it fail), so it is worth keeping, but it does not cover the behaviour this PR changed in this file.

Separately, updatePreviewsMock at line 49 and its two not.toHaveBeenCalled() assertions are now vacuous since promotionUtils.ts no longer imports useLitegraphService, and the name "skips deferred updatePreviews when a preview widget already exists" no longer describes anything that exists.

wstest(
'Promotes a live sampler preview from inside a subgraph to the outer SubgraphNode',
async ({ comfyPage, getWebSocket }) => {
test.fail()

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.

note: keeping the expected-fail markers is fine, but they could use a breadcrumb. They pin the !lgraphNode?.isSubgraphNode() guard at LGraphNode.vue:172, not the allowlist gap this PR fixes: the interior node here is a KSampler, which is allowlisted and already promoted on main, and the assertion targets LivePreview's alt text rather than the NodeContent/ImagePreview path this PR feeds.

Confirmed by patching that line and running the suite: the vitest it.fails counterpart in LGraphNode.test.ts then hard-fails with a bare Error: Expect test to fail, naming no incident, file, or next step. A comment naming incident-94 and the exact line each marker waits on would save whoever fixes the guard a confusing red build.

{
sourceNodeId: interiorNode.id,
sourceWidgetName: CANVAS_IMAGE_PREVIEW_WIDGET,
type: getPreviewMediaType(interiorNode),

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.

suggestion (non-blocking): getPreviewMediaType reads node.previewMediaType, which is only assigned inside updatePreviews -> showPreview (useNodeImage.ts:103,132). For an interior node in a subgraph the user has never entered, that never runs in Vue mode, so it is undefined and falls through to 'image', and NodeContent routes 'image' to ImagePreview, producing <img src="....webm"> for a video interior node.

On the explicit path these were coupled (the video pseudo-widget and previewMediaType = 'video' are set in the same call), so this only becomes reachable now that arbitrary interior nodes can promote. Deriving the type from the output payload via isVideoOutput (litegraphUtil.ts) would be sturdier than the mutable node field.

@christian-byrne christian-byrne self-assigned this Aug 4, 2026
- Track explicitly-removed implicit preview sources in
  previewExposureStore so demoting a virtual/unexposed preview
  actually sticks instead of being re-derived on the next recompute.
- Gate usePromotedPreviews' implicit branch on live nodePreviewImages
  only, not committed nodeOutputs, so a restored LoadImage thumbnail
  from a saved workflow doesn't leak through as an undismissable host
  preview.
- Remove the isPreviewPseudoWidget filter from the implicit branch: it
  excluded nodes purely for having gained a $$canvas-image-preview
  pseudo-widget (which happens to any node with live images once
  SubgraphEditor's interiorWidgets computed runs updatePreviews),
  permanently killing the very previews this PR was meant to surface.
- Derive preview media type from the actual output payload via
  isVideoOutput instead of the mutable node.previewMediaType field,
  which is never set for an interior node in a subgraph the user
  hasn't visually entered.
- Clean up promotionUtils.test.ts: remove the dead useLitegraphService
  mock and its vacuous assertions now that promotionUtils.ts doesn't
  import it, and rewrite the test that depended on it.
- Add breadcrumb comments on the two incident-94 expected-fail
  markers pointing at the actual (different, still-open) guard bug
  and the LGraphNode.vue:172 line to fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CAFGAHSLhxcazgjp3rzH5X
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Aug 4, 2026
@christian-byrne christian-byrne removed their assignment Aug 4, 2026
@christian-byrne

Copy link
Copy Markdown
Contributor

Closing in favour of #14569, which fixes the same user-visible bug with a better-guarded mechanism.

Rationale, from the review above: both PRs add an ambient rollup of interior-node previews over the same computed. #14569 keeps usePromotedPreviews a pure exposure projection instead of mixing derivation into it, and it already carries the two guards this branch lacks (isInputPreviewOutput and hideOutputImages). Verified from code that its rollup does pick up a mid-execution latent preview for a non-allowlisted interior node at depth 1, so the SamplerCustomAdvanced case this PR was opened for is covered there.

Three artifacts here are not redundant and should be ported onto that branch rather than lost:

  • browser_tests/assets/nodes/sampler_custom_advanced_in_subgraph.json

  • browser_tests/tests/subgraph/subgraphPreviewAllowlistGap.spec.ts

    fix: decouple subgraph preview/output display from the promotion system #14569's e2e fixture is two KSamplers, both allowlisted, so reintroducing a type gate into the ambient path would pass every test it has. These two files are the only artifacts in either PR that pin the node type this was actually reported against.

  • The incident-94 guard tests (LGraphNode.test.ts it.fails, imagePreview.spec.ts test.fail())

    These pin the !lgraphNode?.isSubgraphNode() guard at LGraphNode.vue:172, which neither PR touches and which no open PR currently fixes. They need a home and an owner regardless of which mechanism lands.

The promotionUtils.ts change here (dropping the dead requestAnimationFrame(updatePreviews) fallback) is safe but unrelated to the fix, and can be re-raised separately if wanted.

claude Bot pushed a commit that referenced this pull request Aug 5, 2026
#14551 was closed in favor of this PR's ambient-rollup mechanism, but it
carried three artifacts not otherwise covered here:

- browser_tests/assets/nodes/sampler_custom_advanced_in_subgraph.json +
  browser_tests/tests/subgraph/subgraphPreviewAllowlistGap.spec.ts: this
  PR's own e2e fixture uses two KSamplers, both allowlisted, so it would
  pass even if a node-type gate were reintroduced into the ambient path.
  This fixture pins a non-allowlisted node type (SamplerCustomAdvanced)
  instead.
- Two incident-94 expected-fail regression tests (LGraphNode.test.ts,
  imagePreview.spec.ts) pinning the still-open `!lgraphNode?.isSubgraphNode()`
  guard at LGraphNode.vue:172, which neither PR touches.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generation Previews not showing in subgraph node.

3 participants