Skip to content

fix: show backend-submitted node display names in English locale - #14541

Merged
christian-byrne merged 5 commits into
mainfrom
fix/en-node-display-names-from-backend
Aug 4, 2026
Merged

fix: show backend-submitted node display names in English locale#14541
christian-byrne merged 5 commits into
mainfrom
fix/en-node-display-names-from-backend

Conversation

@bigcat88

@bigcat88 bigcat88 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Summary

English node display names now come from the backend /object_info response instead of the bundled en/nodeDefs.json snapshot, so core-node renames take effect without waiting for a frontend locale regeneration.

Changes

  • What: resolveNodeDefText() (src/i18n.ts) resolves node text in an explicit precedence order, replacing the previous approach of merging escaped backend strings into the vue-i18n en message tree.

    locale order
    en custom-node /api/i18n -> backend /object_info -> bundled snapshot -> node name
    other custom-node /api/i18n -> bundled snapshot -> backend /object_info -> node name

    English is the source language, so a backend value is data rather than a translation and is returned without being compiled. Raw /object_info text is held in a plain map (setBackendNodeText), rebuilt per fetch. Non-English behaviour is unchanged except that it now falls back to the live backend value rather than the stale English snapshot. Custom-node translations still go through the compiler, because the generated custom-node locale pipeline escapes them.

  • What: All nodeDefs.* key construction moves behind that resolver (app.ts, nodeTitleUtil.ts, useContextMenuTranslation.ts), so node titles, search, the node library and context menus resolve identically.

  • Fix: escapeI18nMessage mishandled backslash. Since vue-i18n 11 the compiler reads \ as an escape introducer, so a backslash before an escaped character swallowed the brace the escaper emits: C:\@home failed to compile as Invalid linked format, and D:\\output rendered lossily. Backslash is now doubled (vue-i18n cannot express a literal backslash via interpolation, so {'\'} would escape its own closing quote). Non-string input is guarded, matching normalizeI18nKey directly above it. This also fixes build-time locale generation for the same inputs.

  • Fix: nodeCategories keys are normalized. They had the same defect as the dotted node-name lookup four lines above: the serializer writes nodeCategories.sync_so while the consumer asked for nodeCategories.sync.so, which vue-i18n resolves as a nested path.

  • Fix: The legacy nested custom-locale shape resolves again. Some hand-written custom-node locales nest dotted node ids as objects, which vue-i18n resolves by path traversal. translateNodeDef was the last consumer that still reached them, so normalizing alone would have regressed them; both key shapes are now tried.

  • Fix: A non-object /object_info response no longer throws out of getNodeDefs().

  • Revert: One regenerated Playwright golden (vue-nodes-paned-with-touch-mobile) is restored. Its 640 changed pixels of 285711 are antialiasing on a ckpt_name widget value, with the node title row byte-identical, so it carried no signal from this change.

  • Breaking: None.

Review Focus

  • Precedence per locale, and that English never reaches the message compiler.
  • The backslash escape. Verified against the pinned vue-i18n@11.4.6; the existing corpus contains zero backslashes across all 13 shipped locales and 7905 strings in en/nodeDefs.json, so a release regeneration produces byte-identical output and only previously-broken inputs change.
  • Tests cover the precedence table per locale, verbatim rendering of names containing i18n syntax, eviction of dropped backend text, both key shapes, and escape round-trips through the real compiler. Verified by mutation: dropping the English bypass, the legacy key shape, the eviction, or the backslash fix each fails the suite.

Known gaps, deliberately not in this PR

  • Node titles in Playwright goldens now depend on the CI container's ComfyUI build rather than an in-repo file. routeObjectInfoFromSetupApi can stub display names to decouple them; not done here because it cannot be verified without a backend. Follow-up issue to come.
  • Widget labels, output names and tooltips are still resolved from the bundled snapshot. Tooltips in particular must not be escaped, since they are read through stRaw/tm() uncompiled.

Original report and diagnosis by @bigcat88, who identified the root cause and the correct precedence rules; the normalizeI18nKey fix in translateNodeDef is his and is kept. Reworked with his permission.

Linear: FE-1479

The English locale bundle (src/locales/en/nodeDefs.json) previously
shadowed the display_name submitted by the backend in /object_info, so
renaming a core node had no visible effect until the frontend
regenerated its locale files.

Merge the backend display names into the en locale messages when node
defs are fetched, so every nodeDefs.<name>.display_name lookup (node
titles, search, context menus) resolves to the live backend value.
Other locales are unaffected: missing keys there already fall back to
the backend string, and existing translations still apply.

Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019fbe31-690b-76f0-a579-d34bb7adb9e2
@bigcat88
bigcat88 requested a review from a team August 1, 2026 18:11
@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Aug 1, 2026
@dosubot

dosubot Bot commented Aug 1, 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

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

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

📊 Browser Reports
  • chromium: View Report (✅ 1758 / ❌ 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)

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 08/03/2026, 11:48:59 PM UTC

Links

📦 Bundle: 8.23 MB gzip 🔴 +1.19 kB

Details

Summary

  • Raw size: 34.6 MB baseline 34.6 MB — 🔴 +3.35 kB
  • Gzip: 8.23 MB baseline 8.23 MB — 🔴 +1.19 kB
  • Brotli: 5.7 MB baseline 5.69 MB — 🔴 +825 B
  • Bundles: 427 current • 427 baseline • 153 added / 153 removed

Category Glance
Other 🔴 +2.91 kB (12.8 MB) · Data & Services 🔴 +433 B (3.46 MB) · Utilities & Hooks 🔴 +65 B (386 kB) · Graph Workspace 🟢 -51 B (1.31 MB) · Vendor & Third-Party ⚪ 0 B (15.7 MB) · Panels & Settings ⚪ 0 B (551 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-0fYNEflE.js (new) 3.64 kB 🔴 +3.64 kB 🔴 +1.82 kB 🔴 +1.59 kB
assets/index-DwVyCX6x.js (removed) 3.64 kB 🟢 -3.64 kB 🟢 -1.82 kB 🟢 -1.57 kB

Status: 1 added / 1 removed

Graph Workspace — 1.31 MB (baseline 1.31 MB) • 🟢 -51 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-DDLJCsMh.js (removed) 1.31 MB 🟢 -1.31 MB 🟢 -283 kB 🟢 -213 kB
assets/GraphView-TWgrGY0_.js (new) 1.31 MB 🔴 +1.31 MB 🔴 +283 kB 🔴 +213 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-B7hnm-Pj.js (removed) 24.9 kB 🟢 -24.9 kB 🟢 -6.23 kB 🟢 -5.5 kB
assets/CloudSurveyView-xZoeqhLm.js (new) 24.9 kB 🔴 +24.9 kB 🔴 +6.23 kB 🔴 +5.51 kB
assets/CloudLoginView-BeO01pDn.js (removed) 11.6 kB 🟢 -11.6 kB 🟢 -3.11 kB 🟢 -2.74 kB
assets/CloudLoginView-CbiwdlTk.js (new) 11.6 kB 🔴 +11.6 kB 🔴 +3.11 kB 🔴 +2.72 kB
assets/CloudSignupView-DELFMAc4.js (removed) 9.9 kB 🟢 -9.9 kB 🟢 -2.78 kB 🟢 -2.43 kB
assets/CloudSignupView-SCBwlq1K.js (new) 9.9 kB 🔴 +9.9 kB 🔴 +2.78 kB 🔴 +2.42 kB
assets/CloudLayoutView-CdsjDZSi.js (new) 9.48 kB 🔴 +9.48 kB 🔴 +2.31 kB 🔴 +1.99 kB
assets/CloudLayoutView-Dg22uZ0L.js (removed) 9.48 kB 🟢 -9.48 kB 🟢 -2.32 kB 🟢 -2 kB
assets/UserCheckView-Di1GW3Nw.js (new) 8.75 kB 🔴 +8.75 kB 🔴 +2.19 kB 🔴 +1.9 kB
assets/UserCheckView-fNCXF5yq.js (removed) 8.75 kB 🟢 -8.75 kB 🟢 -2.19 kB 🟢 -1.9 kB
assets/WidgetTextPreview-CCXZmw3d.js (removed) 6.07 kB 🟢 -6.07 kB 🟢 -2.13 kB 🟢 -1.89 kB
assets/WidgetTextPreview-CgWfipjc.js (new) 6.07 kB 🔴 +6.07 kB 🔴 +2.13 kB 🔴 +1.89 kB
assets/CloudSubscriptionRedirectView-D-oyXYQe.js (new) 5.99 kB 🔴 +5.99 kB 🔴 +2.23 kB 🔴 +1.94 kB
assets/CloudSubscriptionRedirectView-DTB_83Fe.js (removed) 5.99 kB 🟢 -5.99 kB 🟢 -2.23 kB 🟢 -1.94 kB
assets/UserSelectView-BkTvgZjN.js (new) 5.49 kB 🔴 +5.49 kB 🔴 +1.95 kB 🔴 +1.71 kB
assets/UserSelectView-YCnFRUQx.js (removed) 5.49 kB 🟢 -5.49 kB 🟢 -1.96 kB 🟢 -1.71 kB
assets/CloudForgotPasswordView-CQNMIrSg.js (removed) 5.09 kB 🟢 -5.09 kB 🟢 -1.73 kB 🟢 -1.5 kB
assets/CloudForgotPasswordView-DAn-Rlq6.js (new) 5.09 kB 🔴 +5.09 kB 🔴 +1.73 kB 🔴 +1.5 kB
assets/CloudAuthTimeoutView-BakbRmei.js (new) 4.43 kB 🔴 +4.43 kB 🔴 +1.54 kB 🔴 +1.34 kB
assets/CloudAuthTimeoutView-D6AWW-7t.js (removed) 4.43 kB 🟢 -4.43 kB 🟢 -1.54 kB 🟢 -1.34 kB
assets/OAuthLayoutView-DmXMX-8G.js (removed) 1.31 kB 🟢 -1.31 kB 🟢 -700 B 🟢 -593 B
assets/OAuthLayoutView-YLWkNTum.js (new) 1.31 kB 🔴 +1.31 kB 🔴 +700 B 🔴 +595 B
assets/WidgetTextPreview-BRho_jq0.js (new) 131 B 🔴 +131 B 🔴 +100 B 🔴 +91 B
assets/WidgetTextPreview-ChObyv0d.js (removed) 131 B 🟢 -131 B 🟢 -100 B 🟢 -90 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-Do9f4tYl.js (new) 49.4 kB 🔴 +49.4 kB 🔴 +9.95 kB 🔴 +8.79 kB
assets/KeybindingPanel-GiayStZS.js (removed) 49.4 kB 🟢 -49.4 kB 🟢 -9.94 kB 🟢 -8.8 kB
assets/SecretsPanel-BbvZ2KQC.js (new) 33.7 kB 🔴 +33.7 kB 🔴 +7.86 kB 🔴 +6.89 kB
assets/SecretsPanel-CSS1NU28.js (removed) 33.7 kB 🟢 -33.7 kB 🟢 -7.86 kB 🟢 -6.9 kB
assets/CreditsPanel-K91OMlu0.js (new) 15.9 kB 🔴 +15.9 kB 🔴 +4.63 kB 🔴 +4.06 kB
assets/CreditsPanel-poNDpMA_.js (removed) 15.9 kB 🟢 -15.9 kB 🟢 -4.63 kB 🟢 -4.07 kB
assets/SubscriptionPanel-DdO5U8bU.js (removed) 11.5 kB 🟢 -11.5 kB 🟢 -3.65 kB 🟢 -3.21 kB
assets/SubscriptionPanel-DebfhBVX.js (new) 11.5 kB 🔴 +11.5 kB 🔴 +3.65 kB 🔴 +3.21 kB
assets/AboutPanel-CY7qackV.js (new) 11.2 kB 🔴 +11.2 kB 🔴 +3.03 kB 🔴 +2.71 kB
assets/AboutPanel-kbr5ztUk.js (removed) 11.2 kB 🟢 -11.2 kB 🟢 -3.03 kB 🟢 -2.71 kB
assets/ExtensionPanel-CYnff5eM.js (new) 9.19 kB 🔴 +9.19 kB 🔴 +2.51 kB 🔴 +2.22 kB
assets/ExtensionPanel-k2xUjH1f.js (removed) 9.19 kB 🟢 -9.19 kB 🟢 -2.51 kB 🟢 -2.22 kB
assets/ServerConfigPanel-7xtQsleV.js (removed) 6.09 kB 🟢 -6.09 kB 🟢 -1.94 kB 🟢 -1.73 kB
assets/ServerConfigPanel-BF06AfBw.js (new) 6.09 kB 🔴 +6.09 kB 🔴 +1.94 kB 🔴 +1.72 kB
assets/UserPanel-B-o6TFkd.js (removed) 5.73 kB 🟢 -5.73 kB 🟢 -1.78 kB 🟢 -1.55 kB
assets/UserPanel-C6me1EwJ.js (new) 5.73 kB 🔴 +5.73 kB 🔴 +1.78 kB 🔴 +1.54 kB
assets/refreshRemoteConfig-B_WwVRXi.js (new) 2.94 kB 🔴 +2.94 kB 🔴 +1.25 kB 🔴 +1.11 kB
assets/refreshRemoteConfig-DempSM_M.js (removed) 2.94 kB 🟢 -2.94 kB 🟢 -1.26 kB 🟢 -1.11 kB
assets/cloudRemoteConfig-BltdUF9X.js (removed) 933 B 🟢 -933 B 🟢 -505 B 🟢 -418 B
assets/cloudRemoteConfig-DCo6SRbK.js (new) 933 B 🔴 +933 B 🔴 +505 B 🔴 +414 B
assets/refreshRemoteConfig-b4T4Yg3h.js (new) 110 B 🔴 +110 B 🔴 +89 B 🔴 +85 B
assets/refreshRemoteConfig-D44xr5Df.js (removed) 110 B 🟢 -110 B 🟢 -89 B 🟢 -84 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-CgOy1cvk.js (new) 12.2 kB 🔴 +12.2 kB 🔴 +4.15 kB 🔴 +3.61 kB
assets/SignUpForm-DUJgfjjk.js (removed) 12.2 kB 🟢 -12.2 kB 🟢 -4.15 kB 🟢 -3.62 kB
assets/auth-BLxH6uVF.js (removed) 3.65 kB 🟢 -3.65 kB 🟢 -1.27 kB 🟢 -1.1 kB
assets/auth-CSrkrWfS.js (new) 3.65 kB 🔴 +3.65 kB 🔴 +1.27 kB 🔴 +1.09 kB
assets/usePostAuthRedirect-BLpzrjgz.js (new) 3.28 kB 🔴 +3.28 kB 🔴 +1.24 kB 🔴 +1.08 kB
assets/usePostAuthRedirect-D8tuSHtg.js (removed) 3.28 kB 🟢 -3.28 kB 🟢 -1.24 kB 🟢 -1.08 kB
assets/UpdatePasswordContent-B2IJqP_E.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +840 B 🔴 +727 B
assets/UpdatePasswordContent-CEIO2jNr.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -838 B 🟢 -729 B
assets/authStore-BPW9KX2l.js (new) 128 B 🔴 +128 B 🔴 +104 B 🔴 +106 B
assets/authStore-Tz5ifgXe.js (removed) 128 B 🟢 -128 B 🟢 -104 B 🟢 -105 B
assets/workspaceAuthStore-Ba0MWf1s.js (new) 108 B 🔴 +108 B 🔴 +99 B 🔴 +107 B
assets/workspaceAuthStore-BRM4dN_1.js (removed) 108 B 🟢 -108 B 🟢 -99 B 🟢 -108 B
assets/auth-CcMjLDAi.js (removed) 105 B 🟢 -105 B 🟢 -96 B 🟢 -89 B
assets/auth-DtRUI_Kp.js (new) 105 B 🔴 +105 B 🔴 +96 B 🔴 +79 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-BxefT75J.js (new) 90 kB 🔴 +90 kB 🔴 +19.2 kB 🔴 +16.5 kB
assets/ComfyHubPublishDialog-DI7MYBrF.js (removed) 90 kB 🟢 -90 kB 🟢 -19.2 kB 🟢 -16.5 kB
assets/useShareDialog-BgSf78dR.js (new) 23.9 kB 🔴 +23.9 kB 🔴 +5.7 kB 🔴 +5.04 kB
assets/useShareDialog-yaXYAV7G.js (removed) 23.9 kB 🟢 -23.9 kB 🟢 -5.7 kB 🟢 -5.03 kB
assets/feedbackDialog-76efxx7Q.js (removed) 4.45 kB 🟢 -4.45 kB 🟢 -1.87 kB 🟢 -1.59 kB
assets/feedbackDialog-BAEhycp9.js (new) 4.45 kB 🔴 +4.45 kB 🔴 +1.87 kB 🔴 +1.6 kB
assets/useRangeEditor-Cc4GIv3a.js (removed) 3.23 kB 🟢 -3.23 kB 🟢 -1.13 kB 🟢 -1.04 kB
assets/useRangeEditor-cG5PsWzm.js (new) 3.23 kB 🔴 +3.23 kB 🔴 +1.13 kB 🔴 +1.04 kB
assets/ComfyHubPublishDialog-CmVuOgJz.js (removed) 143 B 🟢 -143 B 🟢 -105 B 🟢 -89 B
assets/ComfyHubPublishDialog-CyvxPzDC.js (new) 143 B 🔴 +143 B 🔴 +105 B 🔴 +89 B
assets/useSubscriptionDialog-BHYs54IZ.js (removed) 108 B 🟢 -108 B 🟢 -102 B 🟢 -88 B
assets/useSubscriptionDialog-DHDuOWFp.js (new) 108 B 🔴 +108 B 🔴 +102 B 🔴 +90 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-CHinvZSz.js (new) 13.5 kB 🔴 +13.5 kB 🔴 +3.73 kB 🔴 +3.31 kB
assets/ComfyQueueButton-D3S1BD0q.js (removed) 13.5 kB 🟢 -13.5 kB 🟢 -3.73 kB 🟢 -3.32 kB
assets/useTerminalTabs-K7sH3lHk.js (removed) 11.8 kB 🟢 -11.8 kB 🟢 -3.69 kB 🟢 -3.27 kB
assets/useTerminalTabs-syuTxDPM.js (new) 11.8 kB 🔴 +11.8 kB 🔴 +3.69 kB 🔴 +3.26 kB
assets/InviteMembersForm-DUwGhJBW.js (removed) 7.96 kB 🟢 -7.96 kB 🟢 -2.64 kB 🟢 -2.36 kB
assets/InviteMembersForm-E9fAD90G.js (new) 7.96 kB 🔴 +7.96 kB 🔴 +2.64 kB 🔴 +2.36 kB
assets/SubscribeButton-DvLgN1GF.js (removed) 2.13 kB 🟢 -2.13 kB 🟢 -954 B 🟢 -834 B
assets/SubscribeButton-vULMVkn3.js (new) 2.13 kB 🔴 +2.13 kB 🔴 +954 B 🔴 +828 B
assets/cloudFeedbackTopbarButton-BaRaGd0y.js (new) 705 B 🔴 +705 B 🔴 +421 B 🔴 +361 B
assets/cloudFeedbackTopbarButton-CZt-Pfss.js (removed) 705 B 🟢 -705 B 🟢 -421 B 🟢 -360 B
assets/ComfyQueueButton-Cn_HrU9M.js (new) 128 B 🔴 +128 B 🔴 +99 B 🔴 +92 B
assets/ComfyQueueButton-DmKnqsv5.js (removed) 128 B 🟢 -128 B 🟢 -99 B 🟢 -90 B

Status: 6 added / 6 removed / 9 unchanged

Data & Services — 3.46 MB (baseline 3.46 MB) • 🔴 +433 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/settingStore-B_Jdyyyy.js (new) 3.18 MB 🔴 +3.18 MB 🔴 +736 kB 🔴 +554 kB
assets/settingStore-D7D06jaV.js (removed) 3.18 MB 🟢 -3.18 MB 🟢 -736 kB 🟢 -554 kB
assets/load3dService--XxKlof3.js (removed) 132 kB 🟢 -132 kB 🟢 -29.2 kB 🟢 -24.6 kB
assets/load3dService-DwJhUqYL.js (new) 132 kB 🔴 +132 kB 🔴 +29.3 kB 🔴 +24.6 kB
assets/api-CbIZbVmD.js (removed) 97.1 kB 🟢 -97.1 kB 🟢 -26.8 kB 🟢 -23 kB
assets/api-DuE_3wNK.js (new) 97.1 kB 🔴 +97.1 kB 🔴 +26.8 kB 🔴 +23 kB
assets/workflowShareService-BNmEIfp_.js (new) 16.4 kB 🔴 +16.4 kB 🔴 +4.89 kB 🔴 +4.33 kB
assets/workflowShareService-BWuY0bRd.js (removed) 16.4 kB 🟢 -16.4 kB 🟢 -4.89 kB 🟢 -4.34 kB
assets/keybindingService-A7YPihzr.js (removed) 7.08 kB 🟢 -7.08 kB 🟢 -1.82 kB 🟢 -1.58 kB
assets/keybindingService-BEzTfKkS.js (new) 7.08 kB 🔴 +7.08 kB 🔴 +1.82 kB 🔴 +1.58 kB
assets/releaseStore-BPQIrX8x.js (removed) 6.72 kB 🟢 -6.72 kB 🟢 -2.03 kB 🟢 -1.78 kB
assets/releaseStore-DS7YDEQA.js (new) 6.72 kB 🔴 +6.72 kB 🔴 +2.03 kB 🔴 +1.77 kB
assets/systemStatsStore-AcutSqaM.js (removed) 4.93 kB 🟢 -4.93 kB 🟢 -1.74 kB 🟢 -1.47 kB
assets/systemStatsStore-DwwyklFJ.js (new) 4.93 kB 🔴 +4.93 kB 🔴 +1.74 kB 🔴 +1.47 kB
assets/userStore-CX5YPrGS.js (removed) 2.38 kB 🟢 -2.38 kB 🟢 -897 B 🟢 -796 B
assets/userStore-kfj6nBnd.js (new) 2.38 kB 🔴 +2.38 kB 🔴 +897 B 🔴 +795 B
assets/audioService-CeclVIqW.js (new) 1.71 kB 🔴 +1.71 kB 🔴 +830 B 🔴 +725 B
assets/audioService-DuAAhvQU.js (removed) 1.71 kB 🟢 -1.71 kB 🟢 -829 B 🟢 -727 B
assets/dialogService-B_E32sBb.js (removed) 98 B 🟢 -98 B 🟢 -97 B 🟢 -85 B
assets/dialogService-CyzqqCf8.js (new) 98 B 🔴 +98 B 🔴 +97 B 🔴 +84 B
assets/releaseStore-Cns5_a6l.js (new) 95 B 🔴 +95 B 🔴 +86 B 🔴 +88 B
assets/releaseStore-YB6l_DVv.js (removed) 95 B 🟢 -95 B 🟢 -86 B 🟢 -90 B
assets/settingStore-Be6O15xf.js (new) 95 B 🔴 +95 B 🔴 +86 B 🔴 +86 B
assets/settingStore-CoHU5sf-.js (removed) 95 B 🟢 -95 B 🟢 -86 B 🟢 -80 B
assets/assetsStore-CwehuyfJ.js (new) 94 B 🔴 +94 B 🔴 +92 B 🔴 +83 B
assets/assetsStore-D7Ahz-Us.js (removed) 94 B 🟢 -94 B 🟢 -92 B 🟢 -83 B
assets/api-B4RF5Hye.js (removed) 62 B 🟢 -62 B 🟢 -74 B 🟢 -66 B
assets/api-CvvO-yS2.js (new) 62 B 🔴 +62 B 🔴 +74 B 🔴 +66 B

Status: 14 added / 14 removed / 3 unchanged

Utilities & Hooks — 386 kB (baseline 386 kB) • 🔴 +65 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useConflictDetection-B0lMkgqo.js (new) 235 kB 🔴 +235 kB 🔴 +52.5 kB 🔴 +42.7 kB
assets/useConflictDetection-CeWRTOZM.js (removed) 235 kB 🟢 -235 kB 🟢 -52.5 kB 🟢 -42.7 kB
assets/useLoad3d-3qbXiJ20.js (new) 25.7 kB 🔴 +25.7 kB 🔴 +5.8 kB 🔴 +5.13 kB
assets/useLoad3d-Dtl8P61v.js (removed) 25.7 kB 🟢 -25.7 kB 🟢 -5.79 kB 🟢 -5.14 kB
assets/useLoad3dViewer-Cz07gkTk.js (removed) 21.2 kB 🟢 -21.2 kB 🟢 -4.98 kB 🟢 -4.36 kB
assets/useLoad3dViewer-vIv0FLAu.js (new) 21.2 kB 🔴 +21.2 kB 🔴 +4.98 kB 🔴 +4.38 kB
assets/useImageCrop-C8JXKH0f.js (removed) 15 kB 🟢 -15 kB 🟢 -3.42 kB 🟢 -2.98 kB
assets/useImageCrop-M0aVLlyG.js (new) 15 kB 🔴 +15 kB 🔴 +3.42 kB 🔴 +2.98 kB
assets/useDowngradeToPersonal-1_Mz1xYr.js (new) 8.85 kB 🔴 +8.85 kB 🔴 +2.54 kB 🔴 +2.17 kB
assets/useDowngradeToPersonal-2bQa4291.js (removed) 8.85 kB 🟢 -8.85 kB 🟢 -2.54 kB 🟢 -2.17 kB
assets/useFeatureFlags-BYsNFkTT.js (removed) 7.52 kB 🟢 -7.52 kB 🟢 -2.21 kB 🟢 -1.85 kB
assets/useFeatureFlags-D7p5LJ1N.js (new) 7.52 kB 🔴 +7.52 kB 🔴 +2.21 kB 🔴 +1.86 kB
assets/useExternalLink-axo0x3Q6.js (new) 2.81 kB 🔴 +2.81 kB 🔴 +1.06 kB 🔴 +916 B
assets/useExternalLink-Ct-h2JAq.js (removed) 2.81 kB 🟢 -2.81 kB 🟢 -1.06 kB 🟢 -915 B
assets/downloadUtil-B3vo_3uZ.js (removed) 2.4 kB 🟢 -2.4 kB 🟢 -1.08 kB 🟢 -872 B
assets/downloadUtil-C78wf3lz.js (new) 2.4 kB 🔴 +2.4 kB 🔴 +1.08 kB 🔴 +872 B
assets/assetPreviewUtil-B2WHTWB4.js (removed) 2.35 kB 🟢 -2.35 kB 🟢 -971 B 🟢 -838 B
assets/assetPreviewUtil-HqbjCwKD.js (new) 2.35 kB 🔴 +2.35 kB 🔴 +970 B 🔴 +840 B
assets/useUpstreamValue-CTmpWRoi.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +757 B 🔴 +675 B
assets/useUpstreamValue-DNKmuzYd.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -759 B 🟢 -677 B
assets/useWorkspaceTierLabel-CIo1loDv.js (new) 1.93 kB 🔴 +1.93 kB 🔴 +813 B 🔴 +735 B
assets/useWorkspaceTierLabel-ZypS3gaG.js (removed) 1.93 kB 🟢 -1.93 kB 🟢 -815 B 🟢 -699 B
assets/useErrorHandling-DBtVSUDk.js (new) 1.49 kB 🔴 +1.49 kB 🔴 +615 B 🔴 +523 B
assets/useErrorHandling-DiKdidQT.js (removed) 1.49 kB 🟢 -1.49 kB 🟢 -614 B 🟢 -527 B
assets/subscriptionCheckoutUtil-CDhBByxD.js (new) 841 B 🔴 +841 B 🔴 +505 B 🔴 +430 B
assets/subscriptionCheckoutUtil-vQaZUnMa.js (removed) 841 B 🟢 -841 B 🟢 -503 B 🟢 -422 B
assets/useSessionCookie-BV2ujQ9v.js (new) 692 B 🔴 +692 B 🔴 +357 B 🔴 +308 B
assets/useSessionCookie-DINPiEwb.js (removed) 692 B 🟢 -692 B 🟢 -357 B 🟢 -307 B
assets/useLoad3d-Cc9ZN6ma.js (new) 311 B 🔴 +311 B 🔴 +164 B 🔴 +147 B
assets/useLoad3d-CL7JhhBB.js (removed) 311 B 🟢 -311 B 🟢 -164 B 🟢 -147 B
assets/useSessionCookie-DFhGNfl4.js (new) 101 B 🔴 +101 B 🔴 +86 B 🔴 +82 B
assets/useSessionCookie-dMCPVtKJ.js (removed) 101 B 🟢 -101 B 🟢 -86 B 🟢 -80 B
assets/useFeatureFlags-Bv4V2HPp.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +81 B
assets/useFeatureFlags-KW-XXSfB.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -79 B
assets/useLoad3dViewer-B6jfdFoI.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +84 B
assets/useLoad3dViewer-DRgC5N8G.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -86 B
assets/useCurrentUser-Br3iZgk5.js (new) 94 B 🔴 +94 B 🔴 +95 B 🔴 +86 B
assets/useCurrentUser-i4u4TDhm.js (removed) 94 B 🟢 -94 B 🟢 -95 B 🟢 -84 B

Status: 19 added / 19 removed / 17 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) • 🔴 +2.91 kB

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-CBXJIa4p.js (new) 111 kB 🔴 +111 kB 🔴 +28.7 kB 🔴 +24.3 kB
assets/core-uyva_Nzq.js (removed) 111 kB 🟢 -111 kB 🟢 -28.7 kB 🟢 -24.3 kB
assets/WidgetSelect-BTu3RXvZ.js (new) 88 kB 🔴 +88 kB 🔴 +19.9 kB 🔴 +17.1 kB
assets/WidgetSelect-DtJqn_N1.js (removed) 88 kB 🟢 -88 kB 🟢 -19.9 kB 🟢 -17 kB
assets/Load3D-8BTjDp_3.js (new) 71.3 kB 🔴 +71.3 kB 🔴 +11.7 kB 🔴 +9.96 kB
assets/Load3D-CQsFouev.js (removed) 71.3 kB 🟢 -71.3 kB 🟢 -11.7 kB 🟢 -9.97 kB
assets/WidgetVideoEdit-BOWCqGvW.js (removed) 63.4 kB 🟢 -63.4 kB 🟢 -14.6 kB 🟢 -12.8 kB
assets/WidgetVideoEdit-CoL7bfbY.js (new) 63.4 kB 🔴 +63.4 kB 🔴 +14.6 kB 🔴 +12.8 kB
assets/SubscriptionTransitionPreviewWorkspace-CDRKbPnP.js (removed) 63.1 kB 🟢 -63.1 kB 🟢 -13 kB 🟢 -11.4 kB
assets/SubscriptionTransitionPreviewWorkspace-LlzCUnxA.js (new) 63.1 kB 🔴 +63.1 kB 🔴 +13 kB 🔴 +11.4 kB
assets/WorkspaceSettingsPanelContent-CYo7yHg_.js (removed) 61.6 kB 🟢 -61.6 kB 🟢 -13.1 kB 🟢 -11.5 kB
assets/WorkspaceSettingsPanelContent-DmfR2hsm.js (new) 61.6 kB 🔴 +61.6 kB 🔴 +13.1 kB 🔴 +11.5 kB
assets/Preview3d-CnKT-CWk.js (new) 50.9 kB 🔴 +50.9 kB 🔴 +8.31 kB 🔴 +7.26 kB
assets/Preview3d-jesVuPZ8.js (removed) 50.9 kB 🟢 -50.9 kB 🟢 -8.31 kB 🟢 -7.24 kB
assets/main-BXfya_op.js (removed) 46.9 kB 🟢 -46.9 kB 🟢 -13.8 kB 🟢 -12 kB
assets/main-DUK2uEXz.js (new) 46.9 kB 🔴 +46.9 kB 🔴 +13.8 kB 🔴 +12 kB
assets/SubscriptionRequiredDialogContentUnified-C8dxyDct.js (new) 42.9 kB 🔴 +42.9 kB 🔴 +9.46 kB 🔴 +8.26 kB
assets/SubscriptionRequiredDialogContentUnified-DB3YyDf9.js (removed) 42.9 kB 🟢 -42.9 kB 🟢 -9.46 kB 🟢 -8.27 kB
assets/MembersPanelContent-CfvDTVQX.js (new) 41.8 kB 🔴 +41.8 kB 🔴 +8.79 kB 🔴 +7.81 kB
assets/MembersPanelContent-DvN_ioSx.js (removed) 41.8 kB 🟢 -41.8 kB 🟢 -8.79 kB 🟢 -7.82 kB
assets/WidgetBoundingBoxes-CvEMXMh3.js (removed) 33.7 kB 🟢 -33.7 kB 🟢 -9.16 kB 🟢 -8.13 kB
assets/WidgetBoundingBoxes-Dq-SuV29.js (new) 33.7 kB 🔴 +33.7 kB 🔴 +9.16 kB 🔴 +8.12 kB
assets/WidgetPainter-0myczIfA.js (removed) 32.6 kB 🟢 -32.6 kB 🟢 -7.87 kB 🟢 -6.97 kB
assets/WidgetPainter-De7wRWT4.js (new) 32.6 kB 🔴 +32.6 kB 🔴 +7.87 kB 🔴 +6.97 kB
assets/SubscriptionPanelContentWorkspace-CFdyhPWo.js (removed) 31.8 kB 🟢 -31.8 kB 🟢 -7.06 kB 🟢 -6.21 kB
assets/SubscriptionPanelContentWorkspace-D0p5p5Nh.js (new) 31.8 kB 🔴 +31.8 kB 🔴 +7.05 kB 🔴 +6.21 kB
assets/Load3dViewerContent-BQQv0r1f.js (removed) 30.8 kB 🟢 -30.8 kB 🟢 -6.26 kB 🟢 -5.43 kB
assets/Load3dViewerContent-D2ZY3xZH.js (new) 30.8 kB 🔴 +30.8 kB 🔴 +6.27 kB 🔴 +5.43 kB
assets/HdrViewerContent-B2kQlukn.js (new) 29.8 kB 🔴 +29.8 kB 🔴 +8.25 kB 🔴 +7.27 kB
assets/HdrViewerContent-Cr9I7cw3.js (removed) 29.8 kB 🟢 -29.8 kB 🟢 -8.25 kB 🟢 -7.27 kB
assets/SubscriptionRequiredDialogContent-B7Zen_mi.js (removed) 26.1 kB 🟢 -26.1 kB 🟢 -6.14 kB 🟢 -5.4 kB
assets/SubscriptionRequiredDialogContent-C-9pzNQp.js (new) 26.1 kB 🔴 +26.1 kB 🔴 +6.14 kB 🔴 +5.41 kB
assets/SubscriptionRequiredDialogContentWorkspace-BqYiG8gr.js (new) 25.1 kB 🔴 +25.1 kB 🔴 +5.8 kB 🔴 +5.1 kB
assets/SubscriptionRequiredDialogContentWorkspace-CMgsauO2.js (removed) 25.1 kB 🟢 -25.1 kB 🟢 -5.8 kB 🟢 -5.1 kB
assets/load3d-Cx5EbaOu.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -5.4 kB 🟢 -4.67 kB
assets/load3d-CZ_Rg-F6.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +5.41 kB 🔴 +4.67 kB
assets/CurrentUserPopoverWorkspace-CD4jnMk4.js (removed) 20.5 kB 🟢 -20.5 kB 🟢 -4.69 kB 🟢 -4.18 kB
assets/CurrentUserPopoverWorkspace-DGDqSLjy.js (new) 20.5 kB 🔴 +20.5 kB 🔴 +4.69 kB 🔴 +4.18 kB
assets/SignInContent-CEKGLxz_.js (removed) 20.2 kB 🟢 -20.2 kB 🟢 -5.1 kB 🟢 -4.46 kB
assets/SignInContent-CqZNjTt-.js (new) 20.2 kB 🔴 +20.2 kB 🔴 +5.1 kB 🔴 +4.47 kB
assets/CreditsTile-Bhg3SiGD.js (new) 19 kB 🔴 +19 kB 🔴 +4.79 kB 🔴 +4.23 kB
assets/CreditsTile-CJsZnIYf.js (removed) 19 kB 🟢 -19 kB 🟢 -4.79 kB 🟢 -4.23 kB
assets/WidgetRecordAudio-Co7jv-U2.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.59 kB 🟢 -4.09 kB
assets/WidgetRecordAudio-DY-urby0.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.59 kB 🔴 +4.09 kB
assets/i18n-DLM7_bFW.js (new) 15.4 kB 🔴 +15.4 kB 🔴 +4.25 kB 🔴 +3.57 kB
assets/WidgetInputNumber-C5njmLUo.js (removed) 13.9 kB 🟢 -13.9 kB 🟢 -3.63 kB 🟢 -3.21 kB
assets/WidgetInputNumber-CRWtBXXM.js (new) 13.9 kB 🔴 +13.9 kB 🔴 +3.63 kB 🔴 +3.22 kB
assets/WidgetRange-C9tGL5h3.js (new) 13.7 kB 🔴 +13.7 kB 🔴 +3.53 kB 🔴 +3.11 kB
assets/WidgetRange-CHZgM8BO.js (removed) 13.7 kB 🟢 -13.7 kB 🟢 -3.53 kB 🟢 -3.11 kB
assets/WaveAudioPlayer-GYI2YOI8.js (new) 12.8 kB 🔴 +12.8 kB 🔴 +3.46 kB 🔴 +3.05 kB
assets/WaveAudioPlayer-WgtEe4dN.js (removed) 12.8 kB 🟢 -12.8 kB 🟢 -3.46 kB 🟢 -3.04 kB
assets/i18n-DHgUSMrB.js (removed) 12.5 kB 🟢 -12.5 kB 🟢 -3.31 kB 🟢 -2.79 kB
assets/WidgetCurve-CCeF71g5.js (new) 11.2 kB 🔴 +11.2 kB 🔴 +3.47 kB 🔴 +3.13 kB
assets/WidgetCurve-GxRGzDtq.js (removed) 11.2 kB 🟢 -11.2 kB 🟢 -3.48 kB 🟢 -3.14 kB
assets/AudioPreviewPlayer-BrwN-RJs.js (new) 10.6 kB 🔴 +10.6 kB 🔴 +3.05 kB 🔴 +2.72 kB
assets/AudioPreviewPlayer-CoEPnXB6.js (removed) 10.6 kB 🟢 -10.6 kB 🟢 -3.05 kB 🟢 -2.71 kB
assets/TeamWorkspacesDialogContent-DpZi0WWq.js (new) 10.3 kB 🔴 +10.3 kB 🔴 +2.97 kB 🔴 +2.63 kB
assets/TeamWorkspacesDialogContent-Z_fsFKAG.js (removed) 10.3 kB 🟢 -10.3 kB 🟢 -2.97 kB 🟢 -2.63 kB
assets/onboardingCloudRoutes-CanB-6jz.js (new) 9.13 kB 🔴 +9.13 kB 🔴 +2.79 kB 🔴 +2.39 kB
assets/onboardingCloudRoutes-Bsuragl4.js (removed) 9.12 kB 🟢 -9.12 kB 🟢 -2.79 kB 🟢 -2.38 kB
assets/Load3DConfiguration-C_wYUpOu.js (removed) 8.91 kB 🟢 -8.91 kB 🟢 -2.61 kB 🟢 -2.3 kB
assets/Load3DConfiguration-DdiVZz5M.js (new) 8.91 kB 🔴 +8.91 kB 🔴 +2.61 kB 🔴 +2.3 kB
assets/WidgetImageCrop-DCy5MRl-.js (removed) 8.49 kB 🟢 -8.49 kB 🟢 -2.65 kB 🟢 -2.34 kB
assets/WidgetImageCrop-TQAzh8Mh.js (new) 8.49 kB 🔴 +8.49 kB 🔴 +2.65 kB 🔴 +2.34 kB
assets/SetMemberCreditLimitDialogContent-B5TrU4tM.js (new) 8.47 kB 🔴 +8.47 kB 🔴 +2.34 kB 🔴 +2.05 kB
assets/SetMemberCreditLimitDialogContent-B7tFNPGg.js (removed) 8.47 kB 🟢 -8.47 kB 🟢 -2.34 kB 🟢 -2.05 kB
assets/nodeTemplates-CvvOBKiI.js (new) 8.28 kB 🔴 +8.28 kB 🔴 +2.85 kB 🔴 +2.5 kB
assets/nodeTemplates-fB1nnp6E.js (removed) 8.28 kB 🟢 -8.28 kB 🟢 -2.84 kB 🟢 -2.51 kB
assets/NightlySurveyController-BTIePpmz.js (new) 7.5 kB 🔴 +7.5 kB 🔴 +2.56 kB 🔴 +2.24 kB
assets/NightlySurveyController-lMgHF_fz.js (removed) 7.5 kB 🟢 -7.5 kB 🟢 -2.55 kB 🟢 -2.24 kB
assets/WidgetWithControl-Bd5ttlBm.js (removed) 6.37 kB 🟢 -6.37 kB 🟢 -2.59 kB 🟢 -2.31 kB
assets/WidgetWithControl-PqB7dC5R.js (new) 6.37 kB 🔴 +6.37 kB 🔴 +2.59 kB 🔴 +2.27 kB
assets/tierBenefits-BexxrQlE.js (new) 6.2 kB 🔴 +6.2 kB 🔴 +1.97 kB 🔴 +1.71 kB
assets/tierBenefits-VclIfmFw.js (removed) 6.2 kB 🟢 -6.2 kB 🟢 -1.97 kB 🟢 -1.71 kB
assets/CancelSubscriptionDialogContent-CH9BZraH.js (removed) 5.97 kB 🟢 -5.97 kB 🟢 -1.98 kB 🟢 -1.74 kB
assets/CancelSubscriptionDialogContent-DcTvcAIZ.js (new) 5.97 kB 🔴 +5.97 kB 🔴 +1.98 kB 🔴 +1.74 kB
assets/load3dPreviewExtensions-CQIsJchm.js (new) 5.88 kB 🔴 +5.88 kB 🔴 +1.81 kB 🔴 +1.6 kB
assets/load3dPreviewExtensions-Cuo9AL52.js (removed) 5.88 kB 🟢 -5.88 kB 🟢 -1.81 kB 🟢 -1.6 kB
assets/missingModelDownload-CfDS33ZZ.js (new) 5.88 kB 🔴 +5.88 kB 🔴 +2.07 kB 🔴 +1.81 kB
assets/missingModelDownload-CrJ1LbzR.js (removed) 5.88 kB 🟢 -5.88 kB 🟢 -2.08 kB 🟢 -1.81 kB
assets/launchCancellationFlow-CzWFkbHQ.js (new) 5.18 kB 🔴 +5.18 kB 🔴 +1.78 kB 🔴 +1.56 kB
assets/launchCancellationFlow-DsKOeuOo.js (removed) 5.18 kB 🟢 -5.18 kB 🟢 -1.78 kB 🟢 -1.56 kB
assets/CreateWorkspaceDialogContent-HWOg20RY.js (new) 5.12 kB 🔴 +5.12 kB 🔴 +1.79 kB 🔴 +1.55 kB
assets/CreateWorkspaceDialogContent-Q1vioMIe.js (removed) 5.12 kB 🟢 -5.12 kB 🟢 -1.79 kB 🟢 -1.55 kB
assets/ChangeMemberRoleDialogContent-Baa-KqGB.js (new) 4.97 kB 🔴 +4.97 kB 🔴 +1.63 kB 🔴 +1.43 kB
assets/ChangeMemberRoleDialogContent-BrfLmLtR.js (removed) 4.97 kB 🟢 -4.97 kB 🟢 -1.63 kB 🟢 -1.43 kB
assets/EditWorkspaceDialogContent-3xPcCFmK.js (removed) 4.93 kB 🟢 -4.93 kB 🟢 -1.76 kB 🟢 -1.52 kB
assets/EditWorkspaceDialogContent-dSEqnUeF.js (new) 4.93 kB 🔴 +4.93 kB 🔴 +1.76 kB 🔴 +1.52 kB
assets/WidgetTextarea-Cf6mjdjb.js (removed) 4.81 kB 🟢 -4.81 kB 🟢 -1.87 kB 🟢 -1.63 kB
assets/WidgetTextarea-ClfcXLk2.js (new) 4.81 kB 🔴 +4.81 kB 🔴 +1.87 kB 🔴 +1.62 kB
assets/saveMesh-DJ284eaT.js (removed) 4.76 kB 🟢 -4.76 kB 🟢 -1.52 kB 🟢 -1.35 kB
assets/saveMesh-uEdVouHb.js (new) 4.76 kB 🔴 +4.76 kB 🔴 +1.52 kB 🔴 +1.35 kB
assets/WorkspacePanelContent-BWR1CO9F.js (removed) 4.72 kB 🟢 -4.72 kB 🟢 -1.6 kB 🟢 -1.4 kB
assets/WorkspacePanelContent-D8OBUD-h.js (new) 4.72 kB 🔴 +4.72 kB 🔴 +1.6 kB 🔴 +1.4 kB
assets/InviteMemberDialogContent-5qOGxsjQ.js (new) 4.68 kB 🔴 +4.68 kB 🔴 +1.58 kB 🔴 +1.37 kB
assets/InviteMemberDialogContent-B5Z7sroI.js (removed) 4.68 kB 🟢 -4.68 kB 🟢 -1.58 kB 🟢 -1.38 kB
assets/ValueControlPopover-CNXHEKGF.js (new) 4.49 kB 🔴 +4.49 kB 🔴 +1.55 kB 🔴 +1.38 kB
assets/ValueControlPopover-Dmd60SJ8.js (removed) 4.49 kB 🟢 -4.49 kB 🟢 -1.55 kB 🟢 -1.38 kB
assets/ApiNodesSignInContent-D_PFIHzi.js (removed) 4.08 kB 🟢 -4.08 kB 🟢 -1.31 kB 🟢 -1.15 kB
assets/ApiNodesSignInContent-DAYSv7Rc.js (new) 4.08 kB 🔴 +4.08 kB 🔴 +1.31 kB 🔴 +1.14 kB
assets/DeleteWorkspaceDialogContent-BtpUo5Yi.js (removed) 3.84 kB 🟢 -3.84 kB 🟢 -1.44 kB 🟢 -1.23 kB
assets/DeleteWorkspaceDialogContent-D2zlZSmP.js (new) 3.84 kB 🔴 +3.84 kB 🔴 +1.44 kB 🔴 +1.23 kB
assets/LeaveWorkspaceDialogContent-B68VzaH1.js (new) 3.67 kB 🔴 +3.67 kB 🔴 +1.38 kB 🔴 +1.19 kB
assets/LeaveWorkspaceDialogContent-CN3e1Kjy.js (removed) 3.67 kB 🟢 -3.67 kB 🟢 -1.38 kB 🟢 -1.19 kB
assets/RemoveMemberDialogContent-C3DUlTCL.js (new) 3.65 kB 🔴 +3.65 kB 🔴 +1.33 kB 🔴 +1.15 kB
assets/RemoveMemberDialogContent-CHJsChe-.js (removed) 3.65 kB 🟢 -3.65 kB 🟢 -1.33 kB 🟢 -1.15 kB
assets/RevokeInviteDialogContent-B7R-lzTT.js (new) 3.56 kB 🔴 +3.56 kB 🔴 +1.35 kB 🔴 +1.17 kB
assets/RevokeInviteDialogContent-DHN0oq--.js (removed) 3.56 kB 🟢 -3.56 kB 🟢 -1.34 kB 🟢 -1.17 kB
assets/InviteMemberUpsellDialogContent-D852zCr9.js (new) 3.44 kB 🔴 +3.44 kB 🔴 +1.23 kB 🔴 +1.09 kB
assets/InviteMemberUpsellDialogContent-uVFXnNxK.js (removed) 3.44 kB 🟢 -3.44 kB 🟢 -1.23 kB 🟢 -1.08 kB
assets/workspaceCheckoutTelemetry-C7YaIgnX.js (removed) 3.4 kB 🟢 -3.4 kB 🟢 -1.52 kB 🟢 -1.33 kB
assets/workspaceCheckoutTelemetry-Di-QhImu.js (new) 3.4 kB 🔴 +3.4 kB 🔴 +1.52 kB 🔴 +1.32 kB
assets/Media3DTop-FL76KBdY.js (new) 3.21 kB 🔴 +3.21 kB 🔴 +1.27 kB 🔴 +1.1 kB
assets/Media3DTop-jMri1Atu.js (removed) 3.21 kB 🟢 -3.21 kB 🟢 -1.27 kB 🟢 -1.1 kB
assets/GlobalToast-BegDfYvH.js (new) 3 kB 🔴 +3 kB 🔴 +1.22 kB 🔴 +1.04 kB
assets/GlobalToast-BsybZWaJ.js (removed) 3 kB 🟢 -3 kB 🟢 -1.22 kB 🟢 -1.06 kB
assets/load3dAdvanced-DQFu4Yk8.js (removed) 2.82 kB 🟢 -2.82 kB 🟢 -1.09 kB 🟢 -954 B
assets/load3dAdvanced-z7DmWJXr.js (new) 2.82 kB 🔴 +2.82 kB 🔴 +1.1 kB 🔴 +954 B
assets/SubscribeToRun-DKnXcSgy.js (removed) 2.39 kB 🟢 -2.39 kB 🟢 -1.03 kB 🟢 -925 B
assets/SubscribeToRun-Z6XkS54T.js (new) 2.39 kB 🔴 +2.39 kB 🔴 +1.03 kB 🔴 +917 B
assets/MediaAudioTop-68eaUAKB.js (new) 1.62 kB 🔴 +1.62 kB 🔴 +808 B 🔴 +665 B
assets/MediaAudioTop-qMZ-OW0Q.js (removed) 1.62 kB 🟢 -1.62 kB 🟢 -805 B 🟢 -665 B
assets/signInSchema-Du8SCm9T.js (removed) 1.55 kB 🟢 -1.55 kB 🟢 -554 B 🟢 -513 B
assets/signInSchema-we5qKWkc.js (new) 1.55 kB 🔴 +1.55 kB 🔴 +554 B 🔴 +521 B
assets/CloudRunButtonWrapper-CSrliK9n.js (removed) 1.05 kB 🟢 -1.05 kB 🟢 -515 B 🟢 -448 B
assets/CloudRunButtonWrapper-ylNdN2Bn.js (new) 1.05 kB 🔴 +1.05 kB 🔴 +516 B 🔴 +454 B
assets/cloudSessionCookie-CJK1Tx8X.js (removed) 933 B 🟢 -933 B 🟢 -433 B 🟢 -379 B
assets/cloudSessionCookie-tsiDq3Xp.js (new) 933 B 🔴 +933 B 🔴 +431 B 🔴 +377 B
assets/cloudBadges-CHxJV6sa.js (removed) 922 B 🟢 -922 B 🟢 -515 B 🟢 -462 B
assets/cloudBadges-x8AX5D4I.js (new) 922 B 🔴 +922 B 🔴 +514 B 🔴 +438 B
assets/Load3DAdvanced-Bu1b7vOo.js (new) 761 B 🔴 +761 B 🔴 +422 B 🔴 +360 B
assets/Load3DAdvanced-yOVTsScj.js (removed) 761 B 🟢 -761 B 🟢 -422 B 🟢 -358 B
assets/nightlyBadges-Cn97cncW.js (new) 411 B 🔴 +411 B 🔴 +273 B 🔴 +273 B
assets/nightlyBadges-CNpFuVHZ.js (removed) 411 B 🟢 -411 B 🟢 -272 B 🟢 -260 B
assets/missingModelDownload-BwKfwBrK.js (new) 371 B 🔴 +371 B 🔴 +204 B 🔴 +178 B
assets/missingModelDownload-CVVexvEL.js (removed) 371 B 🟢 -371 B 🟢 -203 B 🟢 -173 B
assets/SubscriptionPanelContentWorkspace-CwxsILeU.js (new) 179 B 🔴 +179 B 🔴 +117 B 🔴 +92 B
assets/SubscriptionPanelContentWorkspace-DCKGNA6H.js (removed) 179 B 🟢 -179 B 🟢 -117 B 🟢 -104 B
assets/Load3dViewerContent-B52ty8P2.js (new) 137 B 🔴 +137 B 🔴 +103 B 🔴 +94 B
assets/Load3dViewerContent-BQlJAinL.js (removed) 137 B 🟢 -137 B 🟢 -103 B 🟢 -86 B
assets/Load3DAdvanced-DFuq89kq.js (new) 122 B 🔴 +122 B 🔴 +97 B 🔴 +88 B
assets/Load3DAdvanced-KEyKzG2t.js (removed) 122 B 🟢 -122 B 🟢 -97 B 🟢 -87 B
assets/WidgetLegacy-CZTep2gq.js (new) 117 B 🔴 +117 B 🔴 +106 B 🔴 +101 B
assets/WidgetLegacy-D-ArbR69.js (removed) 117 B 🟢 -117 B 🟢 -106 B 🟢 -98 B
assets/workflowDraftStoreV2-6GbiwaLE.js (new) 112 B 🔴 +112 B 🔴 +101 B 🔴 +116 B
assets/workflowDraftStoreV2-BSktXhPW.js (removed) 112 B 🟢 -112 B 🟢 -101 B 🟢 -107 B
assets/Load3D--z3dWmzC.js (removed) 98 B 🟢 -98 B 🟢 -89 B 🟢 -84 B
assets/Load3D-Bb6hNjYc.js (new) 98 B 🔴 +98 B 🔴 +89 B 🔴 +88 B
assets/i18n-Bxsd80Q1.js (removed) 97 B 🟢 -97 B 🟢 -92 B 🟢 -87 B
assets/i18n-C-3j9IjV.js (new) 97 B 🔴 +97 B 🔴 +92 B 🔴 +85 B
assets/changeTracker-CQNPvEp9.js (removed) 91 B 🟢 -91 B 🟢 -93 B 🟢 -81 B
assets/changeTracker-DP2DsuW7.js (new) 91 B 🔴 +91 B 🔴 +93 B 🔴 +85 B

Status: 76 added / 76 removed / 205 unchanged

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 66.2 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 48.0 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 68.9 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 50.6 MB heap
large-graph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 63.2 MB heap
large-graph-pan: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 57.5 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 68.3 MB heap
minimap-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 64.8 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 51.1 MB heap
subgraph-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 44.4 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 45.8 MB heap
subgraph-transition-enter: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 135ms TBT · 94.5 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 66.1 MB heap
vue-large-graph-idle: · 57.1 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 152.8 MB heap
vue-large-graph-pan: · 55.4 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 224ms TBT · 164.8 MB heap
workflow-execution: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 64.8 MB heap

⚠️ 6 regressions detected

Show regressions
Metric Baseline PR (median) Δ Sig
canvas-idle: task duration 373ms 468ms +25% ⚠️ z=2.4
canvas-zoom-sweep: task duration 319ms 375ms +17% ⚠️ z=2.1
large-graph-idle: task duration 540ms 667ms +24% ⚠️ z=2.3
large-graph-pan: task duration 991ms 1287ms +30% ⚠️ z=4.8
minimap-idle: task duration 549ms 656ms +20% ⚠️ z=2.7
subgraph-idle: task duration 375ms 481ms +28% ⚠️ z=3.5
All metrics
Metric Baseline PR (median) Δ Sig
canvas-idle: avg frame time 17ms 17ms +0% z=-0.1
canvas-idle: p95 frame time 17ms 17ms +1%
canvas-idle: layout duration 0ms 0ms +0%
canvas-idle: style recalc duration 8ms 8ms +9% z=-2.7
canvas-idle: layout count 0 0 +0%
canvas-idle: style recalc count 10 10 -5% z=-2.9
canvas-idle: task duration 373ms 468ms +25% ⚠️ z=2.4
canvas-idle: script duration 15ms 16ms +3% z=-4.4
canvas-idle: TBT 0ms 0ms +0%
canvas-idle: heap used 69.9 MB 66.2 MB -5%
canvas-idle: DOM nodes 20 19 -5% z=-2.8
canvas-idle: event listeners 6 4 -33% z=-1.6
canvas-mouse-sweep: avg frame time 17ms 17ms +0% z=-0.4
canvas-mouse-sweep: p95 frame time 17ms 17ms +0%
canvas-mouse-sweep: layout duration 3ms 3ms +10% z=-0.6
canvas-mouse-sweep: style recalc duration 30ms 42ms +39% z=-0.3
canvas-mouse-sweep: layout count 12 12 +0%
canvas-mouse-sweep: style recalc count 72 76 +6% z=-1.1
canvas-mouse-sweep: task duration 747ms 948ms +27% z=1.4
canvas-mouse-sweep: script duration 100ms 128ms +28% z=-1.1
canvas-mouse-sweep: TBT 0ms 0ms +0%
canvas-mouse-sweep: heap used 48.6 MB 48.0 MB -1%
canvas-mouse-sweep: DOM nodes -279 -280 +0% z=-132.2
canvas-mouse-sweep: event listeners -144 -148 +3% z=-37.5
canvas-zoom-sweep: avg frame time 17ms 17ms -0% z=-0.3
canvas-zoom-sweep: p95 frame time 17ms 17ms +1%
canvas-zoom-sweep: layout duration 1ms 1ms +5% z=-1.4
canvas-zoom-sweep: style recalc duration 14ms 17ms +17% z=-1.7
canvas-zoom-sweep: layout count 6 6 +0%
canvas-zoom-sweep: style recalc count 31 32 +2% z=0.5
canvas-zoom-sweep: task duration 319ms 375ms +17% ⚠️ z=2.1
canvas-zoom-sweep: script duration 17ms 18ms +6% z=-3.0
canvas-zoom-sweep: TBT 0ms 0ms +0%
canvas-zoom-sweep: heap used 72.3 MB 68.9 MB -5%
canvas-zoom-sweep: DOM nodes 77 78 +1% z=-2.2
canvas-zoom-sweep: event listeners 19 19 +0% z=-0.9
dom-widget-clipping: avg frame time 17ms 17ms -0% z=-0.2
dom-widget-clipping: p95 frame time 17ms 17ms -0%
dom-widget-clipping: layout duration 0ms 0ms +0%
dom-widget-clipping: style recalc duration 6ms 9ms +43% z=-1.1
dom-widget-clipping: layout count 0 0 +0%
dom-widget-clipping: style recalc count 11 11 -5% z=-5.2
dom-widget-clipping: task duration 310ms 390ms +26% z=1.5
dom-widget-clipping: script duration 46ms 62ms +34% z=-1.8
dom-widget-clipping: TBT 0ms 0ms +0%
dom-widget-clipping: heap used 53.2 MB 50.6 MB -5%
dom-widget-clipping: DOM nodes 18 17 -6% z=-3.6
dom-widget-clipping: event listeners 2 1 -50% variance too high
large-graph-idle: avg frame time 17ms 17ms -0% z=-0.6
large-graph-idle: p95 frame time 17ms 17ms -0%
large-graph-idle: layout duration 0ms 0ms +0%
large-graph-idle: style recalc duration 7ms 8ms +7% z=-4.5
large-graph-idle: layout count 0 0 +0%
large-graph-idle: style recalc count 9 9 -6% z=-9.9
large-graph-idle: task duration 540ms 667ms +24% ⚠️ z=2.3
large-graph-idle: script duration 80ms 102ms +27% z=-0.1
large-graph-idle: TBT 0ms 0ms +0%
large-graph-idle: heap used 64.3 MB 63.2 MB -2%
large-graph-idle: DOM nodes -281 -281 +0% z=-338.2
large-graph-idle: event listeners -144 -142 -1% z=-27.6
large-graph-pan: avg frame time 17ms 17ms +0% z=0.3
large-graph-pan: p95 frame time 17ms 17ms +0%
large-graph-pan: layout duration 0ms 0ms +0%
large-graph-pan: style recalc duration 13ms 13ms -0% z=-4.8
large-graph-pan: layout count 0 0 +0%
large-graph-pan: style recalc count 68 69 +1% z=-1.7
large-graph-pan: task duration 991ms 1287ms +30% ⚠️ z=4.8
large-graph-pan: script duration 325ms 443ms +36% z=1.8
large-graph-pan: TBT 0ms 0ms +0%
large-graph-pan: heap used 59.1 MB 57.5 MB -3%
large-graph-pan: DOM nodes -284 -283 -1% z=-182.7
large-graph-pan: event listeners -142 -159 +12% z=-198.0
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 +3%
large-graph-zoom: style recalc duration 14ms 16ms +13%
large-graph-zoom: layout count 60 60 +0%
large-graph-zoom: style recalc count 66 64 -4%
large-graph-zoom: task duration 1241ms 1516ms +22%
large-graph-zoom: script duration 430ms 549ms +28%
large-graph-zoom: TBT 0ms 0ms +0%
large-graph-zoom: heap used 51.9 MB 68.3 MB +31%
large-graph-zoom: DOM nodes -285 -140 -51%
large-graph-zoom: event listeners -146 -70 -52%
minimap-idle: avg frame time 17ms 17ms -0% z=0.1
minimap-idle: p95 frame time 17ms 17ms +0%
minimap-idle: layout duration 0ms 0ms +0%
minimap-idle: style recalc duration 7ms 7ms -4% z=-3.7
minimap-idle: layout count 0 0 +0%
minimap-idle: style recalc count 9 8 -17% z=-3.0
minimap-idle: task duration 549ms 656ms +20% ⚠️ z=2.7
minimap-idle: script duration 81ms 102ms +25% z=0.3
minimap-idle: TBT 0ms 0ms +0%
minimap-idle: heap used 65.8 MB 64.8 MB -2%
minimap-idle: DOM nodes -281 -282 +0% z=-219.8
minimap-idle: event listeners -144 -143 -1% z=-223.5
subgraph-dom-widget-clipping: avg frame time 17ms 17ms -0% z=-0.4
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 9ms -7% z=-3.6
subgraph-dom-widget-clipping: layout count 0 0 +0%
subgraph-dom-widget-clipping: style recalc count 48 46 -4% z=-3.3
subgraph-dom-widget-clipping: task duration 325ms 393ms +21% z=0.8
subgraph-dom-widget-clipping: script duration 98ms 115ms +17% z=-2.1
subgraph-dom-widget-clipping: TBT 0ms 0ms +0%
subgraph-dom-widget-clipping: heap used 53.4 MB 51.1 MB -4%
subgraph-dom-widget-clipping: DOM nodes 22 18 -18% z=-3.7
subgraph-dom-widget-clipping: event listeners 8 6 -25% z=-1.7
subgraph-idle: avg frame time 17ms 17ms -0% z=-0.2
subgraph-idle: p95 frame time 17ms 17ms +0%
subgraph-idle: layout duration 0ms 0ms +0%
subgraph-idle: style recalc duration 8ms 8ms +5% z=-3.2
subgraph-idle: layout count 0 0 +0%
subgraph-idle: style recalc count 10 9 -10% z=-2.9
subgraph-idle: task duration 375ms 481ms +28% ⚠️ z=3.5
subgraph-idle: script duration 14ms 14ms +0% z=-2.4
subgraph-idle: TBT 0ms 0ms +0%
subgraph-idle: heap used 69.3 MB 44.4 MB -36%
subgraph-idle: DOM nodes 20 -131 -755% z=-102.2
subgraph-idle: event listeners 6 -72 -1300% 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 3ms 4ms +25% z=-1.1
subgraph-mouse-sweep: style recalc duration 30ms 35ms +17% z=-2.3
subgraph-mouse-sweep: layout count 16 16 +0%
subgraph-mouse-sweep: style recalc count 76 75 -2% z=-2.9
subgraph-mouse-sweep: task duration 660ms 804ms +22% z=0.5
subgraph-mouse-sweep: script duration 76ms 93ms +23% z=-1.1
subgraph-mouse-sweep: TBT 0ms 0ms +0%
subgraph-mouse-sweep: heap used 45.9 MB 45.8 MB -0%
subgraph-mouse-sweep: DOM nodes -277 -281 +1% z=-155.5
subgraph-mouse-sweep: event listeners -146 -148 +1% 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 9ms 13ms +45%
subgraph-transition-enter: style recalc duration 23ms 30ms +31%
subgraph-transition-enter: layout count 15 14 -7%
subgraph-transition-enter: style recalc count 19 18 -5%
subgraph-transition-enter: task duration 706ms 908ms +28%
subgraph-transition-enter: script duration 22ms 33ms +50%
subgraph-transition-enter: TBT 80ms 135ms +69%
subgraph-transition-enter: heap used 94.1 MB 94.5 MB +0%
subgraph-transition-enter: DOM nodes 13673 13673 +0%
subgraph-transition-enter: event listeners 2369 2371 +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 38ms 36ms -5%
viewport-pan-sweep: layout count 0 0 +0%
viewport-pan-sweep: style recalc count 249 250 +0%
viewport-pan-sweep: task duration 3543ms 4470ms +26%
viewport-pan-sweep: script duration 1065ms 1384ms +30%
viewport-pan-sweep: TBT 0ms 0ms +0%
viewport-pan-sweep: heap used 64.3 MB 66.1 MB +3%
viewport-pan-sweep: DOM nodes -279 -281 +1%
viewport-pan-sweep: event listeners -128 -128 +0%
vue-large-graph-idle: avg frame time 18ms 17ms -2%
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 14396ms 16694ms +16%
vue-large-graph-idle: script duration 408ms 522ms +28%
vue-large-graph-idle: TBT 0ms 0ms +0%
vue-large-graph-idle: heap used 159.6 MB 152.8 MB -4%
vue-large-graph-idle: DOM nodes -8312 -8314 +0%
vue-large-graph-idle: event listeners -16389 -16387 -0%
vue-large-graph-pan: avg frame time 17ms 18ms +5%
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 13ms 16ms +23%
vue-large-graph-pan: layout count 0 0 +0%
vue-large-graph-pan: style recalc count 115 141 +22%
vue-large-graph-pan: task duration 16738ms 20595ms +23%
vue-large-graph-pan: script duration 692ms 871ms +26%
vue-large-graph-pan: TBT 12ms 224ms +1763%
vue-large-graph-pan: heap used 147.1 MB 164.8 MB +12%
vue-large-graph-pan: DOM nodes -8312 -8312 +0%
vue-large-graph-pan: event listeners -16387 -16381 -0%
workflow-execution: avg frame time 17ms 17ms -0% z=0.1
workflow-execution: p95 frame time 17ms 17ms -1%
workflow-execution: layout duration 0ms 0ms +23% z=-7.3
workflow-execution: style recalc duration 15ms 18ms +19% z=-2.8
workflow-execution: layout count 2 3 +25% z=-4.5
workflow-execution: style recalc count 14 13 -7% z=-2.3
workflow-execution: task duration 91ms 103ms +13% z=-1.9
workflow-execution: script duration 8ms 9ms +21% z=-6.7
workflow-execution: TBT 0ms 0ms +0%
workflow-execution: heap used 48.7 MB 64.8 MB +33%
workflow-execution: DOM nodes 121 125 +3% z=-5.1
workflow-execution: event listeners 65 66 +2% z=3.2
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-03T23:59:34.634Z",
  "gitSha": "6d5607e4be665d4482762b57fe6c78adbac26352",
  "branch": "fix/en-node-display-names-from-backend",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2092.010000000073,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 8.579000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 485.7389999999999,
      "heapDeltaBytes": 5414236,
      "heapUsedBytes": 69366036,
      "domNodes": 20,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 15.787999999999997,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-idle",
      "durationMs": 2039.357999999993,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 8.175000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 450.80600000000004,
      "heapDeltaBytes": 5559068,
      "heapUsedBytes": 69384240,
      "domNodes": 18,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 15.312999999999999,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 2051.3939999999593,
      "styleRecalcs": 78,
      "styleRecalcDurationMs": 47.614999999999995,
      "layouts": 12,
      "layoutDurationMs": 3.4919999999999995,
      "taskDurationMs": 1029.593,
      "heapDeltaBytes": -10155620,
      "heapUsedBytes": 53611728,
      "domNodes": -280,
      "jsHeapTotalBytes": 23318528,
      "scriptDurationMs": 134.963,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1836.1579999999549,
      "styleRecalcs": 74,
      "styleRecalcDurationMs": 36.049,
      "layouts": 12,
      "layoutDurationMs": 3.5030000000000006,
      "taskDurationMs": 865.9549999999999,
      "heapDeltaBytes": -16743912,
      "heapUsedBytes": 46960024,
      "domNodes": -279,
      "jsHeapTotalBytes": 24104960,
      "scriptDurationMs": 121.97699999999999,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1720.843000000059,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 14.902000000000001,
      "layouts": 6,
      "layoutDurationMs": 0.5,
      "taskDurationMs": 363.18,
      "heapDeltaBytes": 8183164,
      "heapUsedBytes": 71950576,
      "domNodes": 77,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 17.567999999999998,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1771.0960000000568,
      "styleRecalcs": 32,
      "styleRecalcDurationMs": 18.224999999999998,
      "layouts": 6,
      "layoutDurationMs": 0.6630000000000001,
      "taskDurationMs": 386.59200000000004,
      "heapDeltaBytes": 8679232,
      "heapUsedBytes": 72616676,
      "domNodes": 78,
      "jsHeapTotalBytes": 24379392,
      "scriptDurationMs": 18.669999999999998,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 649.9679999999444,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 10.081,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 411.64399999999995,
      "heapDeltaBytes": -10595376,
      "heapUsedBytes": 53131608,
      "domNodes": 16,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 65.71199999999999,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 573.5600000000431,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 7.9959999999999996,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 368.025,
      "heapDeltaBytes": -10908228,
      "heapUsedBytes": 52900588,
      "domNodes": 18,
      "jsHeapTotalBytes": 25952256,
      "scriptDurationMs": 58.419,
      "eventListeners": 0,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2026.7109999999775,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 7.755000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 665.4789999999999,
      "heapDeltaBytes": 7166372,
      "heapUsedBytes": 66574244,
      "domNodes": -280,
      "jsHeapTotalBytes": 2998272,
      "scriptDurationMs": 99.99,
      "eventListeners": -142,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2039.1750000000002,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 7.3100000000000005,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 667.9380000000001,
      "heapDeltaBytes": 6658732,
      "heapUsedBytes": 66003648,
      "domNodes": -282,
      "jsHeapTotalBytes": 3260416,
      "scriptDurationMs": 103.855,
      "eventListeners": -142,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2147.770000000037,
      "styleRecalcs": 68,
      "styleRecalcDurationMs": 12.723000000000003,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1308.947,
      "heapDeltaBytes": -6531648,
      "heapUsedBytes": 55027812,
      "domNodes": -283,
      "jsHeapTotalBytes": 3784704,
      "scriptDurationMs": 455.281,
      "eventListeners": -174,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2158.681999999999,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 14.140000000000004,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1265.259,
      "heapDeltaBytes": 5111272,
      "heapUsedBytes": 65617892,
      "domNodes": -282,
      "jsHeapTotalBytes": 3977216,
      "scriptDurationMs": 430.655,
      "eventListeners": -144,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3245.5739999999196,
      "styleRecalcs": 63,
      "styleRecalcDurationMs": 14.962000000000003,
      "layouts": 60,
      "layoutDurationMs": 7.271,
      "taskDurationMs": 1515.176,
      "heapDeltaBytes": 23237224,
      "heapUsedBytes": 85758292,
      "domNodes": 8,
      "jsHeapTotalBytes": 7340032,
      "scriptDurationMs": 554.856,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3180.115999999998,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 16.477,
      "layouts": 60,
      "layoutDurationMs": 6.944000000000001,
      "taskDurationMs": 1517.165,
      "heapDeltaBytes": -5420016,
      "heapUsedBytes": 57430540,
      "domNodes": -288,
      "jsHeapTotalBytes": 5881856,
      "scriptDurationMs": 542.927,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "minimap-idle",
      "durationMs": 2026.2010000000146,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 6.915000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 655.265,
      "heapDeltaBytes": 7144256,
      "heapUsedBytes": 67897588,
      "domNodes": -282,
      "jsHeapTotalBytes": 2998272,
      "scriptDurationMs": 101.628,
      "eventListeners": -144,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "minimap-idle",
      "durationMs": 2038.2749999999987,
      "styleRecalcs": 7,
      "styleRecalcDurationMs": 6.187999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 657.1530000000001,
      "heapDeltaBytes": 7331724,
      "heapUsedBytes": 67970532,
      "domNodes": -281,
      "jsHeapTotalBytes": 2736128,
      "scriptDurationMs": 101.497,
      "eventListeners": -142,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 557.5179999999591,
      "styleRecalcs": 46,
      "styleRecalcDurationMs": 8.946,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 386.36199999999997,
      "heapDeltaBytes": -10438956,
      "heapUsedBytes": 53508188,
      "domNodes": 18,
      "jsHeapTotalBytes": 25690112,
      "scriptDurationMs": 113.727,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 589.8489999999583,
      "styleRecalcs": 46,
      "styleRecalcDurationMs": 9.632000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 399.67600000000004,
      "heapDeltaBytes": -10367844,
      "heapUsedBytes": 53616580,
      "domNodes": 18,
      "jsHeapTotalBytes": 25952256,
      "scriptDurationMs": 116.333,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2037.5510000000077,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 8.056000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 479.432,
      "heapDeltaBytes": -15863572,
      "heapUsedBytes": 47919212,
      "domNodes": -280,
      "jsHeapTotalBytes": 23056384,
      "scriptDurationMs": 13.603,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2037.5420000000304,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 7.767000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 481.62699999999995,
      "heapDeltaBytes": -19001368,
      "heapUsedBytes": 45096480,
      "domNodes": 18,
      "jsHeapTotalBytes": 24104960,
      "scriptDurationMs": 13.980999999999998,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1702.3929999999154,
      "styleRecalcs": 74,
      "styleRecalcDurationMs": 34.996,
      "layouts": 16,
      "layoutDurationMs": 4.718,
      "taskDurationMs": 818.359,
      "heapDeltaBytes": -14896892,
      "heapUsedBytes": 48957740,
      "domNodes": -283,
      "jsHeapTotalBytes": 23580672,
      "scriptDurationMs": 95.895,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1730.152999999973,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 34.31400000000001,
      "layouts": 16,
      "layoutDurationMs": 3.9689999999999994,
      "taskDurationMs": 789.365,
      "heapDeltaBytes": -16902344,
      "heapUsedBytes": 47046932,
      "domNodes": -278,
      "jsHeapTotalBytes": 23580672,
      "scriptDurationMs": 90.834,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-transition-enter",
      "durationMs": 1383.5579999999936,
      "styleRecalcs": 18,
      "styleRecalcDurationMs": 30.032000000000004,
      "layouts": 14,
      "layoutDurationMs": 12.659,
      "taskDurationMs": 907.561,
      "heapDeltaBytes": 31007968,
      "heapUsedBytes": 99045872,
      "domNodes": 13673,
      "jsHeapTotalBytes": 15466496,
      "scriptDurationMs": 33.36800000000001,
      "eventListeners": 2371,
      "totalBlockingTimeMs": 135,
      "frameDurationMs": 16.666666666666636,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8224.57799999995,
      "styleRecalcs": 249,
      "styleRecalcDurationMs": 35.569,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4369.013,
      "heapDeltaBytes": 8686336,
      "heapUsedBytes": 67842124,
      "domNodes": -282,
      "jsHeapTotalBytes": 5812224,
      "scriptDurationMs": 1366.769,
      "eventListeners": -128,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8295.044999999958,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 36.777,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4570.399,
      "heapDeltaBytes": 11430408,
      "heapUsedBytes": 70797852,
      "domNodes": -280,
      "jsHeapTotalBytes": 5287936,
      "scriptDurationMs": 1401.1639999999998,
      "eventListeners": -128,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 16477.700000000026,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 16462.67,
      "heapDeltaBytes": -68347128,
      "heapUsedBytes": 153874092,
      "domNodes": -8316,
      "jsHeapTotalBytes": -9375744,
      "scriptDurationMs": 507.87500000000006,
      "eventListeners": -16387,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.219999999999953,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 16942.465999999968,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 16924.858,
      "heapDeltaBytes": -31910248,
      "heapUsedBytes": 166498092,
      "domNodes": -8312,
      "jsHeapTotalBytes": -14098432,
      "scriptDurationMs": 536.756,
      "eventListeners": -16387,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 20453.34200000002,
      "styleRecalcs": 138,
      "styleRecalcDurationMs": 15.950999999999993,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 20428.072,
      "heapDeltaBytes": -28448676,
      "heapUsedBytes": 176705132,
      "domNodes": -8312,
      "jsHeapTotalBytes": -10231808,
      "scriptDurationMs": 849.672,
      "eventListeners": -16381,
      "totalBlockingTimeMs": 122,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 20794.511000000057,
      "styleRecalcs": 143,
      "styleRecalcDurationMs": 16.60600000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 20761.001,
      "heapDeltaBytes": -54225696,
      "heapUsedBytes": 168828076,
      "domNodes": -8312,
      "jsHeapTotalBytes": -14098432,
      "scriptDurationMs": 892.233,
      "eventListeners": -16381,
      "totalBlockingTimeMs": 325,
      "frameDurationMs": 18.33666666666674,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "workflow-execution",
      "durationMs": 453.20300000003044,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 18.317,
      "layouts": 3,
      "layoutDurationMs": 0.662,
      "taskDurationMs": 108.062,
      "heapDeltaBytes": 4996556,
      "heapUsedBytes": 68129248,
      "domNodes": 130,
      "jsHeapTotalBytes": 4980736,
      "scriptDurationMs": 9.45,
      "eventListeners": 67,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 454.6069999998963,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 17.877,
      "layouts": 2,
      "layoutDurationMs": 0.30900000000000005,
      "taskDurationMs": 97.27900000000001,
      "heapDeltaBytes": 4762352,
      "heapUsedBytes": 67751924,
      "domNodes": 119,
      "jsHeapTotalBytes": 4718592,
      "scriptDurationMs": 9.060000000000002,
      "eventListeners": 65,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    }
  ]
}

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

🌐 Website E2E

Tip

All tests passed.

Status ✅ Passed
Report View Report

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds shared Vue i18n escaping, backend node text tracking, normalized node-definition resolution, and updated display-name consumers. Tests cover precedence, locale behavior, validation, fallbacks, special characters, custom translations, and dotted names.

Changes

Node-definition localization

Layer / File(s) Summary
Shared i18n escaping
packages/shared-frontend-utils/src/formatUtil.ts, packages/shared-frontend-utils/src/formatUtil.test.ts, scripts/nodeDefLocaleSerializer.ts, scripts/nodeDefLocaleSerializer.test.ts
Adds escapeI18nMessage and applies it to serialized node-definition values, names, labels, descriptions, and categories.
Backend text resolution
src/i18n.ts, src/i18n.test.ts
Adds backend text storage and resolveNodeDefText with custom translation, backend, locale, normalized-key, and fallback handling.
Node-definition loading and translation
src/scripts/app.ts, src/scripts/app.getNodeDefs.test.ts
Validates node-definition responses, registers backend text, and resolves normalized display-name, description, and category keys.
Display-name consumer migration
src/utils/nodeTitleUtil.ts, src/composables/useContextMenuTranslation.ts, src/composables/queue/*, src/components/*, src/platform/*, src/renderer/*, src/stores/*
Removes obsolete st arguments and routes node-definition display text through the centralized resolver.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant getNodeDefs
  participant setBackendNodeText
  participant translateNodeDef
  participant resolveNodeDefText
  participant DisplayNameConsumer
  getNodeDefs->>setBackendNodeText: backend node definitions
  getNodeDefs->>translateNodeDef: fetched definitions
  translateNodeDef->>resolveNodeDefText: display name and description
  resolveNodeDefText-->>translateNodeDef: resolved node text
  DisplayNameConsumer->>resolveNodeDefText: node display-name lookup
  resolveNodeDefText-->>DisplayNameConsumer: localized or fallback text
Loading

Possibly related issues

Possibly related PRs

Suggested labels: core/1.48

Suggested reviewers: benceruleanlu


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
End-To-End Regression Coverage For Fixes ❓ Inconclusive Changed files and description are available, but the PR title and commit subjects are not provided, so the required bug-fix signal cannot be verified. Provide the PR title and commit subjects, or rerun the check with complete PR metadata.
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change: showing backend-submitted node display names in the English locale.
Description check ✅ Passed The description includes a clear summary, detailed changes, breaking-change status, review focus, known gaps, and testing context.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Adr Compliance For Entity/Litegraph Changes ✅ Passed The changed files address i18n, node-definition localization, and display-name consumers; metadata shows no ADR 0003/0008 mutation, ECS, god-object, or extension-callback changes.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/en-node-display-names-from-backend

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 1, 2026
@codecov

codecov Bot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.50746% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/composables/useContextMenuTranslation.ts 0.00% 1 Missing ⚠️
@@            Coverage Diff             @@
##             main   #14541      +/-   ##
==========================================
+ Coverage   78.14%   78.53%   +0.39%     
==========================================
  Files        1768     1778      +10     
  Lines      105794   103212    -2582     
  Branches    32899    33063     +164     
==========================================
- Hits        82669    81061    -1608     
+ Misses      22659    21721     -938     
+ Partials      466      430      -36     
Flag Coverage Δ
unit 70.49% <98.50%> (+0.22%) ⬆️

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

Files with missing lines Coverage Δ
packages/shared-frontend-utils/src/formatUtil.ts 86.66% <100.00%> (+0.27%) ⬆️
...rc/components/queue/QueueInlineProgressSummary.vue 84.21% <ø> (ø)
src/components/rightSidePanel/RightSidePanel.vue 50.90% <ø> (-17.74%) ⬇️
...components/rightSidePanel/errors/useErrorGroups.ts 98.63% <ø> (+1.41%) ⬆️
...omponents/rightSidePanel/parameters/WidgetItem.vue 85.33% <ø> (+2.00%) ⬆️
src/composables/queue/useJobList.ts 98.95% <ø> (ø)
src/i18n.ts 97.14% <100.00%> (+1.83%) ⬆️
...tform/missingMedia/components/MissingMediaCard.vue 93.33% <ø> (ø)
...ngModel/composables/useMissingModelInteractions.ts 95.45% <ø> (ø)
...erer/extensions/vueNodes/components/NodeHeader.vue 81.81% <ø> (-3.74%) ⬇️
... and 4 more

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

@bigcat88 bigcat88 added the New Browser Test Expectations New browser test screenshot should be set by github action label Aug 1, 2026
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

Updating Playwright Expectations

@github-actions github-actions Bot removed the New Browser Test Expectations New browser test screenshot should be set by github action label Aug 1, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 1, 2026

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

Taking this over with bigcat88's permission, so this review is documentation for other readers rather than a gate. Nine reviewers were run across i18n semantics, correctness, regression risk, completeness, architecture, ecosystem compatibility, API contract, test quality and CI. Every finding below was independently reproduced against b87cd114a5 before posting; suspicions that did not survive verification were dropped.

What is right and is being kept

The diagnosis is correct, and the precedence rules stated in the Review Focus are the right rules. The normalizeI18nKey fix in translateNodeDef is a genuine bug nobody else caught: nodeTitleUtil.ts:26, useContextMenuTranslation.ts:169, litegraphService.ts:213, NodeTooltip.vue and useNodeTooltips.ts all already normalized, and the serializer writes normalized keys, so app.ts was the lone outlier reading keys nobody writes. It is kept, with the migration caveat in the inline comment.

One correction to an argument that could otherwise be made against this PR, since it turned out to be wrong on inspection: re-sharing the escape helper does not violate a boundary established by #13643. That PR's rationale was module cohesion, not layering, and it kept scripts/nodeDefLocaleSerializer.ts importing normalizeI18nKey from the same shared package. The package is also private: true, so nothing external widens.

Findings that could not be anchored inline

nodeCategories is un-normalized, four lines below the line this PR fixes. app.ts:1115 builds st(`nodeCategories.${category}`, category) with no normalizeI18nKey, while nodeDefLocaleSerializer.ts:122 writes the normalized key. Confirmed in the shipped locale: en/main.json contains nodeCategories.sync_so = "sync.so", so the consumer asks for nodeCategories.sync.so, vue-i18n resolves it as a nested path, misses, and emits a missing key warning. Same defect class as the line above it, and normalizeI18nKey is already imported by this PR.

One regenerated snapshot has no display name cause. vue-nodes-paned-with-touch-mobile-chrome-linux.png differs by 640 pixels of 285711, confined to rows 59, 69-73 and 611-622. Row 611-622 is the ckpt_name combo widget value; glyph x positions are identical and only antialias coverage differs. The node title row is byte identical. That is sub-pixel rasterization noise, not behavior. Re-baselining it hides future genuine regressions in that golden, and playwright.config.ts sets no toHaveScreenshot tolerance, so it will flap. The other 7 are legitimate and were each confirmed visually.

The goldens now assert a name real users never see. The CI container ghcr.io/comfy-org/comfyui-ci-container:0.0.21 is hardcoded in four workflow files, and no Dockerfile, version file or lockfile in this repo records which ComfyUI commit it contains. Meanwhile en/nodeDefs.json is regenerated each release against ComfyUI master. So the container is behind what ships: the bundle says Compare Images, the container says Image Compare, and the new goldens encode the container's stale name. routeObjectInfoFromSetupApi in browser_tests/fixtures/utils/objectInfo.ts:107 already does exactly the needed stubbing for tooltips and combo options, with widgetTooltip.spec.ts:29-41 as a working reference, so a setNodeDisplayName mutator would remove the container from the goldens' dependency set entirely.

A release signal disappears. Before this change, a core node rename broke screenshot goldens on the version bump PR: annoying, but loud and correctly attributed. After it, English names are overridden at runtime, so the same rename only surfaces later on whatever container bump chore PR happens to cross it, whose author has no context.

Precedence is encoded by replaying another module's private state. mergeBackendNodeDisplayNames re-merges the entire customNodesI18nData['en'] subtree on every call, including from reloadNodeDefs(), because the two producers have no ordering relationship. The invariant does hold today in every ordering traced. The cost is that a third source would need N-squared replay edges, and additive mergeLocaleMessage means a later /api/i18n fetch that drops an entry has it resurrected by the replay.

Performance on heavy installs. Each getNodeDefs() now deep copies the full backend node set into the deeply reactive en message tree, twice, and every backend node subsequently hits the vue-i18n message compiler where previously only the 823 bundled keys did. On a stock install that is a wash. On a 3000 node type install it is roughly 4x the compile work plus about 6000 proxied property writes per refresh, and it runs on startup, on every Refresh Node Definitions, and on locale change.

Verified non-findings, recorded so they are not re-litigated

Custom node precedence holds in both load orders, including the void loadI18n() race, because GraphCanvas.vue:528 awaits isI18nReady before comfyApp.setup(). mergeLocaleMessage is a true recursive merge, so bundled description/inputs/outputs survive for all 823 core nodes. No prototype pollution via __proto__. escapeI18nMessage does not become public API: the comfyAPI shim covers only src/scripts and src/extensions/core, and the package is private with an unchanged exports map. Frontend only nodes are unaffected. Cloud e2e is immune because cloudBootMocks.ts:44 stubs object_info to {}. pnpm knip and pnpm format:check both exit 0.

Plan

Rather than patch the character set and the guards individually, the fix being implemented keeps English off the message compiler entirely: a resolver that holds raw backend values and applies the precedence table explicitly, consulting customNodesI18nData directly instead of replaying merges. That removes the backslash class rather than extending it, removes the unvalidated third party merge from the boot path, and drops the need to escape backend text at runtime at all. Non-English keeps today's behavior unchanged.

Comment thread packages/shared-frontend-utils/src/formatUtil.ts Outdated
Comment thread packages/shared-frontend-utils/src/formatUtil.ts
Comment thread src/i18n.ts Outdated
Comment thread src/i18n.ts Outdated
Comment thread src/i18n.ts Outdated
Comment thread src/scripts/app.ts Outdated
Comment thread src/scripts/app.ts Outdated
Comment thread src/i18n.test.ts Outdated
Comment thread src/scripts/app.getNodeDefs.test.ts Outdated
Comment thread packages/shared-frontend-utils/src/formatUtil.ts
English node display names were shadowed by the bundled en/nodeDefs.json
snapshot, so renaming a core node had no effect until the frontend
regenerated its locale files.

The previous approach escaped backend strings and merged them into the
vue-i18n 'en' message tree. That kept the source language on the message
compiler, which brought several problems: the escape set was incomplete
for vue-i18n 11 (a backslash before an escaped character swallows the
brace the escaper emits, so "C:\@home" failed to compile and rendered as
literal escape syntax), an unvalidated /api/i18n payload was re-merged
from the boot-critical getNodeDefs path where a throw is fatal rather
than degrading, and the merge mutated the imported locale JSON module in
place with no way to evict stale entries.

Resolve instead. Raw /object_info text is kept in a plain map, and
resolveNodeDefText applies precedence explicitly:

  en:    custom-node /api/i18n -> backend -> bundled -> node name
  other: custom-node /api/i18n -> bundled -> backend -> node name

English is the source language, so a backend value is data rather than a
translation and is returned without being compiled. Non-English keeps
today's behaviour, falling back to the live backend value instead of the
stale English snapshot. Custom-node translations still compile, because
the generated locale pipeline escapes them.

Also:
- Fix the escape helper for backslash (double it; vue-i18n cannot express
  a literal backslash via interpolation) and guard non-string input, so
  build-time locale generation is correct for the same inputs.
- Normalize nodeCategories keys, which had the same defect the dotted
  node-name fix addressed four lines above.
- Resolve the legacy nested custom-locale shape as well as the flat
  normalized key, so hand-written locales that nest dotted node ids keep
  working.
- Tolerate a non-object /object_info response.
- Revert a regenerated pan.spec golden whose 640 changed pixels are
  antialiasing on a widget value, with the node title row byte-identical.

Tests cover the precedence table per locale, verbatim rendering of names
containing i18n syntax, eviction of dropped backend text, both key
shapes, and escape round-trips through the real vue-i18n compiler.
Verified by mutation: dropping the English bypass, the legacy key shape,
the eviction, or the backslash fix each fails the suite.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@src/scripts/app.ts`:
- Around line 1122-1123: Validate the `/object_info/` result in the
`getNodeDefs` flow with a type guard that accepts only non-array records before
passing it to `Object.values` and `_.mapValues`; fall back safely for null,
strings, arrays, booleans, and numbers. Update
`src/scripts/app.getNodeDefs.test.ts` lines 103-108 to cover each invalid
response type, while `src/scripts/app.ts` lines 1122-1123 must implement the
narrowing and safe fallback.
- Around line 1105-1112: Update the node text construction around
resolveNodeDefText in getNodeDefs so display_name does not pass def.name as the
backend fallback when display_name is missing; pass only a non-empty backend
value or omit the third argument, allowing bundled/custom text resolution.
Resolve description unconditionally instead of returning an empty string for
missing def.description, and add getNodeDefs tests covering omitted backend
fields with bundled and custom text available.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: aeef71db-ff66-41a7-aa6c-f9df457d795c

📥 Commits

Reviewing files that changed from the base of the PR and between c83f7de and 9d01afb.

⛔ Files ignored due to path filters (7)
  • browser_tests/tests/imageCompare.spec.ts-snapshots/image-compare-default-50-chromium-linux.png is excluded by !**/*.png
  • browser_tests/tests/imageCompare.spec.ts-snapshots/image-compare-slider-25-chromium-linux.png is excluded by !**/*.png
  • browser_tests/tests/imageCompare.spec.ts-snapshots/image-compare-slider-75-chromium-linux.png is excluded by !**/*.png
  • browser_tests/tests/nodeBadge.spec.ts-snapshots/node-lifecycle-None-classic-chromium-linux.png is excluded by !**/*.png
  • browser_tests/tests/nodeBadge.spec.ts-snapshots/node-lifecycle-None-vue-chromium-linux.png is excluded by !**/*.png
  • browser_tests/tests/nodeBadge.spec.ts-snapshots/node-lifecycle-Show-all-classic-chromium-linux.png is excluded by !**/*.png
  • browser_tests/tests/nodeBadge.spec.ts-snapshots/node-lifecycle-Show-all-vue-chromium-linux.png is excluded by !**/*.png
📒 Files selected for processing (19)
  • packages/shared-frontend-utils/src/formatUtil.test.ts
  • packages/shared-frontend-utils/src/formatUtil.ts
  • scripts/nodeDefLocaleSerializer.test.ts
  • src/components/queue/QueueInlineProgressSummary.vue
  • src/components/rightSidePanel/RightSidePanel.vue
  • src/components/rightSidePanel/errors/useErrorGroups.ts
  • src/components/rightSidePanel/parameters/WidgetItem.vue
  • src/composables/queue/useJobList.test.ts
  • src/composables/queue/useJobList.ts
  • src/composables/useContextMenuTranslation.ts
  • src/i18n.test.ts
  • src/i18n.ts
  • src/platform/missingMedia/components/MissingMediaCard.vue
  • src/platform/missingModel/composables/useMissingModelInteractions.ts
  • src/renderer/extensions/vueNodes/components/NodeHeader.vue
  • src/scripts/app.getNodeDefs.test.ts
  • src/scripts/app.ts
  • src/stores/workspace/favoritedWidgetsStore.ts
  • src/utils/nodeTitleUtil.ts

Comment thread src/scripts/app.ts Outdated
Comment thread src/scripts/app.ts Outdated
Two defects in the resolver wiring, both reported by CodeRabbit on the
previous commit.

translateNodeDef passed `def.display_name || def.name` as the backend
value, so a def whose display_name the backend omits was handed its own
node name as though the backend had supplied it. resolveNodeDefText then
returned that and never consulted the bundled snapshot, which inverts the
documented precedence. Pass the backend value only when there is one, and
resolve the description the same way rather than short-circuiting to ''
when the backend omits it.

`?? {}` only guards null and undefined. A string response survived it,
Object.values spread it into characters, and translateNodeDef then threw
on def.category.split during node registration. Accept only a non-array
object, and tolerate a def with no category.

Tests use genuinely bundled nodes rather than custom-node entries, since
a custom-node entry short-circuits ahead of the path under test and hides
the defect. Verified by mutation: restoring either short-circuit or the
weak guard fails the suite.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@src/scripts/app.getNodeDefs.test.ts`:
- Around line 138-141: Update the test around comfyApp.getNodeDefs() to capture
its resolved node definitions and assert that the definition created by nodeDef
with an undefined category has category equal to an empty string, while
retaining the existing no-throw expectation.

In `@src/scripts/app.ts`:
- Around line 1124-1132: In src/scripts/app.ts lines 1124-1132, update the
getNodeDefs response handling to type-guard every entry and its required text
fields before setBackendNodeText and translateNodeDef, discarding malformed
definitions while retaining valid ones. In src/scripts/app.getNodeDefs.test.ts
lines 103-112, add cases where an otherwise valid object response contains null
or invalid field types and verify those entries are ignored without preventing
valid node registration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bf88c4b3-fb00-45c3-9614-c480900c127a

📥 Commits

Reviewing files that changed from the base of the PR and between 9d01afb and a86aa28.

📒 Files selected for processing (2)
  • src/scripts/app.getNodeDefs.test.ts
  • src/scripts/app.ts

Comment thread src/scripts/app.getNodeDefs.test.ts Outdated
Comment thread src/scripts/app.ts
…ation

The response-level guard accepted an object whose individual entries were
malformed, so `{ Broken: null }` still reached translateNodeDef and threw
on `def.name`, and `{ name: 'X', category: 1 }` threw on `category.split`.
A guard that stops at the envelope implies a safety it does not provide.

Validate each entry, keep the well-formed ones, and narrow the category
read to an actual string. A malformed entry is now dropped rather than
aborting node registration for every node.

Also assert the resolved category value for a def with no category, which
the previous test only checked for absence of a throw.

Verified by mutation: dropping the per-entry filter or widening the
category read back to `?? ''` fails the suite.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously requested changes Aug 3, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@src/scripts/app.ts`:
- Around line 1124-1140: Strengthen the isNodeDef validator in
src/scripts/app.ts:1124-1140 to require the complete ComfyNodeDefV1 structure,
including input, output_name, and python_module, while preserving the existing
missing-category fallback; in src/scripts/app.getNodeDefs.test.ts:146-159, add a
name-only definition fixture and assert getNodeDefs excludes it from the
returned definitions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5f06b299-73f1-4f37-a004-ca49c63c5599

📥 Commits

Reviewing files that changed from the base of the PR and between a86aa28 and deec5f0.

📒 Files selected for processing (2)
  • src/scripts/app.getNodeDefs.test.ts
  • src/scripts/app.ts

Comment thread src/scripts/app.ts
@christian-byrne
christian-byrne dismissed coderabbitai[bot]’s stale review August 4, 2026 00:02

Valid findings from this review were fixed in a86aa28 and deec5f0 (precedence inversion on missing backend text, weak object_info envelope guard, per-entry validation, category assertion). The remaining request, full structural validation of node definitions at the API boundary, is declined with reasoning in the thread: it is not a regression from this PR, and it would reverse the deliberate removal of node-def validation in #1190 and #4038 while risking silently dropping custom nodes whose shape does not match ComfyNodeDefV1 exactly. Dismissing so the PR is not blocked on a scope increase that belongs in its own change.

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

Approving the reworked version.

Landing bigcat88's fix with his permission, on a different mechanism. His diagnosis and the precedence rules in the original Review Focus were correct, and the normalizeI18nKey fix in translateNodeDef was a real bug nobody else had caught: every other nodeDefs.* consumer already normalized, so that one call site was reading keys nothing writes. That is kept.

What changed is where backend text lives. Merging escaped backend strings into the vue-i18n en message tree kept the source language on the message compiler, which is what produced the escaping defect (incomplete for vue-i18n 11 on backslash), put an unvalidated /api/i18n merge on the boot-critical path, and mutated the imported locale JSON with no way to evict. Resolving instead removes all three rather than patching them.

Verified: 53 checks green, 0 failing. Escape behaviour checked against the pinned vue-i18n@11.4.6, and the change is a provable no-op for the existing corpus (0 backslashes across 13 locales, 7905 strings), so a release regeneration is byte-identical. Coverage verified by mutation rather than inspection: dropping the English bypass, the legacy key shape, the eviction, the backslash fix, the per-entry filter, or either precedence short-circuit each fails the suite.

Known gaps are filed rather than hidden: #14629, #14630, #14631.

@christian-byrne
christian-byrne merged commit 91c31b1 into main Aug 4, 2026
75 checks passed
@christian-byrne
christian-byrne deleted the fix/en-node-display-names-from-backend branch August 4, 2026 00:03
@christian-byrne

Copy link
Copy Markdown
Contributor

@bigcat88 thanks for this, and for letting me take it over. Merged as 91c31b1.

Your diagnosis was right and so were the precedence rules you wrote in the Review Focus. The normalizeI18nKey fix in translateNodeDef was a genuine bug nobody else had spotted: every other nodeDefs.* consumer already normalized, so that one call site was reading keys nothing ever writes. That is kept as-is.

What I changed is where the backend text lives, not what it means. Merging escaped backend strings into the vue-i18n en message tree kept English on the message compiler, and three problems followed from that rather than from anything wrong in your logic:

  • The escape helper was incomplete for the pinned vue-i18n 11. Since v11 the compiler reads \ as an escape introducer, so a backslash before an escaped character swallows the brace the escaper emits. C:\@home threw Invalid linked format and rendered as literal escape syntax. It was unreachable before your PR only because the bundled locale contains no backslashes; merging made te() true for every node, so the path became live. The fix is to double the backslash, not to add it to the character set, since {'\'} escapes its own closing quote.
  • mergeLocaleMessage throws on any non-object, and /api/i18n is unvalidated (zCustomNodesI18n is declared but never parsed with). Re-merging it from getNodeDefs() moved that throw onto the boot path, where it aborts node registration instead of being swallowed by bootstrapStore.
  • The merge wrote into the imported en/nodeDefs.json module object and only ever added, so a def that stopped sending display_name kept the old one for the session.

Resolving instead of merging removes all three rather than patching each. Precedence is now declared explicitly per locale, English returns the backend value uncompiled, and non-English is unchanged except that it falls back to the live backend value rather than the stale English snapshot.

One thing your PR flagged that turned out to be half true: the Review Focus said the legacy nested custom-locale shape was unsupported anywhere. Every other consumer had indeed stopped resolving it, but translateNodeDef was the last one that still did, via vue-i18n path traversal, so normalizing alone would have silently broken locales that nest dotted node ids. jtydhr88/ComfyTV ships 167 nodes that way. The resolver now tries both key shapes, so that keeps working.

Follow-ups are filed rather than folded in: #14629, #14630, #14631.

christian-byrne added a commit that referenced this pull request Aug 5, 2026
## Summary

Pin the node display names that Playwright goldens capture, so
screenshots stop tracking whatever ComfyUI build the CI container
happens to ship — and make the failure mode legible when a pinned node
type goes missing.

## Changes

- **What**:
- New `setNodeDisplayName(objectInfo, nodeType, displayName)` mutator in
`browser_tests/fixtures/utils/objectInfo.ts`, alongside
`setStringInputTooltip` / `setComboInputOptions`.
- `imageCompare.spec.ts` pins `ImageCompare` -> `Image Compare`;
`nodeBadge.spec.ts` pins `ImageBatch` -> `Batch Images`.
- Both install the stub by extending the `page` fixture, so the route is
live before `comfyPage.setup()` boots the node-definition store. That is
the same pattern as `propertiesPanel/errorsTabModeAware.spec.ts` and
avoids the extra `reloadAndWaitForApp()` that `widgetTooltip.spec.ts`
needs when routing mid-test.
- **Pre-existing bug fix:** `routeObjectInfoFromSetupApi` only wrapped
the fetch and JSON parse in a `try`. A throwing `customize` callback
rejected the route handler, so `route.fulfill` never ran and the request
hung — the test then died on an opaque Playwright timeout rather than
reporting the cause. The mutators throw precisely when a node type is
missing from `/object_info`, which is what a container bump triggers, so
shipping the pins without this would turn "node was renamed upstream"
into a mystery hang. `customize` is now guarded and fulfills a 500
naming the failure, with the message logged to test output.

No baselines were regenerated. The pinned strings are the ones the
committed PNGs already encode, so the images are byte-identical to
`main`.

## Review Focus

Since #14541, English node titles resolve from the backend
`/object_info` rather than from a bundled file. That makes every golden
containing a node header a function of the CI container image, which is
pinned to `ghcr.io/comfy-org/comfyui-ci-container:0.0.21` (ComfyUI
v0.19.3) in four workflows: `ci-tests-e2e.yaml:57` and `:115`,
`pr-update-playwright-expectations.yaml:84`, `ci-perf-report.yaml:34`.
`0.0.22` (ComfyUI v0.30.0) already exists in the registry, and whoever
bumps the pin currently gets unrelated node-title screenshot diffs with
nothing in-repo explaining them. This makes that bump safe.

The chosen strings are not guesses. #14541 itself re-baselined these
goldens, so they encode the container's names, and the rename is visible
in the diff of that commit: in `image-compare-default-50`, the title
descenders move from `p` at x=60 / `g` at x=112 (bundled `Compare
Images`) to `g` at x=56 / `p` at x=98 (container `Image Compare`).
`Batch Images` is legible directly in `node-lifecycle-*`.

No unit test covers the hang fix: `browser_tests/**` is outside vitest's
`include` globs (`src/`, `packages/`, `scripts/`), and widening them
would sweep the Playwright `.spec.ts` files into `pnpm test:unit`.
Exercising the path for real needs a running ComfyUI backend.

Still coupled to the container, deliberately out of scope here: the
`api-pricing-*` goldens (title `Flux 1.1 [pro] Ultra Image`, from
`FluxProUltraImageNode`) and `node-badge-*` (titles from the
`nodes/execution_error` workflow). Same fix applies if we want them
covered.

Fixes #14630

---------

Co-authored-by: Connor Byrne <c.byrne@comfy.org>
christian-byrne added a commit that referenced this pull request Aug 5, 2026
#14747)

## Summary

Widget labels, socket labels, output names, node descriptions and
tooltips now resolve from the live `/object_info` response instead of
the bundled `en/nodeDefs.json` snapshot, so a backend rename no longer
leaves a new node title beside old widget labels and old tooltips.

## Changes

- **What**: `resolveNodeDefInputText()` / `resolveNodeDefOutputText()`
(`src/i18n.ts`) extend the precedence introduced in #14541 to slot text.
They own all `nodeDefs.*.inputs|outputs.*` key construction and apply
the same per-locale order:

| locale | order |
| ------ |
----------------------------------------------------------------------------------------
|
| `en` | custom-node `/api/i18n` -> backend `/object_info` -> bundled
snapshot -> caller fallback |
| other | custom-node `/api/i18n` -> bundled snapshot -> backend ->
caller fallback |

The existing `resolveNodeDefText` and the new slot resolvers share one
core (`resolveNodeDefPath`), which now takes the message reader as a
parameter — the only behavioural difference between a name and a
tooltip.

- **What**: Call sites moved onto the resolvers:
- `litegraphService.addInputWidget` — `widget.label` and the widget's
socket `localized_name`
  - `litegraphService.addInputSocket` — socket `localized_name`
- `litegraphService.addOutputs` — output `localized_name` (the
`dataTypes.*` branch, used when the output name equals its type, is
unchanged)
  - `NodeTooltip.vue` — input slot, output slot and widget tooltips
  - `useNodeTooltips.ts` — input slot, output slot and widget tooltips

- **What**: `useNodeTooltips.getNodeDescription` no longer re-resolves
the description against the snapshot. `getNodeDefs()` has already
resolved it, so wrapping it in `st()` let the stale bundled value win.

- **Breaking**: None.

## Review Focus

- **The raw/compiled split is the risk in this PR.**
`scripts/nodeDefLocaleSerializer.ts` escapes `name` and leaves `tooltip`
verbatim, because tooltips are read through `stRaw`/`tm()` uncompiled —
an escaped `{'@'}` would render literally to the user.
`slotMessageReader()` is the single place that picks `st` vs `stRaw`,
keyed on the field. Nothing new is escaped at runtime, and no backend
value is merged into the vue-i18n message tree.

- Widget labels previously always came from the snapshot, whose
`inputs.*.name` is the raw input name rather than `display_name` — so a
backend `display_name` on an input was never shown. It now is. Where the
backend sends no `display_name` the snapshot still applies, which is the
existing behaviour.

- Tests are verified by mutation, not by inspection, because `st()`
swallows a vue-i18n `SyntaxError` and falls back to the raw stored
message — a fixture with a throwing character passes either way. The
`raw / compiled split` fixture uses `50{'%'} {'@'}`, which compiles
cleanly, so `name` -> `50% @` and `tooltip` -> `50{'%'} {'@'}` genuinely
diverge. Forcing either reader in both directions fails that test;
dropping the `en` backend bypass, the custom-node precedence, or the
backend fallback each fails a distinct test; passing `undefined` for the
backend value at each of the seven call sites fails the test covering
it.

Fixes #14631

Co-authored-by: Connor Byrne <c.byrne@comfy.org>
christian-byrne added a commit that referenced this pull request Aug 5, 2026
…4773)

## Summary

`ComfyApp.getNodeDefs()` discards `/object_info` entries that are not
objects with a string `name`, so a single malformed def cannot abort
node registration for every node. It did so silently, which makes a node
vanishing from the UI undiagnosable.

Warn once per fetch, naming the discarded keys.

## Why this shape

This is the decision half of #14644, which asks whether node definitions
should be structurally validated at the API boundary and what should
happen to ones that fail.

Validation was removed deliberately: #1190 disabled it by default and
#4038 removed it outright along with its setting. `/object_info` carries
definitions from arbitrary custom nodes whose shapes vary in ways
`ComfyNodeDefV1` does not fully capture, so tightening the contract
risks silently dropping a node the user installed and expects to see.
That posture is kept here.

What was actually wrong was not the permissiveness, it was the silence.
Naming the dropped keys keeps the permissive behaviour while making the
data loss visible, and it is the cheapest way to learn whether real
payloads ever reach this path. If telemetry later shows they do, #14644
can be decided with evidence rather than speculation.

- **Breaking**: none. Same defs are dropped as before; only the logging
changes.

## Review Focus

Verified by mutation: removing the warning fails the suite. A second
test pins that a well-formed response stays silent, so the warning
cannot become unconditional noise.

Related: #14644, #14541

---------

Co-authored-by: Connor Byrne <c.byrne@comfy.org>
christian-byrne added a commit that referenced this pull request Aug 5, 2026
## Summary

Finishes what #14744 started: the last two node-title goldens that still
track the CI container image are now pinned. No baselines regenerated.

## Changes

`browser_tests/tests/nodeBadge.spec.ts` already extended the `page`
fixture to stub `/object_info` for `ImageBatch`. That map now also
carries:

| golden | node type | pinned title |
| --- | --- | --- |
| `api-pricing-{on,off}-{classic,vue}` | `FluxProUltraImageNode` | `Flux
1.1 [pro] Ultra Image` |
| `node-badge-{Show-all,Hide-built-in,None}` | `PreviewImage` | `Preview
Image` |

The route shape, the `try`/`finally` unroute and the pre-boot install
are unchanged — only the mutator body generalises to a loop.

`nodes/execution_error` also renders `DevToolsErrorRaiseNode` (`Raise
Error`), which is **deliberately not pinned**. That name is defined in
this repo at `tools/devtools/nodes/errors.py:76` and copied into
`custom_nodes` during CI, so it is not a function of the container
image. Pinning it would mask a deliberate in-repo rename.

## Review Focus

**Motivation.** Since #14541 English node display names resolve from the
backend `/object_info`, so every golden containing a node header is a
function of `ghcr.io/comfy-org/comfyui-ci-container`. #14682 moves that
pin from `0.0.21` (ComfyUI v0.19.3) to `0.0.22` (v0.30.0) — eleven
minors. The goal is that after this lands, a node-title golden that
moves on that bump means a real structural change, not an upstream
rename.

**How the strings were established.** Both are read off the committed
PNGs, not guessed:

- `Flux 1.1 [pro] Ultra Image` is legible in the title band of
`api-pricing-on-classic` and `api-pricing-on-vue`, and matches
`src/locales/en/nodeDefs.json`.
- `Preview Image` is legible in the title band of all three
`node-badge-*` goldens, likewise matching the bundled snapshot.

Two independent corroborations that these strings hold on both sides of
the bump:

1. #14541 re-baselined only `image-compare-*` and `node-lifecycle-*`. It
left `api-pricing-*` and `node-badge-*` byte-identical, so at `0.0.21`
the container name already equalled the bundled name.
2. Diffing every golden #14682 regenerates against its committed
counterpart, the changed pixels in `node-badge-*` sit at x 454–509 / y
69–81 — an `images` output slot appearing on `PreviewImage`. The title
band is byte-identical, and `api-pricing-*` is not regenerated at all.
So neither title moves at `0.0.22` either.

**Sweep.** All 26 goldens #14682 regenerates were diffed old-vs-new and
classified. **None move because of a node display name:**

| cause | goldens |
| --- | --- |
| `SaveImage`/`PreviewImage` gained an `images` output | `colorPalette`
×9, `node-badge-*` ×3, `loadWorkflowInMedia` ×4,
`save-image-and-webm-preview`, `lod-comparison-high-quality` |
| `control after generate` default `randomize` -> `fixed` |
`static-primitive-connected` |
| 3D render differences | `load3d-*` ×3 |
| sub-5px antialiasing | `interaction` ×3, `lod-comparison-low-quality`
|

So there is no evidence-backed third site. The remaining exposure is the
default-workflow titles (`KSampler`, `CLIP Text Encode (Prompt)`, `Load
Checkpoint`, `Save Image`, …), which appear across roughly 37 spec files
and 257 goldens. Pinning those would touch most of the screenshot suite
for a rename that has not happened, so it is left out; the fixture
pattern applies unchanged if one ever does.

## Testing

`typecheck`, `lint`, `format`, `knip` pass locally. The stub itself
needs a running ComfyUI backend, so CI is the verifier — the proof is
that the `nodeBadge` and `imageCompare` screenshot tests stay green with
the goldens unmodified, which also exercises the route-install ordering.

Related: #14630 (closed by #14744; this is the follow-through)

Co-authored-by: Connor Byrne <c.byrne@comfy.org>
christian-byrne added a commit that referenced this pull request Aug 5, 2026
Reverts five PRs that were merged to `main` without independent review,
which is not our process. Backing them out so they can go through review
properly.

Reverted, newest first:

- #14775 — resolve
display name and description at read time
- #14774 — pin
remaining container-coupled node titles
- #14773 — warn on
dropped malformed node defs
- #14747 — widget
labels, output names and tooltips from the backend
- #14744 — decouple
node-title goldens from the CI container

**Not reverted:**
#14541. It was
authored by @bigcat88 and carried a genuine approval before merge, so it
followed process. The five above were authored and merged under the same
account, and GitHub blocks self-approval, so none of them could receive
one. Three had no approval of any kind at merge time.

`main` is not branch-protected here, so nothing blocked the merges. That
is the gap that let this happen.

## State after this revert

All five reverts applied without conflict. The tree returns to the
post-14541 state:
`resolveNodeDefText` and `setBackendNodeText` remain, `translateNodeDef`
resolves
`display_name`/`description` inline again, and the slot resolvers,
getters, dropped-def
warning and golden stubbing are all removed.

Verified locally: `pnpm typecheck` clean, `pnpm knip` clean, 156 unit
tests pass across
the four affected suites.

## Follow-up

Each reverted change will be re-opened as its own PR from its original
branch, which
still exists, for normal review. Nothing is lost.

---------

Co-authored-by: Connor Byrne <c.byrne@comfy.org>
christian-byrne added a commit that referenced this pull request Aug 19, 2026
#14797)

#14541 made English
`display_name` and `description` come from the backend. Widget labels,
output names and tooltips were still read from the stale bundled
snapshot, so a renamed node showed a new title beside old labels.

Adds `resolveNodeDefInputText` / `resolveNodeDefOutputText` and extracts
`resolveNodeDefPath`, so the per-locale precedence table now lives in
exactly one place and `resolveNodeDefText` delegates to it. Applied in
`litegraphService` (widget labels, socket and output `localized_name`),
`NodeTooltip.vue`, and `useNodeTooltips.ts`. Also fixes
`getNodeDescription`, which wrapped an already-resolved value in `st()`
and let the stale bundle win.

## Review focus

**Tooltips must never be escaped or compiled.** They are read through
`stRaw`/`tm()`, which returns the message uncompiled, so a literal
`{'@'}` would render to the user. One function decides it:

```ts
return field === 'tooltip' ? stRaw : st
```

Backend values short-circuit before any reader runs, so a tooltip
reaches the compiler by no path. No runtime escaping added;
`escapeI18nMessage` stays build-time-only.

Coverage was verified by mutation rather than inspection, which matters
here: `st()` swallows a vue-i18n `SyntaxError` and returns the raw
stored message, so a fixture containing a throwing character passes
whether or not the code is correct. The raw/compiled fixture (`50{'%'}
{'@'}`) compiles cleanly so that escape hatch cannot mask a defect.
Forcing the reader to always-`st` or always-`stRaw` each fails the
suite.

## Migration guidance (`node.widgets`)

`widget.label` now resolves through the node-def text pipeline
(custom-node translations, then the live backend value, then the bundled
snapshot) instead of taking the node definition's `display_name`
verbatim. The resolved string therefore varies by active locale and by
what `/object_info` sends.

Extensions must use `widget.name` for widget identity. `widget.label` is
display text and was never stable across locales. No type or API shape
changed.

Fixes #14631

---
Previously merged without review and backed out by
#14791. Re-submitting
for normal review. Rebased onto post-revert `main`; content unchanged.

---------

Co-authored-by: Connor Byrne <c.byrne@comfy.org>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: DrJKL <DrJKL0424@gmail.com>
comfydesigner pushed a commit that referenced this pull request Aug 20, 2026
#14797)

#14541 made English
`display_name` and `description` come from the backend. Widget labels,
output names and tooltips were still read from the stale bundled
snapshot, so a renamed node showed a new title beside old labels.

Adds `resolveNodeDefInputText` / `resolveNodeDefOutputText` and extracts
`resolveNodeDefPath`, so the per-locale precedence table now lives in
exactly one place and `resolveNodeDefText` delegates to it. Applied in
`litegraphService` (widget labels, socket and output `localized_name`),
`NodeTooltip.vue`, and `useNodeTooltips.ts`. Also fixes
`getNodeDescription`, which wrapped an already-resolved value in `st()`
and let the stale bundle win.

## Review focus

**Tooltips must never be escaped or compiled.** They are read through
`stRaw`/`tm()`, which returns the message uncompiled, so a literal
`{'@'}` would render to the user. One function decides it:

```ts
return field === 'tooltip' ? stRaw : st
```

Backend values short-circuit before any reader runs, so a tooltip
reaches the compiler by no path. No runtime escaping added;
`escapeI18nMessage` stays build-time-only.

Coverage was verified by mutation rather than inspection, which matters
here: `st()` swallows a vue-i18n `SyntaxError` and returns the raw
stored message, so a fixture containing a throwing character passes
whether or not the code is correct. The raw/compiled fixture (`50{'%'}
{'@'}`) compiles cleanly so that escape hatch cannot mask a defect.
Forcing the reader to always-`st` or always-`stRaw` each fails the
suite.

## Migration guidance (`node.widgets`)

`widget.label` now resolves through the node-def text pipeline
(custom-node translations, then the live backend value, then the bundled
snapshot) instead of taking the node definition's `display_name`
verbatim. The resolved string therefore varies by active locale and by
what `/object_info` sends.

Extensions must use `widget.name` for widget identity. `widget.label` is
display text and was never stable across locales. No type or API shape
changed.

Fixes #14631

---
Previously merged without review and backed out by
#14791. Re-submitting
for normal review. Rebased onto post-revert `main`; content unchanged.

---------

Co-authored-by: Connor Byrne <c.byrne@comfy.org>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: DrJKL <DrJKL0424@gmail.com>
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.

2 participants