Skip to content

test: Add test to prevent regression of workflow corruption during graph loading#10623

Merged
pythongosssss merged 1 commit intomainfrom
pysssss/test/switching-tab-regression-test
Mar 27, 2026
Merged

test: Add test to prevent regression of workflow corruption during graph loading#10623
pythongosssss merged 1 commit intomainfrom
pysssss/test/switching-tab-regression-test

Conversation

@pythongosssss
Copy link
Copy Markdown
Member

@pythongosssss pythongosssss commented Mar 27, 2026

Summary

Adds regression test for #9531

Changes

  • What:
  • registers extension that triggers checkState during afterConfigureGraph (at this point the workflow data and active graph are not in sync), previously causing it to overwrite the workflow data
  • switches between tabs
  • ensures they are not corrupted

Line 35 can be uncommented to cause the test to fail by clearing the isLoadingGraph flag

┆Issue is synchronized with this Notion page by Unito

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

📝 Walkthrough

Walkthrough

A new Playwright browser test file is added to validate the "Change Tracker - isLoadingGraph guard" behavior. The test suite verifies that workflow state remains correct when switching between tabs while a graph is loading.

Changes

Cohort / File(s) Summary
Browser Test - Change Tracker Guard
browser_tests/tests/changeTrackerLoadGuard.spec.ts
New test file (66 lines) that validates change tracker state preservation during graph loading by programmatically registering an extension with afterConfigureGraph callback, performing tab switches between workflows, and asserting correct node counts (7 for existing workflow, 0 for blank) to ensure state integrity.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A test that guards the tracker's flow,
Through tabs and graphs it swiftly goes,
Seven nodes and none stay pure,
State preserved, forever sure!
The loadGuard stands with whisker'd might. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete and does not follow the provided template structure. It is missing critical sections including a proper 'What' explanation and the required 'Review Focus' section. Complete the PR description by filling in the 'What' section with details about the test implementation and adding a 'Review Focus' section explaining critical aspects of the regression test.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding a regression test to prevent workflow corruption during graph loading, which directly matches the PR's purpose.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
End-To-End Regression Coverage For Fixes ✅ Passed PR satisfies the check by adding a Playwright regression test under browser_tests/tests/changeTrackerLoadGuard.spec.ts that validates workflow state integrity during graph loading.
Adr Compliance For Entity/Litegraph Changes ✅ Passed The ADR compliance check does not apply because the modified file is outside the scope defined in the check instructions.

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

✨ 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 pysssss/test/switching-tab-regression-test

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 and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 27, 2026

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 03/27/2026, 05:16:00 PM UTC

Links

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 27, 2026

🎭 Playwright: ✅ 719 passed, 0 failed · 4 flaky

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

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 27, 2026

📦 Bundle: 5.09 MB gzip 🟢 -68 B

Details

Summary

  • Raw size: 23.4 MB baseline 23.4 MB — ⚪ 0 B
  • Gzip: 5.09 MB baseline 5.09 MB — 🟢 -68 B
  • Brotli: 3.94 MB baseline 3.94 MB — 🟢 -47 B
  • Bundles: 249 current • 249 baseline • 114 added / 114 removed

Category Glance
Vendor & Third-Party ⚪ 0 B (9.8 MB) · Other ⚪ 0 B (8.42 MB) · Data & Services ⚪ 0 B (2.96 MB) · Graph Workspace ⚪ 0 B (1.14 MB) · Panels & Settings ⚪ 0 B (484 kB) · Utilities & Hooks ⚪ 0 B (334 kB) · + 5 more

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

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-BBMecLiX.js (removed) 22.3 kB 🟢 -22.3 kB 🟢 -7.93 kB 🟢 -6.8 kB
assets/index-DQBxhJtX.js (new) 22.3 kB 🔴 +22.3 kB 🔴 +7.93 kB 🔴 +6.81 kB

Status: 1 added / 1 removed

Graph Workspace — 1.14 MB (baseline 1.14 MB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-CdDdy3cB.js (new) 1.14 MB 🔴 +1.14 MB 🔴 +243 kB 🔴 +183 kB
assets/GraphView-rZAUZOOh.js (removed) 1.14 MB 🟢 -1.14 MB 🟢 -243 kB 🟢 -183 kB

Status: 1 added / 1 removed

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

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-Bx_Vvalg.js (removed) 15.7 kB 🟢 -15.7 kB 🟢 -3.4 kB 🟢 -2.9 kB
assets/CloudSurveyView-C4zYQm1V.js (new) 15.7 kB 🔴 +15.7 kB 🔴 +3.4 kB 🔴 +2.9 kB
assets/CloudLoginView-B5Yi8iRQ.js (new) 12 kB 🔴 +12 kB 🔴 +3.35 kB 🔴 +2.96 kB
assets/CloudLoginView-BSdHgIL7.js (removed) 12 kB 🟢 -12 kB 🟢 -3.36 kB 🟢 -2.96 kB
assets/CloudSignupView-C-ugVNre.js (removed) 9.78 kB 🟢 -9.78 kB 🟢 -2.85 kB 🟢 -2.49 kB
assets/CloudSignupView-CjT1dsf9.js (new) 9.78 kB 🔴 +9.78 kB 🔴 +2.85 kB 🔴 +2.5 kB
assets/UserCheckView-BAs8WSZj.js (new) 9.04 kB 🔴 +9.04 kB 🔴 +2.33 kB 🔴 +2.03 kB
assets/UserCheckView-DDudWPfN.js (removed) 9.04 kB 🟢 -9.04 kB 🟢 -2.33 kB 🟢 -2.03 kB
assets/CloudLayoutView-B8abSX3_.js (removed) 7.54 kB 🟢 -7.54 kB 🟢 -2.36 kB 🟢 -2.04 kB
assets/CloudLayoutView-CWpQxiI9.js (new) 7.54 kB 🔴 +7.54 kB 🔴 +2.36 kB 🔴 +2.04 kB
assets/CloudForgotPasswordView-DF6T7BV0.js (removed) 5.94 kB 🟢 -5.94 kB 🟢 -2.09 kB 🟢 -1.83 kB
assets/CloudForgotPasswordView-DY9xRGcX.js (new) 5.94 kB 🔴 +5.94 kB 🔴 +2.09 kB 🔴 +1.85 kB
assets/CloudAuthTimeoutView-BACxqnVA.js (new) 5.31 kB 🔴 +5.31 kB 🔴 +1.93 kB 🔴 +1.69 kB
assets/CloudAuthTimeoutView-BnVHlHjR.js (removed) 5.31 kB 🟢 -5.31 kB 🟢 -1.93 kB 🟢 -1.69 kB
assets/CloudSubscriptionRedirectView-C3IUFus_.js (new) 5.08 kB 🔴 +5.08 kB 🔴 +1.91 kB 🔴 +1.68 kB
assets/CloudSubscriptionRedirectView-Y3ehhHvo.js (removed) 5.08 kB 🟢 -5.08 kB 🟢 -1.91 kB 🟢 -1.69 kB
assets/UserSelectView-BrEnc6oP.js (removed) 4.71 kB 🟢 -4.71 kB 🟢 -1.74 kB 🟢 -1.54 kB
assets/UserSelectView-wIFwEDLS.js (new) 4.71 kB 🔴 +4.71 kB 🔴 +1.74 kB 🔴 +1.54 kB

Status: 9 added / 9 removed / 2 unchanged

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

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/KeybindingPanel-DgF4q_Bz.js (removed) 46.6 kB 🟢 -46.6 kB 🟢 -9.52 kB 🟢 -8.47 kB
assets/KeybindingPanel-pxsJHPl-.js (new) 46.6 kB 🔴 +46.6 kB 🔴 +9.52 kB 🔴 +8.47 kB
assets/SecretsPanel-CK1oLx8w.js (new) 22.4 kB 🔴 +22.4 kB 🔴 +5.42 kB 🔴 +4.76 kB
assets/SecretsPanel-CKs6ssYT.js (removed) 22.4 kB 🟢 -22.4 kB 🟢 -5.42 kB 🟢 -4.76 kB
assets/LegacyCreditsPanel-BRJcPFO1.js (new) 21.5 kB 🔴 +21.5 kB 🔴 +5.81 kB 🔴 +5.14 kB
assets/LegacyCreditsPanel-C5QvePWI.js (removed) 21.5 kB 🟢 -21.5 kB 🟢 -5.81 kB 🟢 -5.12 kB
assets/SubscriptionPanel-Bnnss647.js (new) 19.6 kB 🔴 +19.6 kB 🔴 +4.98 kB 🔴 +4.39 kB
assets/SubscriptionPanel-DYobEly9.js (removed) 19.6 kB 🟢 -19.6 kB 🟢 -4.99 kB 🟢 -4.37 kB
assets/AboutPanel-C5AeRRm-.js (new) 12 kB 🔴 +12 kB 🔴 +3.32 kB 🔴 +2.98 kB
assets/AboutPanel-CmqE1Lk3.js (removed) 12 kB 🟢 -12 kB 🟢 -3.33 kB 🟢 -2.99 kB
assets/ExtensionPanel-BC3p_Z-5.js (new) 9.78 kB 🔴 +9.78 kB 🔴 +2.82 kB 🔴 +2.51 kB
assets/ExtensionPanel-PIN8MU0A.js (removed) 9.78 kB 🟢 -9.78 kB 🟢 -2.82 kB 🟢 -2.52 kB
assets/ServerConfigPanel-DQKc0o_d.js (removed) 6.85 kB 🟢 -6.85 kB 🟢 -2.27 kB 🟢 -2.03 kB
assets/ServerConfigPanel-ISjnojnz.js (new) 6.85 kB 🔴 +6.85 kB 🔴 +2.27 kB 🔴 +2.03 kB
assets/UserPanel-B2z93Xda.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -2.15 kB 🟢 -1.88 kB
assets/UserPanel-cgSn2bel.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +2.15 kB 🔴 +1.88 kB
assets/cloudRemoteConfig-C-rANOtn.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -901 B 🟢 -789 B
assets/cloudRemoteConfig-DlzHG5-0.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +900 B 🔴 +795 B
assets/refreshRemoteConfig-DLS7X2dP.js (removed) 1.45 kB 🟢 -1.45 kB 🟢 -650 B 🟢 -549 B
assets/refreshRemoteConfig-YC_if7Dt.js (new) 1.45 kB 🔴 +1.45 kB 🔴 +647 B 🔴 +551 B

Status: 10 added / 10 removed / 12 unchanged

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

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-BT4_3wdh.js (new) 3.57 kB 🔴 +3.57 kB 🔴 +1.26 kB 🔴 +1.07 kB
assets/auth-Lm4uvXbK.js (removed) 3.57 kB 🟢 -3.57 kB 🟢 -1.26 kB 🟢 -1.08 kB
assets/SignUpForm-ChsSdltV.js (new) 3.16 kB 🔴 +3.16 kB 🔴 +1.29 kB 🔴 +1.14 kB
assets/SignUpForm-uofh4Llc.js (removed) 3.16 kB 🟢 -3.16 kB 🟢 -1.29 kB 🟢 -1.14 kB
assets/UpdatePasswordContent-ByL2Omc9.js (new) 2.66 kB 🔴 +2.66 kB 🔴 +1.19 kB 🔴 +1.06 kB
assets/UpdatePasswordContent-C7hSw5pJ.js (removed) 2.66 kB 🟢 -2.66 kB 🟢 -1.19 kB 🟢 -1.05 kB
assets/authStore-C5GOA7Ck.js (removed) 989 B 🟢 -989 B 🟢 -481 B 🟢 -424 B
assets/authStore-DFOJJEdZ.js (new) 989 B 🔴 +989 B 🔴 +478 B 🔴 +426 B
assets/auth-BdAVEsbA.js (removed) 348 B 🟢 -348 B 🟢 -218 B 🟢 -194 B
assets/auth-DExTgc7f.js (new) 348 B 🔴 +348 B 🔴 +217 B 🔴 +194 B

Status: 5 added / 5 removed / 2 unchanged

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

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useShareDialog-DEdMz9MU.js (new) 108 kB 🔴 +108 kB 🔴 +22.3 kB 🔴 +18.8 kB
assets/useShareDialog-DkxrOlbg.js (removed) 108 kB 🟢 -108 kB 🟢 -22.3 kB 🟢 -18.8 kB
assets/useSubscriptionDialog-DGRSpXsY.js (removed) 969 B 🟢 -969 B 🟢 -475 B 🟢 -415 B
assets/useSubscriptionDialog-yViVOcJC.js (new) 969 B 🔴 +969 B 🔴 +473 B 🔴 +412 B

Status: 2 added / 2 removed

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-c59bK4iF.js (new) 14.3 kB 🔴 +14.3 kB 🔴 +4.01 kB 🔴 +3.58 kB
assets/ComfyQueueButton-dUfxiOWC.js (removed) 14.3 kB 🟢 -14.3 kB 🟢 -4.01 kB 🟢 -3.58 kB
assets/useTerminalTabs-C0w2IqCD.js (removed) 10.7 kB 🟢 -10.7 kB 🟢 -3.6 kB 🟢 -3.16 kB
assets/useTerminalTabs-DPiuocLV.js (new) 10.7 kB 🔴 +10.7 kB 🔴 +3.6 kB 🔴 +3.17 kB
assets/SubscribeButton-BlvVmH-_.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.04 kB 🔴 +914 B
assets/SubscribeButton-C5gd3kg_.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.04 kB 🟢 -914 B
assets/cloudFeedbackTopbarButton-B7vfOIZG.js (new) 1.66 kB 🔴 +1.66 kB 🔴 +841 B 🔴 +756 B
assets/cloudFeedbackTopbarButton-CtZdAdHg.js (removed) 1.66 kB 🟢 -1.66 kB 🟢 -842 B 🟢 -746 B
assets/ComfyQueueButton-BAWOTebj.js (removed) 1.03 kB 🟢 -1.03 kB 🟢 -488 B 🟢 -436 B
assets/ComfyQueueButton-BLCYSd-D.js (new) 1.03 kB 🔴 +1.03 kB 🔴 +487 B 🔴 +436 B

Status: 5 added / 5 removed / 8 unchanged

Data & Services — 2.96 MB (baseline 2.96 MB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-D34ZO_8W.js (removed) 1.92 MB 🟢 -1.92 MB 🟢 -443 kB 🟢 -336 kB
assets/dialogService-D8Kyz0pP.js (new) 1.92 MB 🔴 +1.92 MB 🔴 +443 kB 🔴 +336 kB
assets/api-C_kOjXYW.js (removed) 884 kB 🟢 -884 kB 🟢 -211 kB 🟢 -166 kB
assets/api-CdSOfQba.js (new) 884 kB 🔴 +884 kB 🔴 +211 kB 🔴 +166 kB
assets/load3dService-BPRBcbm7.js (new) 92.5 kB 🔴 +92.5 kB 🔴 +19.7 kB 🔴 +16.9 kB
assets/load3dService-Dhvzo2OY.js (removed) 92.5 kB 🟢 -92.5 kB 🟢 -19.7 kB 🟢 -16.9 kB
assets/workflowShareService-BFJ7dZ-r.js (removed) 16.4 kB 🟢 -16.4 kB 🟢 -4.82 kB 🟢 -4.27 kB
assets/workflowShareService-DeFMLP_V.js (new) 16.4 kB 🔴 +16.4 kB 🔴 +4.82 kB 🔴 +4.27 kB
assets/keybindingService-B7Lt9i61.js (removed) 13.8 kB 🟢 -13.8 kB 🟢 -3.66 kB 🟢 -3.21 kB
assets/keybindingService-CiF2LSOT.js (new) 13.8 kB 🔴 +13.8 kB 🔴 +3.67 kB 🔴 +3.21 kB
assets/releaseStore-BR2OLZXO.js (removed) 8.12 kB 🟢 -8.12 kB 🟢 -2.28 kB 🟢 -2 kB
assets/releaseStore-Cm3M10l3.js (new) 8.12 kB 🔴 +8.12 kB 🔴 +2.28 kB 🔴 +2 kB
assets/userStore-DmYrTNlp.js (new) 2.24 kB 🔴 +2.24 kB 🔴 +866 B 🔴 +760 B
assets/userStore-Dz7PcUkV.js (removed) 2.24 kB 🟢 -2.24 kB 🟢 -872 B 🟢 -762 B
assets/audioService-Csnb8EHe.js (removed) 1.8 kB 🟢 -1.8 kB 🟢 -879 B 🟢 -759 B
assets/audioService-PmlJV8pu.js (new) 1.8 kB 🔴 +1.8 kB 🔴 +877 B 🔴 +758 B
assets/releaseStore--K-kMBqv.js (new) 993 B 🔴 +993 B 🔴 +478 B 🔴 +423 B
assets/releaseStore-DZHDmfr1.js (removed) 993 B 🟢 -993 B 🟢 -480 B 🟢 -427 B
assets/workflowDraftStore-D8UdrnWF.js (new) 969 B 🔴 +969 B 🔴 +472 B 🔴 +418 B
assets/workflowDraftStore-DvX6j-Pm.js (removed) 969 B 🟢 -969 B 🟢 -474 B 🟢 -417 B
assets/dialogService-B9JoVnoF.js (removed) 958 B 🟢 -958 B 🟢 -466 B 🟢 -413 B
assets/dialogService-DPpcWHs1.js (new) 958 B 🔴 +958 B 🔴 +465 B 🔴 +412 B
assets/settingStore-BtWmV2VK.js (removed) 956 B 🟢 -956 B 🟢 -470 B 🟢 -413 B
assets/settingStore-D5QyxdC5.js (new) 956 B 🔴 +956 B 🔴 +467 B 🔴 +411 B
assets/assetsStore-C4RANuzW.js (removed) 955 B 🟢 -955 B 🟢 -469 B 🟢 -412 B
assets/assetsStore-D1hnzWjF.js (new) 955 B 🔴 +955 B 🔴 +467 B 🔴 +412 B

Status: 13 added / 13 removed / 4 unchanged

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

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useConflictDetection-DfJ46Cx_.js (new) 232 kB 🔴 +232 kB 🔴 +51.3 kB 🔴 +41.7 kB
assets/useConflictDetection-DKV9ArPJ.js (removed) 232 kB 🟢 -232 kB 🟢 -51.3 kB 🟢 -41.8 kB
assets/useLoad3dViewer-BvA6QGlr.js (removed) 18.7 kB 🟢 -18.7 kB 🟢 -4.44 kB 🟢 -3.88 kB
assets/useLoad3dViewer-HrlHNGCQ.js (new) 18.7 kB 🔴 +18.7 kB 🔴 +4.44 kB 🔴 +3.88 kB
assets/useLoad3d-BwsRon-f.js (removed) 15 kB 🟢 -15 kB 🟢 -3.79 kB 🟢 -3.35 kB
assets/useLoad3d-CKTdu52N.js (new) 15 kB 🔴 +15 kB 🔴 +3.79 kB 🔴 +3.35 kB
assets/useFeatureFlags-Cmjoioqb.js (new) 5.78 kB 🔴 +5.78 kB 🔴 +1.75 kB 🔴 +1.48 kB
assets/useFeatureFlags-DxhjrXnT.js (removed) 5.78 kB 🟢 -5.78 kB 🟢 -1.75 kB 🟢 -1.48 kB
assets/useCopyToClipboard-C7G-wI2n.js (new) 5.29 kB 🔴 +5.29 kB 🔴 +1.86 kB 🔴 +1.57 kB
assets/useCopyToClipboard-D4mxOpO6.js (removed) 5.29 kB 🟢 -5.29 kB 🟢 -1.86 kB 🟢 -1.58 kB
assets/useWorkspaceUI-9kyP6-hv.js (removed) 3.34 kB 🟢 -3.34 kB 🟢 -982 B 🟢 -810 B
assets/useWorkspaceUI-DpdeL5mI.js (new) 3.34 kB 🔴 +3.34 kB 🔴 +980 B 🔴 +812 B
assets/subscriptionCheckoutUtil-BNuNzCBL.js (removed) 2.97 kB 🟢 -2.97 kB 🟢 -1.31 kB 🟢 -1.14 kB
assets/subscriptionCheckoutUtil-D_rUWWTk.js (new) 2.97 kB 🔴 +2.97 kB 🔴 +1.31 kB 🔴 +1.15 kB
assets/assetPreviewUtil-9GxwfOnr.js (new) 2.27 kB 🔴 +2.27 kB 🔴 +959 B 🔴 +833 B
assets/assetPreviewUtil-DnUrd-aW.js (removed) 2.27 kB 🟢 -2.27 kB 🟢 -957 B 🟢 -829 B
assets/useUpstreamValue-C8topgdh.js (removed) 2.08 kB 🟢 -2.08 kB 🟢 -804 B 🟢 -709 B
assets/useUpstreamValue-HVVRrEoJ.js (new) 2.08 kB 🔴 +2.08 kB 🔴 +804 B 🔴 +717 B
assets/useLoad3d-C5UF26JX.js (removed) 1.13 kB 🟢 -1.13 kB 🟢 -534 B 🟢 -475 B
assets/useLoad3d-Doyg5Olq.js (new) 1.13 kB 🔴 +1.13 kB 🔴 +536 B 🔴 +476 B
assets/useLoad3dViewer-BHlvdqfN.js (new) 1.07 kB 🔴 +1.07 kB 🔴 +504 B 🔴 +451 B
assets/useLoad3dViewer-DSAECjC9.js (removed) 1.07 kB 🟢 -1.07 kB 🟢 -503 B 🟢 -450 B
assets/useCurrentUser-B0ZZPTeJ.js (new) 955 B 🔴 +955 B 🔴 +467 B 🔴 +411 B
assets/useCurrentUser-fWQgemni.js (removed) 955 B 🟢 -955 B 🟢 -470 B 🟢 -411 B
assets/useWorkspaceSwitch-B7p1uR6I.js (removed) 747 B 🟢 -747 B 🟢 -388 B 🟢 -335 B
assets/useWorkspaceSwitch-WK07Xm_n.js (new) 747 B 🔴 +747 B 🔴 +389 B 🔴 +333 B

Status: 13 added / 13 removed / 12 unchanged

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

External libraries and shared vendor chunks

Status: 16 unchanged

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

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-BgdWET9_.js (removed) 76.8 kB 🟢 -76.8 kB 🟢 -19.9 kB 🟢 -16.9 kB
assets/core-DzzUYgyc.js (new) 76.8 kB 🔴 +76.8 kB 🔴 +19.9 kB 🔴 +17 kB
assets/groupNode-DuQysEwf.js (new) 74 kB 🔴 +74 kB 🔴 +18.5 kB 🔴 +16.3 kB
assets/groupNode-wq11O1qD.js (removed) 74 kB 🟢 -74 kB 🟢 -18.5 kB 🟢 -16.3 kB
assets/WidgetSelect-BJtMF8gu.js (removed) 64.6 kB 🟢 -64.6 kB 🟢 -14.1 kB 🟢 -12.2 kB
assets/WidgetSelect-TUofnfO0.js (new) 64.6 kB 🔴 +64.6 kB 🔴 +14.1 kB 🔴 +12.1 kB
assets/SubscriptionRequiredDialogContentWorkspace-C8wNirA5.js (removed) 48.9 kB 🟢 -48.9 kB 🟢 -9.29 kB 🟢 -7.96 kB
assets/SubscriptionRequiredDialogContentWorkspace-dyi2E0dB.js (new) 48.9 kB 🔴 +48.9 kB 🔴 +9.29 kB 🔴 +7.93 kB
assets/WidgetPainter-C-qjViSX.js (new) 33.3 kB 🔴 +33.3 kB 🔴 +8.11 kB 🔴 +7.19 kB
assets/WidgetPainter-FS2fvC9m.js (removed) 33.3 kB 🟢 -33.3 kB 🟢 -8.11 kB 🟢 -7.22 kB
assets/Load3DControls-CiLZHJVH.js (removed) 32.1 kB 🟢 -32.1 kB 🟢 -5.47 kB 🟢 -4.75 kB
assets/Load3DControls-nllFVAgT.js (new) 32.1 kB 🔴 +32.1 kB 🔴 +5.47 kB 🔴 +4.77 kB
assets/WorkspacePanelContent-2QKUMMFY.js (removed) 29.9 kB 🟢 -29.9 kB 🟢 -6.33 kB 🟢 -5.57 kB
assets/WorkspacePanelContent-B5PUud4_.js (new) 29.9 kB 🔴 +29.9 kB 🔴 +6.33 kB 🔴 +5.55 kB
assets/SubscriptionRequiredDialogContent-B0lceDwK.js (removed) 28.2 kB 🟢 -28.2 kB 🟢 -7.17 kB 🟢 -6.33 kB
assets/SubscriptionRequiredDialogContent-Z1NpJ4_0.js (new) 28.2 kB 🔴 +28.2 kB 🔴 +7.16 kB 🔴 +6.3 kB
assets/Load3dViewerContent-CovJmqgb.js (new) 24.3 kB 🔴 +24.3 kB 🔴 +5.33 kB 🔴 +4.63 kB
assets/Load3dViewerContent-Dh8lav04.js (removed) 24.3 kB 🟢 -24.3 kB 🟢 -5.32 kB 🟢 -4.63 kB
assets/WidgetImageCrop-BXIabg1t.js (removed) 23.3 kB 🟢 -23.3 kB 🟢 -5.82 kB 🟢 -5.13 kB
assets/WidgetImageCrop-CTCEXoso.js (new) 23.3 kB 🔴 +23.3 kB 🔴 +5.82 kB 🔴 +5.13 kB
assets/SubscriptionPanelContentWorkspace-Bt1NWPi_.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +5.18 kB 🔴 +4.55 kB
assets/SubscriptionPanelContentWorkspace-CMJglmFu.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -5.18 kB 🟢 -4.56 kB
assets/SignInContent-CGU54g5G.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.29 kB 🟢 -4.62 kB
assets/SignInContent-CpsPrf53.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.29 kB 🔴 +4.63 kB
assets/CurrentUserPopoverWorkspace-B4W_k4Yz.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -4.83 kB 🟢 -4.33 kB
assets/CurrentUserPopoverWorkspace-COLXKIfY.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +4.83 kB 🔴 +4.33 kB
assets/WidgetInputNumber-BnKqMZ0Y.js (removed) 19.1 kB 🟢 -19.1 kB 🟢 -4.84 kB 🟢 -4.29 kB
assets/WidgetInputNumber-G0AWHCv4.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.84 kB 🔴 +4.29 kB
assets/WidgetRecordAudio-DNS-T6XB.js (removed) 18.1 kB 🟢 -18.1 kB 🟢 -5.18 kB 🟢 -4.64 kB
assets/WidgetRecordAudio-DRj1AfX1.js (new) 18.1 kB 🔴 +18.1 kB 🔴 +5.18 kB 🔴 +4.64 kB
assets/Load3D-BIhUOH4-.js (removed) 16.9 kB 🟢 -16.9 kB 🟢 -4.12 kB 🟢 -3.59 kB
assets/Load3D-BP6h0oOW.js (new) 16.9 kB 🔴 +16.9 kB 🔴 +4.12 kB 🔴 +3.59 kB
assets/WidgetCurve-BRevMW8h.js (new) 16.1 kB 🔴 +16.1 kB 🔴 +4.96 kB 🔴 +4.45 kB
assets/WidgetCurve-WwPiAfJU.js (removed) 16.1 kB 🟢 -16.1 kB 🟢 -4.96 kB 🟢 -4.46 kB
assets/load3d-CWhndqrX.js (new) 15 kB 🔴 +15 kB 🔴 +4.32 kB 🔴 +3.74 kB
assets/load3d-OgZd4i27.js (removed) 15 kB 🟢 -15 kB 🟢 -4.32 kB 🟢 -3.74 kB
assets/WaveAudioPlayer-B1e2qtj7.js (removed) 13.4 kB 🟢 -13.4 kB 🟢 -3.68 kB 🟢 -3.22 kB
assets/WaveAudioPlayer-D7Qw2-B-.js (new) 13.4 kB 🔴 +13.4 kB 🔴 +3.69 kB 🔴 +3.23 kB
assets/TeamWorkspacesDialogContent-BYf4welV.js (new) 11.1 kB 🔴 +11.1 kB 🔴 +3.33 kB 🔴 +2.97 kB
assets/TeamWorkspacesDialogContent-D7eHdywX.js (removed) 11.1 kB 🟢 -11.1 kB 🟢 -3.33 kB 🟢 -2.98 kB
assets/nodeTemplates-BWcvOFK_.js (new) 9.58 kB 🔴 +9.58 kB 🔴 +3.37 kB 🔴 +2.97 kB
assets/nodeTemplates-CxYg2Mzc.js (removed) 9.58 kB 🟢 -9.58 kB 🟢 -3.37 kB 🟢 -2.98 kB
assets/InviteMemberDialogContent-DeIOjbwZ.js (new) 7.77 kB 🔴 +7.77 kB 🔴 +2.45 kB 🔴 +2.13 kB
assets/InviteMemberDialogContent-X3zzFY0e.js (removed) 7.77 kB 🟢 -7.77 kB 🟢 -2.45 kB 🟢 -2.15 kB
assets/Load3DConfiguration-Bmr2-VAO.js (new) 6.6 kB 🔴 +6.6 kB 🔴 +2.04 kB 🔴 +1.78 kB
assets/Load3DConfiguration-Dmhx5O-p.js (removed) 6.6 kB 🟢 -6.6 kB 🟢 -2.04 kB 🟢 -1.78 kB
assets/onboardingCloudRoutes-D1plFSYC.js (removed) 6.53 kB 🟢 -6.53 kB 🟢 -2.04 kB 🟢 -1.76 kB
assets/onboardingCloudRoutes-D8M2-wXr.js (new) 6.53 kB 🔴 +6.53 kB 🔴 +2.04 kB 🔴 +1.75 kB
assets/WidgetWithControl-DCEC_L0S.js (removed) 5.99 kB 🟢 -5.99 kB 🟢 -2.38 kB 🟢 -2.11 kB
assets/WidgetWithControl-G3VeRh1N.js (new) 5.99 kB 🔴 +5.99 kB 🔴 +2.38 kB 🔴 +2.12 kB
assets/CreateWorkspaceDialogContent-Bao40Plg.js (new) 5.95 kB 🔴 +5.95 kB 🔴 +2.15 kB 🔴 +1.87 kB
assets/CreateWorkspaceDialogContent-FH1USDBL.js (removed) 5.95 kB 🟢 -5.95 kB 🟢 -2.15 kB 🟢 -1.88 kB
assets/FreeTierDialogContent-BkuaERTE.js (new) 5.82 kB 🔴 +5.82 kB 🔴 +2.04 kB 🔴 +1.8 kB
assets/FreeTierDialogContent-SQxQhowi.js (removed) 5.82 kB 🟢 -5.82 kB 🟢 -2.04 kB 🟢 -1.8 kB
assets/EditWorkspaceDialogContent-BWGkxSiH.js (removed) 5.75 kB 🟢 -5.75 kB 🟢 -2.11 kB 🟢 -1.84 kB
assets/EditWorkspaceDialogContent-C0-tMTOI.js (new) 5.75 kB 🔴 +5.75 kB 🔴 +2.11 kB 🔴 +1.84 kB
assets/WidgetTextarea-D6j2GGrq.js (new) 5.53 kB 🔴 +5.53 kB 🔴 +2.17 kB 🔴 +1.91 kB
assets/WidgetTextarea-DqMrAm2C.js (removed) 5.53 kB 🟢 -5.53 kB 🟢 -2.17 kB 🟢 -1.92 kB
assets/Preview3d-3ikA3Gzq.js (removed) 5.36 kB 🟢 -5.36 kB 🟢 -1.79 kB 🟢 -1.56 kB
assets/Preview3d-Cce75_KU.js (new) 5.36 kB 🔴 +5.36 kB 🔴 +1.79 kB 🔴 +1.55 kB
assets/ValueControlPopover-Cjb6At_w.js (new) 5.33 kB 🔴 +5.33 kB 🔴 +1.93 kB 🔴 +1.73 kB
assets/ValueControlPopover-DjbR5GxD.js (removed) 5.33 kB 🟢 -5.33 kB 🟢 -1.93 kB 🟢 -1.72 kB
assets/CancelSubscriptionDialogContent-BImE07Yb.js (removed) 5.22 kB 🟢 -5.22 kB 🟢 -1.95 kB 🟢 -1.7 kB
assets/CancelSubscriptionDialogContent-BwcZA-EU.js (new) 5.22 kB 🔴 +5.22 kB 🔴 +1.94 kB 🔴 +1.7 kB
assets/DeleteWorkspaceDialogContent-BNz6URW0.js (removed) 4.65 kB 🟢 -4.65 kB 🟢 -1.79 kB 🟢 -1.55 kB
assets/DeleteWorkspaceDialogContent-DMA9XHSn.js (new) 4.65 kB 🔴 +4.65 kB 🔴 +1.78 kB 🔴 +1.55 kB
assets/LeaveWorkspaceDialogContent-CXKccoyk.js (new) 4.48 kB 🔴 +4.48 kB 🔴 +1.73 kB 🔴 +1.51 kB
assets/LeaveWorkspaceDialogContent-DCQ-Ou5R.js (removed) 4.48 kB 🟢 -4.48 kB 🟢 -1.73 kB 🟢 -1.51 kB
assets/RemoveMemberDialogContent-ByVnk4fe.js (removed) 4.46 kB 🟢 -4.46 kB 🟢 -1.69 kB 🟢 -1.47 kB
assets/RemoveMemberDialogContent-DRXBD54T.js (new) 4.46 kB 🔴 +4.46 kB 🔴 +1.69 kB 🔴 +1.47 kB
assets/tierBenefits-CIdmc_pU.js (new) 4.45 kB 🔴 +4.45 kB 🔴 +1.57 kB 🔴 +1.36 kB
assets/tierBenefits-V_3pVOP3.js (removed) 4.45 kB 🟢 -4.45 kB 🟢 -1.58 kB 🟢 -1.37 kB
assets/RevokeInviteDialogContent-cMlQpUNE.js (removed) 4.37 kB 🟢 -4.37 kB 🟢 -1.7 kB 🟢 -1.48 kB
assets/RevokeInviteDialogContent-CVVPqa1h.js (new) 4.37 kB 🔴 +4.37 kB 🔴 +1.7 kB 🔴 +1.49 kB
assets/InviteMemberUpsellDialogContent-BBfiOS-_.js (new) 4.27 kB 🔴 +4.27 kB 🔴 +1.56 kB 🔴 +1.37 kB
assets/InviteMemberUpsellDialogContent-CxB1O9jE.js (removed) 4.27 kB 🟢 -4.27 kB 🟢 -1.56 kB 🟢 -1.37 kB
assets/cloudSessionCookie-C5Tihgoc.js (removed) 4.12 kB 🟢 -4.12 kB 🟢 -1.48 kB 🟢 -1.29 kB
assets/cloudSessionCookie-CUxymKZ1.js (new) 4.12 kB 🔴 +4.12 kB 🔴 +1.48 kB 🔴 +1.29 kB
assets/saveMesh-5-agXzy4.js (removed) 3.92 kB 🟢 -3.92 kB 🟢 -1.68 kB 🟢 -1.48 kB
assets/saveMesh-vBTNHC8Z.js (new) 3.92 kB 🔴 +3.92 kB 🔴 +1.68 kB 🔴 +1.48 kB
assets/Media3DTop-CjVGnsZZ.js (new) 3.85 kB 🔴 +3.85 kB 🔴 +1.62 kB 🔴 +1.42 kB
assets/Media3DTop-CZpLSvP8.js (removed) 3.85 kB 🟢 -3.85 kB 🟢 -1.62 kB 🟢 -1.42 kB
assets/GlobalToast-BphDNdzT.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.26 kB 🟢 -1.07 kB
assets/GlobalToast-C_4J4cFY.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.26 kB 🔴 +1.1 kB
assets/SubscribeToRun-7c-6hkNn.js (removed) 2.13 kB 🟢 -2.13 kB 🟢 -983 B 🟢 -870 B
assets/SubscribeToRun-B1kJ_0ig.js (new) 2.13 kB 🔴 +2.13 kB 🔴 +982 B 🔴 +870 B
assets/MediaAudioTop-BZjyrcSm.js (removed) 2.02 kB 🟢 -2.02 kB 🟢 -983 B 🟢 -875 B
assets/MediaAudioTop-CNJ9rDXJ.js (new) 2.02 kB 🔴 +2.02 kB 🔴 +983 B 🔴 +830 B
assets/CloudRunButtonWrapper-q6pHRGYf.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -910 B 🟢 -807 B
assets/CloudRunButtonWrapper-Z3HX1Jz_.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +910 B 🔴 +805 B
assets/cloudBadges-CU0xrioE.js (removed) 1.77 kB 🟢 -1.77 kB 🟢 -890 B 🟢 -785 B
assets/cloudBadges-D_xRRMa9.js (new) 1.77 kB 🔴 +1.77 kB 🔴 +892 B 🔴 +786 B
assets/cloudSubscription-CFgxJxe_.js (removed) 1.68 kB 🟢 -1.68 kB 🟢 -812 B 🟢 -700 B
assets/cloudSubscription-DU14aXGI.js (new) 1.68 kB 🔴 +1.68 kB 🔴 +814 B 🔴 +696 B
assets/previousFullPath-BYI5um8L.js (new) 1.53 kB 🔴 +1.53 kB 🔴 +695 B 🔴 +600 B
assets/previousFullPath-D16lUEFv.js (removed) 1.53 kB 🟢 -1.53 kB 🟢 -695 B 🟢 -602 B
assets/Load3D-AicHLaS_.js (removed) 1.34 kB 🟢 -1.34 kB 🟢 -611 B 🟢 -541 B
assets/Load3D-D86-g-S3.js (new) 1.34 kB 🔴 +1.34 kB 🔴 +611 B 🔴 +543 B
assets/nightlyBadges-CWW_kc7w.js (new) 1.29 kB 🔴 +1.29 kB 🔴 +654 B 🔴 +573 B
assets/nightlyBadges-F_wKNoBk.js (removed) 1.29 kB 🟢 -1.29 kB 🟢 -657 B 🟢 -573 B
assets/Load3dViewerContent-Bd7Z_Nmh.js (new) 1.23 kB 🔴 +1.23 kB 🔴 +564 B 🔴 +498 B
assets/Load3dViewerContent-kgsJ1d_G.js (removed) 1.23 kB 🟢 -1.23 kB 🟢 -565 B 🟢 -497 B
assets/SubscriptionPanelContentWorkspace-B8_blotu.js (removed) 1.15 kB 🟢 -1.15 kB 🟢 -533 B 🟢 -462 B
assets/SubscriptionPanelContentWorkspace-CGUNL9IY.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +532 B 🔴 +466 B
assets/WidgetLegacy-BW86vhDd.js (removed) 978 B 🟢 -978 B 🟢 -481 B 🟢 -420 B
assets/WidgetLegacy-CzvNgBf9.js (new) 978 B 🔴 +978 B 🔴 +479 B 🔴 +422 B
assets/changeTracker-9Ey40rA2.js (new) 952 B 🔴 +952 B 🔴 +467 B 🔴 +411 B
assets/changeTracker-BDJ9CHE0.js (removed) 952 B 🟢 -952 B 🟢 -469 B 🟢 -409 B
assets/graphHasMissingNodes-ByZwqUfO.js (new) 822 B 🔴 +822 B 🔴 +415 B 🔴 +348 B
assets/graphHasMissingNodes-DPev-kdC.js (removed) 822 B 🟢 -822 B 🟢 -414 B 🟢 -348 B

Status: 55 added / 55 removed / 79 unchanged

⚡ Performance Report

⚠️ 2 regressions detected

Metric Baseline PR (median) Δ Sig
canvas-zoom-sweep: layout duration 1ms 1ms +14% ⚠️ z=4.5
canvas-zoom-sweep: frame duration 17ms 17ms +0% ⚠️ z=2.2
All metrics
Metric Baseline PR (median) Δ Sig
canvas-idle: layout duration 0ms 0ms +0%
canvas-idle: style recalc duration 10ms 9ms -3% z=-1.7
canvas-idle: layout count 0 0 +0%
canvas-idle: style recalc count 11 11 +0% z=-0.3
canvas-idle: task duration 452ms 370ms -18% z=-0.8
canvas-idle: script duration 25ms 26ms +4% z=0.1
canvas-idle: TBT 0ms 0ms +0%
canvas-idle: frame duration 17ms 17ms +0% z=0.8
canvas-idle: heap used 60.1 MB 60.4 MB +0%
canvas-idle: DOM nodes 22 22 +0% z=-0.5
canvas-idle: event listeners 6 6 +0% z=-1.2
canvas-mouse-sweep: layout duration 4ms 4ms +5% z=1.5
canvas-mouse-sweep: style recalc duration 46ms 42ms -8% z=-0.1
canvas-mouse-sweep: layout count 12 12 +0%
canvas-mouse-sweep: style recalc count 84 76 -10% z=-1.1
canvas-mouse-sweep: task duration 1028ms 832ms -19% z=-0.6
canvas-mouse-sweep: script duration 139ms 124ms -11% z=-1.8
canvas-mouse-sweep: TBT 0ms 0ms +0%
canvas-mouse-sweep: frame duration 17ms 17ms -0% z=-2.6
canvas-mouse-sweep: heap used 55.6 MB 55.6 MB -0%
canvas-mouse-sweep: DOM nodes 65 60 -8% z=-0.9
canvas-mouse-sweep: event listeners 6 6 +0% z=-0.6
canvas-zoom-sweep: layout duration 1ms 1ms +14% ⚠️ z=4.5
canvas-zoom-sweep: style recalc duration 27ms 19ms -29% z=-0.2
canvas-zoom-sweep: layout count 6 6 +0%
canvas-zoom-sweep: style recalc count 31 32 +3% z=1.6
canvas-zoom-sweep: task duration 373ms 307ms -18% z=-0.9
canvas-zoom-sweep: script duration 30ms 27ms -10% z=-0.0
canvas-zoom-sweep: TBT 0ms 0ms +0%
canvas-zoom-sweep: frame duration 17ms 17ms +0% ⚠️ z=2.2
canvas-zoom-sweep: heap used 63.9 MB 64.2 MB +0%
canvas-zoom-sweep: DOM nodes 81 79 -2% z=-0.3
canvas-zoom-sweep: event listeners 19 19 +0% z=-0.9
dom-widget-clipping: layout duration 0ms 0ms +0%
dom-widget-clipping: style recalc duration 8ms 8ms -5% z=-2.7
dom-widget-clipping: layout count 0 0 +0%
dom-widget-clipping: style recalc count 12 13 +8% z=-0.2
dom-widget-clipping: task duration 379ms 331ms -13% z=-2.0
dom-widget-clipping: script duration 68ms 58ms -15% z=-3.0
dom-widget-clipping: TBT 0ms 0ms +0%
dom-widget-clipping: frame duration 17ms 17ms -0% z=-1.3
dom-widget-clipping: heap used 47.9 MB 48.0 MB +0%
dom-widget-clipping: DOM nodes 20 22 +10% z=-0.1
dom-widget-clipping: event listeners 2 2 +0% variance too high
large-graph-idle: layout duration 0ms 0ms +0%
large-graph-idle: style recalc duration 10ms 9ms -14% z=-3.2
large-graph-idle: layout count 0 0 +0%
large-graph-idle: style recalc count 11 11 +0% z=-1.9
large-graph-idle: task duration 670ms 572ms -15% z=0.5
large-graph-idle: script duration 106ms 96ms -10% z=-0.6
large-graph-idle: TBT 0ms 0ms +0%
large-graph-idle: frame duration 17ms 17ms +0% z=-1.8
large-graph-idle: heap used 66.7 MB 52.7 MB -21%
large-graph-idle: DOM nodes -257 -253 -2% z=-307.2
large-graph-idle: event listeners -123 -123 +0% z=-24.5
large-graph-pan: layout duration 0ms 0ms +0%
large-graph-pan: style recalc duration 16ms 16ms +1% z=-1.6
large-graph-pan: layout count 0 0 +0%
large-graph-pan: style recalc count 68 69 +1% z=-0.9
large-graph-pan: task duration 1208ms 1065ms -12% z=-0.4
large-graph-pan: script duration 398ms 372ms -6% z=-1.8
large-graph-pan: TBT 0ms 0ms +0%
large-graph-pan: frame duration 17ms 17ms -0% z=-1.8
large-graph-pan: heap used 68.2 MB 64.8 MB -5%
large-graph-pan: DOM nodes -264 -258 -2% z=-167.9
large-graph-pan: event listeners -125 -125 +0% z=-156.9
large-graph-zoom: layout duration 8ms 8ms -7%
large-graph-zoom: style recalc duration 19ms 17ms -9%
large-graph-zoom: layout count 60 60 +0%
large-graph-zoom: style recalc count 66 65 -2%
large-graph-zoom: task duration 1445ms 1304ms -10%
large-graph-zoom: script duration 512ms 464ms -9%
large-graph-zoom: TBT 0ms 0ms +0%
large-graph-zoom: frame duration 17ms 17ms +0%
large-graph-zoom: heap used 61.9 MB 59.1 MB -4%
large-graph-zoom: DOM nodes -267 -266 -0%
large-graph-zoom: event listeners -123 -123 +0%
minimap-idle: layout duration 0ms 0ms +0%
minimap-idle: style recalc duration 11ms 8ms -21% z=-1.3
minimap-idle: layout count 0 0 +0%
minimap-idle: style recalc count 11 10 -9% z=0.6
minimap-idle: task duration 645ms 544ms -16% z=0.3
minimap-idle: script duration 101ms 95ms -6% z=-0.3
minimap-idle: TBT 0ms 0ms +0%
minimap-idle: frame duration 17ms 17ms +0% z=1.2
minimap-idle: heap used 54.9 MB 54.4 MB -1%
minimap-idle: DOM nodes -257 -259 +1% z=-203.4
minimap-idle: event listeners -127 -125 -2% z=-196.2
subgraph-dom-widget-clipping: layout duration 0ms 0ms +0%
subgraph-dom-widget-clipping: style recalc duration 13ms 10ms -18% z=-2.4
subgraph-dom-widget-clipping: layout count 0 0 +0%
subgraph-dom-widget-clipping: style recalc count 48 48 +0% z=0.1
subgraph-dom-widget-clipping: task duration 382ms 341ms -11% z=-2.0
subgraph-dom-widget-clipping: script duration 125ms 115ms -7% z=-2.0
subgraph-dom-widget-clipping: TBT 0ms 0ms +0%
subgraph-dom-widget-clipping: frame duration 17ms 17ms -0% z=-2.0
subgraph-dom-widget-clipping: heap used 48.6 MB 48.4 MB -1%
subgraph-dom-widget-clipping: DOM nodes 21 21 +0% z=-1.1
subgraph-dom-widget-clipping: event listeners 8 8 +0% z=-1.4
subgraph-idle: layout duration 0ms 0ms +0%
subgraph-idle: style recalc duration 9ms 9ms -9% z=-2.4
subgraph-idle: layout count 0 0 +0%
subgraph-idle: style recalc count 10 11 +10% z=0.2
subgraph-idle: task duration 436ms 347ms -20% z=-0.7
subgraph-idle: script duration 28ms 19ms -30% z=-0.3
subgraph-idle: TBT 0ms 0ms +0%
subgraph-idle: frame duration 17ms 17ms +0% z=1.5
subgraph-idle: heap used 60.3 MB 60.0 MB -0%
subgraph-idle: DOM nodes 20 22 +10% z=0.1
subgraph-idle: event listeners 6 6 +0% variance too high
subgraph-mouse-sweep: layout duration 5ms 5ms -2% z=0.0
subgraph-mouse-sweep: style recalc duration 50ms 46ms -9% z=1.0
subgraph-mouse-sweep: layout count 16 16 +0%
subgraph-mouse-sweep: style recalc count 85 85 +0% z=2.5
subgraph-mouse-sweep: task duration 1004ms 897ms -11% z=1.9
subgraph-mouse-sweep: script duration 102ms 93ms -9% z=-1.2
subgraph-mouse-sweep: TBT 0ms 0ms +0%
subgraph-mouse-sweep: frame duration 17ms 17ms -0% z=-1.4
subgraph-mouse-sweep: heap used 52.3 MB 52.0 MB -1%
subgraph-mouse-sweep: DOM nodes 72 74 +3% z=3.2
subgraph-mouse-sweep: event listeners 6 6 +0% variance too high
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 11051ms 10627ms -4%
vue-large-graph-idle: script duration 608ms 555ms -9%
vue-large-graph-idle: TBT 0ms 0ms +0%
vue-large-graph-idle: frame duration 18ms 18ms -0%
vue-large-graph-idle: heap used 165.2 MB 155.0 MB -6%
vue-large-graph-idle: DOM nodes -8331 -8331 +0%
vue-large-graph-idle: event listeners -16467 -16468 +0%
vue-large-graph-pan: layout duration 0ms 0ms +0%
vue-large-graph-pan: style recalc duration 16ms 15ms -5%
vue-large-graph-pan: layout count 0 0 +0%
vue-large-graph-pan: style recalc count 65 64 -2%
vue-large-graph-pan: task duration 12846ms 12415ms -3%
vue-large-graph-pan: script duration 906ms 821ms -9%
vue-large-graph-pan: TBT 0ms 0ms +0%
vue-large-graph-pan: frame duration 18ms 18ms +0%
vue-large-graph-pan: heap used 163.8 MB 164.9 MB +1%
vue-large-graph-pan: DOM nodes -8331 -8331 +0%
vue-large-graph-pan: event listeners -16464 -16464 +0%
workflow-execution: layout duration 2ms 1ms -24% z=-1.8
workflow-execution: style recalc duration 27ms 22ms -21% z=-1.2
workflow-execution: layout count 6 5 -17% z=0.1
workflow-execution: style recalc count 20 16 -20% z=-0.9
workflow-execution: task duration 144ms 117ms -19% z=-0.6
workflow-execution: script duration 30ms 27ms -10% z=-0.7
workflow-execution: TBT 0ms 0ms +0%
workflow-execution: frame duration 17ms 17ms +0% z=1.6
workflow-execution: heap used 47.7 MB 47.8 MB +0%
workflow-execution: DOM nodes 169 156 -8% z=-0.7
workflow-execution: event listeners 71 71 +0% z=4.4
Historical variance (last 15 runs)
Metric μ σ CV
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: frame duration 17ms 0ms 0.0%
canvas-idle: DOM nodes 23 1 5.6%
canvas-idle: event listeners 12 5 40.9%
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: frame duration 17ms 0ms 0.0%
canvas-mouse-sweep: DOM nodes 62 3 4.2%
canvas-mouse-sweep: event listeners 8 4 49.4%
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: frame duration 17ms 0ms 0.0%
canvas-zoom-sweep: DOM nodes 79 1 1.0%
canvas-zoom-sweep: event listeners 24 5 21.8%
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: frame duration 17ms 0ms 0.0%
dom-widget-clipping: DOM nodes 22 1 6.4%
dom-widget-clipping: event listeners 8 6 81.2%
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: frame duration 17ms 0ms 0.0%
large-graph-idle: DOM nodes 25 1 3.7%
large-graph-idle: event listeners 26 6 23.2%
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: frame duration 17ms 0ms 0.0%
large-graph-pan: DOM nodes 19 2 8.7%
large-graph-pan: event listeners 5 1 16.8%
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: frame duration 17ms 0ms 0.0%
minimap-idle: DOM nodes 19 1 7.1%
minimap-idle: event listeners 5 1 14.4%
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: frame duration 17ms 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: 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: frame duration 17ms 0ms 0.0%
subgraph-idle: DOM nodes 22 1 6.9%
subgraph-idle: event listeners 10 7 64.5%
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: frame duration 17ms 0ms 0.0%
subgraph-mouse-sweep: DOM nodes 67 2 3.3%
subgraph-mouse-sweep: event listeners 8 4 52.6%
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: frame duration 17ms 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: 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: frame duration ▆▃▆▁▆▃▆█▆▆▄▃▃▄▃ ➡️ 17ms
canvas-idle: heap used ➡️ NaN MB
canvas-idle: DOM nodes █▇▆▅▃▇▃▁▂▂▅▆▆▆▇ ➡️ 24
canvas-idle: event listeners ▅█▅▄▁▅▁▁▁▄▅▅▁▅▄ 📉 11
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: frame duration ▆█▆▃▁▃▁▆▆▁▃▆▆▃▃ ➡️ 17ms
canvas-mouse-sweep: heap used ➡️ NaN MB
canvas-mouse-sweep: DOM nodes █▅▃▃▁▂▂▃▂▄▆▅▃▅▅ ➡️ 64
canvas-mouse-sweep: event listeners █▁▁▁▁▁▇▁▁▁██▇▁█ 📈 13
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: frame duration ▅▅█▄▅▁▁▁▅▁▁▅▄▅▁ ➡️ 17ms
canvas-zoom-sweep: heap used ➡️ NaN MB
canvas-zoom-sweep: DOM nodes ▄▃▁▅█▁▃▆▄▅▅▃▃▄▃ ➡️ 79
canvas-zoom-sweep: event listeners ▁▁▂▅█▂▁▅▁▅▅▄▁▅▁ ➡️ 19
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: frame duration ▂▄▅▅▂▄█▇▅▇▇▅▅▁▇ ➡️ 17ms
dom-widget-clipping: heap used ➡️ NaN MB
dom-widget-clipping: DOM nodes ▇▇▄▇▅▄█▇▅▁▅▄▇▃▄ ➡️ 21
dom-widget-clipping: event listeners ▅▅▅▅▁▅██▁▁▁▁█▁▁ 📉 2
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: frame duration ▅▅▅▅▅▂▁▂▄▅▄▂▂▅█ ➡️ 17ms
large-graph-idle: heap used ➡️ NaN MB
large-graph-idle: DOM nodes ▆█▅▂▅▃▁▂▃▅▅▆▂▆▅ ➡️ 25
large-graph-idle: event listeners ███▇██▄▁▄▇▇█▂█▇ ➡️ 29
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: frame duration ▆▃▃▆█▃▁█▆▆▆▆█▁▆ ➡️ 17ms
large-graph-pan: heap used ➡️ NaN MB
large-graph-pan: DOM nodes ▅▃▆▂▄▁▃▁▁▅▁▂█▅▂ ➡️ 18
large-graph-pan: event listeners █▆█▁▁▆▁▁▃▆▁▃██▃ ➡️ 5
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: frame duration ▃▆▆▃█▁█▆▆▃▃▆█▆█ ➡️ 17ms
minimap-idle: heap used ➡️ NaN MB
minimap-idle: DOM nodes ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 19
minimap-idle: event listeners ▃▃▆▁▁▁▃▁▁▆▁▃█▆▁ ➡️ 4
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: frame duration ▅▄▄▄▄▄█▄▄▄▃▁▆▃▃ ➡️ 17ms
subgraph-dom-widget-clipping: heap used ➡️ NaN MB
subgraph-dom-widget-clipping: DOM nodes ▅▇▅▂▅▂▁▅▅▅▁▇▅█▄ ➡️ 22
subgraph-dom-widget-clipping: event listeners ▅▅▅▂▅▁▅██▁▁█▅█▅ 📈 16
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: frame duration ▆▆█▁▆▃▆▆▆▃▆▁▃▆█ ➡️ 17ms
subgraph-idle: heap used ➡️ NaN MB
subgraph-idle: DOM nodes ▃▅▃▂▁▄▁▂▁▅▃▂▇█▇ ➡️ 24
subgraph-idle: event listeners ▁▅▁▁▁▁▁▁▁▅▄▁███ 📈 21
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: frame duration ▅▄▁▃▃▄▆▄▆▃▃█▁▃▃ ➡️ 17ms
subgraph-mouse-sweep: heap used ➡️ NaN MB
subgraph-mouse-sweep: DOM nodes ▅▁▄▅▁▄▃▃█▅▅▄▂▅▃ ➡️ 66
subgraph-mouse-sweep: event listeners ▇▁▂▇▁▂▂▂█▇▂▂▇▇▂ 📈 5
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: frame duration ▆▆▆▄▆▆▃▄▁▄█▆▅▄▆ ➡️ 17ms
workflow-execution: heap used ➡️ NaN MB
workflow-execution: DOM nodes ▂█▃▆▁▄▃▅▃█▃▃▄▃▁ ➡️ 152
workflow-execution: event listeners ▅███▁▅███▁██▅█▅ ➡️ 49
Raw data
{
  "timestamp": "2026-03-27T17:25:07.996Z",
  "gitSha": "4defe467dea10f0d94d761ea9febcbc66f06ebe0",
  "branch": "pysssss/test/switching-tab-regression-test",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2004.6290000000226,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 9.339,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 369.78,
      "heapDeltaBytes": 21040692,
      "heapUsedBytes": 63360452,
      "domNodes": 22,
      "jsHeapTotalBytes": 22544384,
      "scriptDurationMs": 25.593999999999998,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "canvas-idle",
      "durationMs": 2010.5649999999855,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 9.174,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 374.4789999999999,
      "heapDeltaBytes": 21004156,
      "heapUsedBytes": 64715176,
      "domNodes": 22,
      "jsHeapTotalBytes": 22806528,
      "scriptDurationMs": 26.962999999999994,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "canvas-idle",
      "durationMs": 1998.80399999995,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 10.293,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 366.475,
      "heapDeltaBytes": 20124148,
      "heapUsedBytes": 63010304,
      "domNodes": 23,
      "jsHeapTotalBytes": 22544384,
      "scriptDurationMs": 20.072,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000073
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1877.758999999969,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 42.361000000000004,
      "layouts": 12,
      "layoutDurationMs": 5.569,
      "taskDurationMs": 831.9960000000001,
      "heapDeltaBytes": 15857480,
      "heapUsedBytes": 58253784,
      "domNodes": 58,
      "jsHeapTotalBytes": 23068672,
      "scriptDurationMs": 131.672,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1988.2809999999722,
      "styleRecalcs": 84,
      "styleRecalcDurationMs": 43.669,
      "layouts": 12,
      "layoutDurationMs": 3.626,
      "taskDurationMs": 969.129,
      "heapDeltaBytes": 15876976,
      "heapUsedBytes": 58334040,
      "domNodes": 66,
      "jsHeapTotalBytes": 23855104,
      "scriptDurationMs": 123.59800000000001,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1809.7270000000663,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 38.441,
      "layouts": 12,
      "layoutDurationMs": 3.9020000000000006,
      "taskDurationMs": 751.7909999999999,
      "heapDeltaBytes": 15533724,
      "heapUsedBytes": 58244232,
      "domNodes": 60,
      "jsHeapTotalBytes": 24117248,
      "scriptDurationMs": 121.53699999999999,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.65999999999999
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1720.158999999967,
      "styleRecalcs": 32,
      "styleRecalcDurationMs": 16.636000000000003,
      "layouts": 6,
      "layoutDurationMs": 0.745,
      "taskDurationMs": 300.87,
      "heapDeltaBytes": 24594912,
      "heapUsedBytes": 67423872,
      "domNodes": 79,
      "jsHeapTotalBytes": 20971520,
      "scriptDurationMs": 24.815000000000005,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000027
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1753.2620000000065,
      "styleRecalcs": 34,
      "styleRecalcDurationMs": 18.89,
      "layouts": 6,
      "layoutDurationMs": 1.5389999999999997,
      "taskDurationMs": 315.072,
      "heapDeltaBytes": 24610844,
      "heapUsedBytes": 67349708,
      "domNodes": 82,
      "jsHeapTotalBytes": 20447232,
      "scriptDurationMs": 27.983999999999995,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000073
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1770.6819999999652,
      "styleRecalcs": 32,
      "styleRecalcDurationMs": 21.159000000000002,
      "layouts": 6,
      "layoutDurationMs": 0.8469999999999999,
      "taskDurationMs": 306.765,
      "heapDeltaBytes": 24643896,
      "heapUsedBytes": 67060560,
      "domNodes": 79,
      "jsHeapTotalBytes": 20447232,
      "scriptDurationMs": 27.046999999999997,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 539.8910000000114,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 6.653,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 324.682,
      "heapDeltaBytes": 6131196,
      "heapUsedBytes": 49178236,
      "domNodes": 14,
      "jsHeapTotalBytes": 13107200,
      "scriptDurationMs": 54.607,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.65999999999999
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 557.1360000000141,
      "styleRecalcs": 14,
      "styleRecalcDurationMs": 11.088999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 345.059,
      "heapDeltaBytes": -1823332,
      "heapUsedBytes": 50884060,
      "domNodes": 22,
      "jsHeapTotalBytes": 15990784,
      "scriptDurationMs": 58.934000000000005,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 523.832000000084,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 7.755000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 331.227,
      "heapDeltaBytes": 6697260,
      "heapUsedBytes": 50328580,
      "domNodes": 22,
      "jsHeapTotalBytes": 13893632,
      "scriptDurationMs": 58.02299999999999,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2029.5429999999897,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 8.848000000000003,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 563.34,
      "heapDeltaBytes": 4627008,
      "heapUsedBytes": 54865472,
      "domNodes": -257,
      "jsHeapTotalBytes": 15929344,
      "scriptDurationMs": 96.17,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2015.9230000000434,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 8.745999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 571.5110000000001,
      "heapDeltaBytes": 19814316,
      "heapUsedBytes": 71473944,
      "domNodes": -253,
      "jsHeapTotalBytes": 14675968,
      "scriptDurationMs": 95.064,
      "eventListeners": -123,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.659999999999947
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2047.166000000061,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 9.361999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 579.7909999999999,
      "heapDeltaBytes": 5632580,
      "heapUsedBytes": 55254892,
      "domNodes": -252,
      "jsHeapTotalBytes": 15929344,
      "scriptDurationMs": 96.12799999999999,
      "eventListeners": -121,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2127.1050000000287,
      "styleRecalcs": 70,
      "styleRecalcDurationMs": 16.605,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1058.298,
      "heapDeltaBytes": 16417476,
      "heapUsedBytes": 67978876,
      "domNodes": -258,
      "jsHeapTotalBytes": 18231296,
      "scriptDurationMs": 372.335,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.659999999999947
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2141.985000000034,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 16.007,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1105.157,
      "heapDeltaBytes": 19549564,
      "heapUsedBytes": 71220840,
      "domNodes": -260,
      "jsHeapTotalBytes": 17969152,
      "scriptDurationMs": 388.243,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2109.2409999999973,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 15.879000000000005,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1065.211,
      "heapDeltaBytes": -5319868,
      "heapUsedBytes": 47580744,
      "domNodes": -257,
      "jsHeapTotalBytes": 21491712,
      "scriptDurationMs": 365.55,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3134.1059999999743,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 15.736,
      "layouts": 60,
      "layoutDurationMs": 7.738,
      "taskDurationMs": 1304.197,
      "heapDeltaBytes": 7250708,
      "heapUsedBytes": 61962708,
      "domNodes": -266,
      "jsHeapTotalBytes": 17240064,
      "scriptDurationMs": 463.79800000000006,
      "eventListeners": -123,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3152.238000000011,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 17.02,
      "layouts": 60,
      "layoutDurationMs": 7.646,
      "taskDurationMs": 1320.521,
      "heapDeltaBytes": 9351040,
      "heapUsedBytes": 64614052,
      "domNodes": -264,
      "jsHeapTotalBytes": 15249408,
      "scriptDurationMs": 476.02299999999997,
      "eventListeners": -123,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3134.65999999994,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 16.813000000000002,
      "layouts": 60,
      "layoutDurationMs": 7.644,
      "taskDurationMs": 1293.215,
      "heapDeltaBytes": 6752760,
      "heapUsedBytes": 61486296,
      "domNodes": -266,
      "jsHeapTotalBytes": 17240064,
      "scriptDurationMs": 451.566,
      "eventListeners": -123,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "minimap-idle",
      "durationMs": 2059.886000000006,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 8.498999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 543.5490000000001,
      "heapDeltaBytes": 4478928,
      "heapUsedBytes": 57019372,
      "domNodes": -259,
      "jsHeapTotalBytes": 16453632,
      "scriptDurationMs": 95.47999999999999,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "minimap-idle",
      "durationMs": 2043.7430000000063,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 8.771999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 556.332,
      "heapDeltaBytes": 20497712,
      "heapUsedBytes": 72456032,
      "domNodes": -258,
      "jsHeapTotalBytes": 15929344,
      "scriptDurationMs": 101.71,
      "eventListeners": -123,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "minimap-idle",
      "durationMs": 2024.0720000000465,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 8.028,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 528.093,
      "heapDeltaBytes": -7011876,
      "heapUsedBytes": 46413512,
      "domNodes": -260,
      "jsHeapTotalBytes": 16510976,
      "scriptDurationMs": 87.23599999999999,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000073
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 587.931000000026,
      "styleRecalcs": 49,
      "styleRecalcDurationMs": 12.400999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 363.767,
      "heapDeltaBytes": 6537052,
      "heapUsedBytes": 49182932,
      "domNodes": 22,
      "jsHeapTotalBytes": 12582912,
      "scriptDurationMs": 126.247,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.65999999999999
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 562.7210000000105,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 10.479000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 340.92,
      "heapDeltaBytes": 6442716,
      "heapUsedBytes": 50780108,
      "domNodes": 20,
      "jsHeapTotalBytes": 13631488,
      "scriptDurationMs": 115.386,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 525.7930000000215,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 10.488000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 331.688,
      "heapDeltaBytes": 6734628,
      "heapUsedBytes": 50725664,
      "domNodes": 21,
      "jsHeapTotalBytes": 13369344,
      "scriptDurationMs": 110.791,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2004.854000000023,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 8.536999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 346.858,
      "heapDeltaBytes": 19814988,
      "heapUsedBytes": 62859108,
      "domNodes": 23,
      "jsHeapTotalBytes": 22806528,
      "scriptDurationMs": 19.442999999999998,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "subgraph-idle",
      "durationMs": 1996.0330000000113,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.110000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 349.402,
      "heapDeltaBytes": 19882348,
      "heapUsedBytes": 62899392,
      "domNodes": 22,
      "jsHeapTotalBytes": 23068672,
      "scriptDurationMs": 19.349999999999998,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000073
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2005.4710000000568,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 8.468,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 340.009,
      "heapDeltaBytes": 19889652,
      "heapUsedBytes": 62899112,
      "domNodes": 21,
      "jsHeapTotalBytes": 23330816,
      "scriptDurationMs": 18.185,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1971.8809999999962,
      "styleRecalcs": 85,
      "styleRecalcDurationMs": 45.724000000000004,
      "layouts": 16,
      "layoutDurationMs": 4.699,
      "taskDurationMs": 896.894,
      "heapDeltaBytes": 11819672,
      "heapUsedBytes": 54492972,
      "domNodes": 74,
      "jsHeapTotalBytes": 22806528,
      "scriptDurationMs": 93.252,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.659999999999947
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1996.1210000000165,
      "styleRecalcs": 88,
      "styleRecalcDurationMs": 46.931,
      "layouts": 16,
      "layoutDurationMs": 4.652,
      "taskDurationMs": 940.9110000000001,
      "heapDeltaBytes": 2352372,
      "heapUsedBytes": 54504352,
      "domNodes": 74,
      "jsHeapTotalBytes": 25690112,
      "scriptDurationMs": 93.652,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.659999999999947
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1697.9179999999587,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 36.113,
      "layouts": 16,
      "layoutDurationMs": 6.324000000000001,
      "taskDurationMs": 671.84,
      "heapDeltaBytes": 11743408,
      "heapUsedBytes": 54823680,
      "domNodes": 61,
      "jsHeapTotalBytes": 22806528,
      "scriptDurationMs": 88.822,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000027
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 10643.439999999999,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 10627.072,
      "heapDeltaBytes": -33395952,
      "heapUsedBytes": 162514768,
      "domNodes": -8331,
      "jsHeapTotalBytes": 23945216,
      "scriptDurationMs": 579.811,
      "eventListeners": -16468,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 18.329999999999927
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 10895.164000000022,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 10882.683,
      "heapDeltaBytes": -44555652,
      "heapUsedBytes": 165708548,
      "domNodes": -8331,
      "jsHeapTotalBytes": 26828800,
      "scriptDurationMs": 554.5390000000001,
      "eventListeners": -16466,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 18.32000000000007
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 10592.265999999996,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 10580.347,
      "heapDeltaBytes": -40213296,
      "heapUsedBytes": 157259648,
      "domNodes": -8331,
      "jsHeapTotalBytes": 15294464,
      "scriptDurationMs": 538.761,
      "eventListeners": -16470,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 18.31999999999971
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 12432.480999999996,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 13.601000000000003,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12414.766999999998,
      "heapDeltaBytes": -22589708,
      "heapUsedBytes": 172944164,
      "domNodes": -8331,
      "jsHeapTotalBytes": 24383488,
      "scriptDurationMs": 839.5890000000002,
      "eventListeners": -16468,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 20
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 12375.834999999995,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 15.017000000000003,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12356.28,
      "heapDeltaBytes": -19957964,
      "heapUsedBytes": 173236120,
      "domNodes": -8329,
      "jsHeapTotalBytes": 25169920,
      "scriptDurationMs": 801.074,
      "eventListeners": -16462,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 18.329999999999927
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 12534.01000000008,
      "styleRecalcs": 67,
      "styleRecalcDurationMs": 17.412999999999982,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12514.356000000002,
      "heapDeltaBytes": -34690396,
      "heapUsedBytes": 159555028,
      "domNodes": -8331,
      "jsHeapTotalBytes": -4452352,
      "scriptDurationMs": 821.378,
      "eventListeners": -16464,
      "totalBlockingTimeMs": 81,
      "frameDurationMs": 18.340000000000146
    },
    {
      "name": "workflow-execution",
      "durationMs": 458.27500000001464,
      "styleRecalcs": 22,
      "styleRecalcDurationMs": 21.679999999999996,
      "layouts": 5,
      "layoutDurationMs": 1.7820000000000003,
      "taskDurationMs": 116.75700000000003,
      "heapDeltaBytes": 4668468,
      "heapUsedBytes": 50255856,
      "domNodes": 190,
      "jsHeapTotalBytes": 524288,
      "scriptDurationMs": 21.224,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.65999999999999
    },
    {
      "name": "workflow-execution",
      "durationMs": 444.95899999992616,
      "styleRecalcs": 16,
      "styleRecalcDurationMs": 24.335,
      "layouts": 5,
      "layoutDurationMs": 1.2599999999999998,
      "taskDurationMs": 125.31199999999998,
      "heapDeltaBytes": 4495780,
      "heapUsedBytes": 48914236,
      "domNodes": 156,
      "jsHeapTotalBytes": 262144,
      "scriptDurationMs": 30.315999999999995,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "workflow-execution",
      "durationMs": 446.42899999996644,
      "styleRecalcs": 16,
      "styleRecalcDurationMs": 19.924999999999997,
      "layouts": 5,
      "layoutDurationMs": 1.289,
      "taskDurationMs": 115.213,
      "heapDeltaBytes": 4479420,
      "heapUsedBytes": 50082888,
      "domNodes": 156,
      "jsHeapTotalBytes": 524288,
      "scriptDurationMs": 27.021000000000004,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000027
    }
  ]
}

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
browser_tests/tests/changeTrackerLoadGuard.spec.ts (2)

18-20: Avoid hard-coding the default workflow node count (7).

This makes the test fragile to default-workflow changes unrelated to the regression. Capture the baseline once, then assert it stays unchanged across tab switches.

♻️ Suggested refactor
-      // Tab 0: default workflow (7 nodes)
-      expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(7)
+      // Tab 0: capture baseline node count for this environment/workflow
+      const workflowANodeCount = await comfyPage.nodeOps.getGraphNodesCount()
+      expect(workflowANodeCount).toBeGreaterThan(0)

@@
-      expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(7)
+      expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(workflowANodeCount)

@@
-      expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(7)
+      expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(workflowANodeCount)

Based on learnings: default workflow composition can change, making fixed count assertions fragile.

Also applies to: 52-53, 63-63

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@browser_tests/tests/changeTrackerLoadGuard.spec.ts` around lines 18 - 20, The
test currently hard-codes the default workflow node count (expect(await
comfyPage.nodeOps.getGraphNodesCount()).toBe(7)), which is brittle; change the
test to capture the baseline count once (call
comfyPage.nodeOps.getGraphNodesCount() and store it in a variable like
baselineCount) and then reuse that variable for subsequent assertions across tab
switches instead of asserting against 7; update all occurrences (the initial
check and the later checks around lines referenced) to compare to baselineCount
so the test adapts to legitimate default-workflow changes.

55-56: Avoid relying on the literal 'Unsaved Workflow' tab label.

That label can change (naming/localization/product copy). Give tab 1 a deterministic name and switch by that.

♻️ Suggested refactor
       await comfyPage.menu.topbar.triggerTopbarCommand(['New'])
       await comfyPage.nextFrame()
       expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(0)
+      await comfyPage.menu.topbar.saveWorkflow('workflow-b')

@@
-      const tab1 = comfyPage.menu.topbar.getWorkflowTab('Unsaved Workflow')
+      const tab1 = comfyPage.menu.topbar.getWorkflowTab('workflow-b')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@browser_tests/tests/changeTrackerLoadGuard.spec.ts` around lines 55 - 56, The
test currently selects the tab by the literal label 'Unsaved Workflow'; instead
create or set a deterministic workflow name earlier in the test (e.g., const
workflowName = 'test-workflow-<uniqueId>') and use that variable when locating
the tab instead of the hardcoded string; update the call to
comfyPage.menu.topbar.getWorkflowTab(...) to use the deterministic workflowName
and ensure any workflow creation/rename step uses the same variable so the tab
lookup is stable across copy/localization changes (refer to
comfyPage.menu.topbar.getWorkflowTab and the tab1 variable).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@browser_tests/tests/changeTrackerLoadGuard.spec.ts`:
- Around line 18-20: The test currently hard-codes the default workflow node
count (expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(7)), which is
brittle; change the test to capture the baseline count once (call
comfyPage.nodeOps.getGraphNodesCount() and store it in a variable like
baselineCount) and then reuse that variable for subsequent assertions across tab
switches instead of asserting against 7; update all occurrences (the initial
check and the later checks around lines referenced) to compare to baselineCount
so the test adapts to legitimate default-workflow changes.
- Around line 55-56: The test currently selects the tab by the literal label
'Unsaved Workflow'; instead create or set a deterministic workflow name earlier
in the test (e.g., const workflowName = 'test-workflow-<uniqueId>') and use that
variable when locating the tab instead of the hardcoded string; update the call
to comfyPage.menu.topbar.getWorkflowTab(...) to use the deterministic
workflowName and ensure any workflow creation/rename step uses the same variable
so the tab lookup is stable across copy/localization changes (refer to
comfyPage.menu.topbar.getWorkflowTab and the tab1 variable).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 58c7a549-e6b9-4bdc-892a-bedf692ca774

📥 Commits

Reviewing files that changed from the base of the PR and between 2f9431c and c60d94b.

📒 Files selected for processing (1)
  • browser_tests/tests/changeTrackerLoadGuard.spec.ts

@pythongosssss pythongosssss marked this pull request as ready for review March 27, 2026 17:36
@pythongosssss pythongosssss requested a review from a team March 27, 2026 17:36
@dosubot dosubot bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Mar 27, 2026
Copy link
Copy Markdown
Contributor

@christian-byrne christian-byrne left a comment

Choose a reason for hiding this comment

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

LGTM!

Comment on lines +27 to +41
await comfyPage.page.evaluate(() => {
window.app!.registerExtension({
name: 'TestCheckStateDuringLoad',
afterConfigureGraph() {
const workflow = (window.app!.extensionManager as WorkspaceStore)
.workflow.activeWorkflow
if (!workflow) throw new Error('No workflow found')
// Bypass the guard to reproduce the corruption bug:
// ; (workflow.changeTracker.constructor as unknown as { isLoadingGraph: boolean }).isLoadingGraph = false

// Simulate the user clicking during graph loading
workflow.changeTracker.checkState()
}
})
})
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.

This is pretty creative. @coderabbitai make a tracking Issue to make a helper for registering any of the ComfyExtension hooks/callbacks in a browser test easily (if the time comes when we are doing this in multiple places).

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.

🧩 Analysis chain

@christian-byrne, I've created the tracking issue! Here's the summary of what was captured:

Issue created: the title is "test: Add helper for registering ComfyExtension hooks/callbacks in browser tests", assigned to you.

The issue documents:

  • The motivating pattern from this PR (inline page.evaluate(() => window.app!.registerExtension({...})))
  • A sketch of a proposed API (e.g., comfyPage.registerExtension({...}) as a helper on ComfyPage or a dedicated ExtensionHelper fixture)
  • Key benefits: reduced boilerplate, a single place to handle page.evaluate serialization constraints, and clearer test intent
  • Backlinks to this PR and comment

🏁 Script executed:

#!/bin/bash
gh issue create \
  --repo Comfy-Org/ComfyUI_frontend \
  --assignee christian-byrne \
  --title "test: Add helper for registering ComfyExtension hooks/callbacks in browser tests" \
  --body "## Summary

When writing E2E regression tests that need to simulate extension behavior, tests currently must inline a full \`window.app!.registerExtension({...})\` call inside \`page.evaluate()\`. See the pattern introduced in PR `#10623`:

\`\`\`ts
await comfyPage.page.evaluate(() => {
  window.app!.registerExtension({
    name: 'TestCheckStateDuringLoad',
    afterConfigureGraph() {
      // ...
    }
  })
})
\`\`\`

As more tests adopt this pattern, it will be beneficial to introduce a reusable browser-test helper (e.g., on \`ComfyPage\` or a dedicated \`ExtensionHelper\`) that allows callers to declaratively register any \`ComfyExtension\` hook/callback without repeating the boilerplate evaluate wrapper.

## Proposed API (sketch)

\`\`\`ts
// Possible surface on ComfyPage or a new ExtensionHelper fixture
await comfyPage.registerExtension({
  name: 'MyTestExtension',
  afterConfigureGraph() { ... },
  // ...any other ComfyExtension hooks
})
\`\`\`

## Motivation

- Reduces boilerplate across spec files.
- Provides a single place to handle serialization constraints (e.g., functions passed to \`page.evaluate\` must be serializable).
- Makes test intent clearer — callers express *what* hooks to register, not *how* to wire them into the page context.

## Context

- Tracking issue requested in: https://github.com/Comfy-Org/ComfyUI_frontend/pull/10623#discussion_r3002645765
- First usage / motivating example: https://github.com/Comfy-Org/ComfyUI_frontend/pull/10623
- Requested by: `@christian-byrne`
"

Length of output: 58


@christian-byrne, the tracking issue has been created: #10626

It documents the motivating pattern from this PR, a sketch of a proposed comfyPage.registerExtension(...) helper API, and the key benefits (reduced boilerplate, centralized handling of page.evaluate serialization constraints, and clearer test intent). It's assigned to you.


🧠 Learnings used
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 10547
File: browser_tests/tests/workflowPersistence.spec.ts:459-471
Timestamp: 2026-03-27T05:12:16.400Z
Learning: In `browser_tests/tests/workflowPersistence.spec.ts` (Comfy-Org/ComfyUI_frontend PR `#10547`), the G10 test for PR `#8715` (transient blob:/api-view URL serialization) intentionally validates only the static/default workflow export — not an executed/transient widget state. Putting an image widget into its executed state requires actual model inference (image output generation), which is not available in the current E2E test infrastructure. The test still covers the regression if the `widget.serialize` disable path breaks. Do not flag the absence of transient-state setup in this test; full integration coverage is tracked separately.

Learnt from: xmarre
Repo: Comfy-Org/ComfyUI_frontend PR: 10367
File: browser_tests/tests/workflowPersistence.spec.ts:68-77
Timestamp: 2026-03-21T16:57:48.590Z
Learning: In `browser_tests/tests/workflowPersistence.spec.ts`, the `waitForTabStatePersistence` helper intentionally does NOT validate `activeIndex` on the persisted `OpenPaths` session storage entry. The test immediately overwrites `openPointer.activeIndex = 1` after the wait resolves, so the previously persisted `activeIndex` value is irrelevant. The only invariant being guarded is that `openPointer.paths.length >= expectedMinPaths` (i.e., all workflow paths have been flushed into storage before the test proceeds). Do not suggest adding `activeIndex` validation to this wait predicate in future reviews.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 10548
File: browser_tests/tests/propertiesPanel/propertiesPanel.spec.ts:57-66
Timestamp: 2026-03-27T05:12:28.417Z
Learning: In Comfy-Org/ComfyUI_frontend browser tests for the properties panel (`browser_tests/tests/propertiesPanel/propertiesPanel.spec.ts`), do not assert that the rendered node-entry count in the Nodes tab matches `comfyPage.nodeOps.getNodeCount()`. The default workflow composition can change, making count-based assertions fragile. Prefer asserting that a known node (e.g., 'KSampler') is visible. For filter assertions, asserting the matching entry is visible is sufficient; a non-match disappearing assertion is deferred to a future iteration.

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/AGENTS.md:0-0
Timestamp: 2026-02-03T20:33:39.759Z
Learning: Applies to browser_tests/**/*.spec.ts : Use premade JSON workflows in the `assets/` directory to load desired graph state in E2E tests

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7415
File: browser_tests/tests/mobileBaseline.spec.ts:17-22
Timestamp: 2025-12-13T05:54:35.779Z
Learning: In browser_tests tests for the Comfy-Org/ComfyUI_frontend repository, the `comfyPage.loadWorkflow()` method already handles all necessary synchronization and waiting. No additional `await comfyPage.nextFrame()` call is needed before taking screenshots after loading a workflow.

Learnt from: pythongosssss
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: :0-0
Timestamp: 2026-03-18T15:38:16.169Z
Learning: In Comfy-Org/ComfyUI_frontend, race conditions between WebSocket events and HTTP responses (e.g., the WebSocket/HTTP race in job tracking in `src/renderer/extensions/linearMode/linearOutputStore.ts`) are not suitable candidates for E2E testing because the non-deterministic ordering cannot be reliably reproduced in Playwright. Unit tests (e.g., in `linearOutputStore.test.ts`) that deterministically simulate event ordering are the correct approach. Do not request E2E tests for such race condition scenarios.

Learnt from: jaeone94
Repo: Comfy-Org/ComfyUI_frontend PR: 10309
File: browser_tests/tests/missingMedia.spec.ts:141-145
Timestamp: 2026-03-25T15:30:09.361Z
Learning: In `browser_tests/tests/missingMedia.spec.ts` (Comfy-Org/ComfyUI_frontend PR `#10309`), the library-select E2E test uses `test.skip()` when no options are found because the OSS test server's input directory content varies per environment and cannot be guaranteed to contain specific library items. The upload flow test already covers the full 2-step confirm path. Do not flag this `test.skip()` guard as a regression risk or suggest pre-uploading files (which creates inter-test dependency). If deterministic coverage is needed in the future, suggest mocking the input-file list endpoint via Playwright's `page.route()` instead.

Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: :0-0
Timestamp: 2026-03-27T05:26:01.429Z
Learning: In Comfy-Org/ComfyUI_frontend PR `#10526`, the async scope-disposal race in `src/platform/cloud/notification/components/DesktopCloudNotificationController.vue` (desktop/mac-only cloud promo flow) is intentionally covered only at the unit level via `DesktopCloudNotificationController.test.ts`, using a deferred `settingStore.load()` promise and fake timers to deterministically verify that the dialog is not scheduled or shown after the owning scope is disposed. A Playwright E2E test is not appropriate here because: (1) the non-deterministic ordering cannot be reliably reproduced in Playwright, (2) the feature requires a real macOS Electron environment not available in CI, and (3) a timing-driven pseudo-E2E would be flaky and weaker than the unit test. If broader coverage is needed later, the right approach is a separate desktop promo smoke test, not a race-specific E2E regression. Do not request a Playwright/E2E test for this specific race condition scenario.

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/AGENTS.md:0-0
Timestamp: 2026-03-17T08:09:41.456Z
Learning: Applies to browser_tests/**/*.spec.ts : Refer to `docs/guidance/playwright.md` for Playwright best practices when writing E2E tests

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 9554
File: browser_tests/fixtures/ComfyPage.ts:189-193
Timestamp: 2026-03-12T10:03:55.383Z
Learning: In browser_tests, seed localStorage-based feature flags at init time using FeatureFlagHelper.seedFlags() (which uses page.addInitScript) before any navigation. Ensure this happens before comfyPage.setup() is called. The comfyPageFixture currently yields after calling comfyPage.setup(), so do not defer setup() from the fixture or add a pre-setup hook, as changing this would break existing tests.

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-27T01:16:09.991Z
Learning: Applies to browser_tests/**/*.spec.ts : Write E2E tests in `browser_tests/**/*.spec.ts` using Playwright

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-27T01:16:09.991Z
Learning: Applies to browser_tests/**/*.spec.ts : Follow Playwright best practices from Playwright documentation for E2E tests

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-03-24T17:16:12.386Z
Learning: For bug-fix PRs, ensure end-to-end regression coverage by either: (1) changing at least one file under `browser_tests/`, or (2) providing a concrete, non-placeholder explanation in the PR description of why an end-to-end regression test was not added. Use only PR metadata available in the review context (PR title, commit subjects, files changed relative to base, PR description). Do not rely on shell commands or inspect files outside the PR.

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/AGENTS.md:0-0
Timestamp: 2026-03-17T08:09:41.456Z
Learning: Applies to browser_tests/**/*.ts : Run `pnpm typecheck:browser` after modifying TypeScript files in the browser_tests directory

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 10140
File: apps/website/package.json:1-79
Timestamp: 2026-03-17T07:28:27.677Z
Learning: In Comfy-Org/ComfyUI_frontend, PRs managed via Graphite stacked sets (using `gt split`) may show browser_tests/ files in the diff as artifacts of the split process. These files contain no actual changes relative to origin/main and should not be flagged as unrelated scope changes. Verify against the PR title/description stacking context before raising scope concerns.

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-03-17T07:39:57.336Z
Learning: End-to-end regression coverage for fixes: Use PR metadata (PR title, commit subjects, files changed relative to PR base, PR description) to verify bug-fix PRs include end-to-end regression test coverage. Pass if: (1) PR title and commit subjects don't use bug-fix language (fix, fixed, fixes, fixing, bugfix, hotfix), OR (2) PR changes at least one file under browser_tests/, OR (3) PR description includes concrete non-placeholder explanation for why end-to-end regression test wasn't added. Fail otherwise, mentioning the bug-fix signal found and asking to add/update Playwright regression test under browser_tests/ or provide concrete explanation in PR description.

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-03-27T04:23:01.330Z
Learning: End-to-end regression coverage for fixes: For PRs that include bug-fix language in the title or commit subjects (fix, fixed, fixes, fixing, bugfix, hotfix), ensure at least one of the following: (1) files are changed under browser_tests/, or (2) the PR description includes a concrete, non-placeholder explanation of why an end-to-end regression test was not added. Only use PR metadata available in the review context (PR title, commit subjects, files changed relative to base, PR description). Do not rely on shell commands, reverse diffs, or files outside the PR.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 8951
File: src/platform/workflow/management/stores/workflowStore.ts:301-301
Timestamp: 2026-03-05T23:21:47.113Z
Learning: In src/platform/workflow/management/stores/workflowStore.ts, `createTemporary()` and `createNewTemporary()` intentionally inject a UUID `id` into workflow data via `ensureWorkflowId()` to give workflows stable identity for sharing. This is a known behavioral change introduced in PR `#8951`. Extensions relying on serialized content matching their input may be silently affected.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7415
File: browser_tests/tests/mobileBaseline.spec.ts:7-15
Timestamp: 2025-12-13T05:34:15.488Z
Learning: In Playwright tests for the ComfyUI frontend, the toPass() assertion uses incremental backoff during retries. When a test may involve async operations, increasing the timeout (e.g., to 5000 ms) can be sufficient instead of aggressively extending timeouts. Apply this understanding to tests under browser_tests/tests/; if not resolved, review the toPass() backoff behavior and ensure timeouts align with expected async completion without masking issues.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8248
File: src/platform/assets/schemas/assetSchema.ts:109-118
Timestamp: 2026-01-22T23:44:59.888Z
Learning: Do not export declarations (e.g., schemas, constants, types) unless they are actually used elsewhere in the codebase. Keep the public API surface minimal by exporting only items with concrete usage. This reduces coupling and keeps imports explicit. In src/platform/assets/schemas/assetSchema.ts, ensure only necessary exports are exposed; remove unused exports or switch to non-exported/internal where appropriate.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8722
File: src/composables/maskeditor/useBrushDrawing.ts:5-5
Timestamp: 2026-02-08T03:19:12.009Z
Learning: Treat unresolved import warnings caused by pnpm workspace catalog mappings (pnpm-workspace.yaml) and unplugin-typegpu in vite.config.mts as false positives. Do not flag these in PR reviews; they are expected in sandboxes without node_modules and are not indicative of actual missing dependencies in the TS codebase.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 8966
File: src/extensions/core/load3d.ts:427-430
Timestamp: 2026-02-19T02:06:23.468Z
Learning: In TypeScript, you can use typeof SomeClass in type annotation positions (e.g., param: typeof LGraphNode) even when SomeClass is imported with import type. This is a type query that only exists at compile time and is erased in runtime, so it is safe to combine with type-only imports. Apply this pattern to TS files broadly when you need a type that references the shape of a class or constructor function without importing the value at runtime.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 8966
File: src/extensions/core/uploadAudio.ts:91-94
Timestamp: 2026-02-19T02:06:38.395Z
Learning: In TypeScript files, you can use a type annotation like 'nodeType: typeof MyClass' even if MyClass is imported via 'import type'. Both the type-only import and 'typeof' operate at the type level and are erased at compile time. This pattern is commonly used for constructor types (e.g., 'nodeType: typeof LGraphNode'). Apply this pattern across TypeScript files in the repository (src/**/*.ts) as appropriate, ensuring the imported symbol is a type-only import when possible for clarity and to avoid runtime imports.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8992
File: src/lib/litegraph/src/widgets/GradientSliderWidget.ts:18-18
Timestamp: 2026-02-20T21:08:19.814Z
Learning: When drawing with CanvasRenderingContext2D in TypeScript/JavaScript, wrap the drawing logic with ctx.save() at the start and ctx.restore() at the end to preserve and restore the canvas state. Do not manually destructure and restore individual properties (e.g., fillStyle, strokeStyle); rely on save/restore to manage state changes in a scoped manner. This should be applied to all TS files that perform canvas drawing.

Learnt from: dante01yoon
Repo: Comfy-Org/ComfyUI_frontend PR: 9075
File: src/scripts/api.featureFlags.test.ts:237-268
Timestamp: 2026-02-22T04:27:33.379Z
Learning: In Vite/Vitest, import.meta.env.DEV is true for any mode that is not 'production' (i.e., DEV is the opposite of PROD, and can be true in 'test', 'development', etc.). Do not assume DEV implies only 'development' mode. When reviewing code and tests, treat DEV as a non-production flag and verify environment-specific logic accordingly. Reference: https://vite.dev/guide/env-and-mode#modes

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 9427
File: src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownMenuFilter.vue:33-33
Timestamp: 2026-03-06T00:53:28.835Z
Learning: When reviewing code, note that the enforce-canonical-classes (better-tailwindcss) rule may auto-fix Tailwind v3 !class-name syntax by converting it to v4 class-name! syntax. Do not treat these auto-fixed class-name! instances as newly introduced issues; the perceived change is in syntax placement, not in usage or intent. This guidance applies across all .vue and .ts files in the repository.

Learnt from: sonnybox
Repo: Comfy-Org/ComfyUI_frontend PR: 9446
File: src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue:45-45
Timestamp: 2026-03-06T01:55:00.013Z
Learning: Treat wrap-break-word as a valid Tailwind CSS utility for overflow-wrap: break-word in Tailwind v4+ projects. Do not flag this class as invalid in any Vue (.vue) or TypeScript (.ts/.tsx) files within the repository (e.g., Comfy-Org/ComfyUI_frontend) or other Tailwind v4+ projects. When reviewing, verify that the class is used to enable word breaking in long text content and reference the Tailwind docs: https://tailwindcss.com/docs/overflow-wrap.

Learnt from: Yourz
Repo: Comfy-Org/ComfyUI_frontend PR: 10310
File: browser_tests/tests/topbarMenuDismissal.spec.ts:0-0
Timestamp: 2026-03-19T16:16:40.350Z
Learning: In Comfy-Org/ComfyUI_frontend, when reviewing changes limited to adding/revising `:modal="false"` (or similar modal/non-modal behavior props) on reakit-ui/reka-ui primitives such as `ContextMenuRoot` and `DropdownMenuRoot`, do not request Playwright/E2E regression coverage solely for that prop-level change. The dismissal behavior for modal vs non-modal is documented and tested upstream in the reka-ui library; only ask for E2E tests when the change affects ComfyUI_frontend behavior beyond these primitive prop wiring differences (e.g., custom logic, integration behavior, or new user flows not covered upstream).

Learnt from: jaeone94
Repo: Comfy-Org/ComfyUI_frontend PR: 10302
File: browser_tests/tests/dialog.spec.ts:31-32
Timestamp: 2026-03-22T14:21:45.793Z
Learning: In E2E tests, when asserting errors rendered by `ErrorOverlay.vue` (container has `data-testid="error-overlay"`), do not use `TestIds.dialogs.missingNodePacksGroup` (`error-group-missing-node`) or `TestIds.dialogs.missingModelsGroup` (`error-group-missing-model`)—those test IDs are rendered on `PropertiesAccordionItem` elements inside `TabErrors.vue`, not inside the overlay. For overlay-level assertions, scope queries to the overlay container and assert using the visible text (e.g., `errorOverlay.getByText(/Missing Node Packs/)`) rather than `getByTestId`.

Learnt from: viva-jinyi
Repo: Comfy-Org/ComfyUI_frontend PR: 10499
File: browser_tests/tests/vueNodes/widgets/load/formDropdownPosition.spec.ts:55-59
Timestamp: 2026-03-25T03:30:28.527Z
Learning: In Comfy-Org/ComfyUI_frontend browser tests, follow the established canvas zoom convention: set zoom in tests using direct assignment `canvas.ds.scale = s` (as used by `browser_tests/fixtures/helpers/CanvasHelper.ts` in `CanvasHelper.setScale()`). Do not recommend switching to `canvas.ds.changeScale()` in spec files when the test re-queries element positions using Playwright `boundingBox()`, since boundingBox coordinates are already in the post-transform viewport space and any offset recalculation associated with `changeScale()` is not relevant there.

Learnt from: jtydhr88
Repo: Comfy-Org/ComfyUI_frontend PR: 10574
File: browser_tests/tests/maskEditor.spec.ts:70-75
Timestamp: 2026-03-26T23:45:21.231Z
Learning: In Comfy-Org/ComfyUI_frontend browser tests, only use `dispatchEvent('contextmenu', { bubbles: true, cancelable: true, button: 2 })` when the ComfyUI canvas z-999 overlay is intercepting pointer events on canvas-level DOM widgets. Vue-rendered elements (e.g., selectors like `.lg-node-header`) are not occluded by the canvas overlay—so for those, follow the established pattern used in `imagePreview.spec.ts`: click to select with `locator.click()` (left click), then trigger the context menu with `locator.click({ button: 'right' })`.

Also, ensure you’re using the correct Playwright API: `getNodeLocator()` returns a Playwright `Locator` (not a NodeReference). Therefore, `Locator.click('title')` is invalid syntax—if you need to click a string part of a node, only `NodeReference.click('title')` supports the string part argument.

Learnt from: dante01yoon
Repo: Comfy-Org/ComfyUI_frontend PR: 10580
File: browser_tests/tests/sidebar/textSizeRename.spec.ts:20-20
Timestamp: 2026-03-27T13:58:46.129Z
Learning: In ComfyUI_frontend browser tests, when selecting the element with test id `node-tree-leaf`, use `getByTestId('node-tree-leaf')` with the raw string even if `node-tree-leaf` is intentionally NOT present in the centralized `TestIds` (see `browser_tests/fixtures/selectors.ts`). Do not flag this as a violation of the centralized `TestIds` guideline for this specific test id.

.workflow.activeWorkflow
if (!workflow) throw new Error('No workflow found')
// Bypass the guard to reproduce the corruption bug:
// ; (workflow.changeTracker.constructor as unknown as { isLoadingGraph: boolean }).isLoadingGraph = false
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

question (non-blocking): What does this mean exactly?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

In order to recreate the issue, uncommenting the line of code removes the guard, triggering the workflow overwrite on tab switch

@pythongosssss pythongosssss merged commit dabfc65 into main Mar 27, 2026
39 checks passed
@pythongosssss pythongosssss deleted the pysssss/test/switching-tab-regression-test branch March 27, 2026 18:54
christian-byrne pushed a commit that referenced this pull request Mar 28, 2026
…aph loading (#10623)

## Summary

Adds regression test for
#9531

## Changes

- **What**:  
- registers extension that triggers checkState during
afterConfigureGraph (at this point the workflow data and active graph
are not in sync), previously causing it to overwrite the workflow data
- switches between tabs
- ensures they are not corrupted

Line 35 can be uncommented to cause the test to fail by clearing the
isLoadingGraph flag

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10623-test-Add-test-to-prevent-regression-of-workflow-corruption-during-graph-loading-3306d73d3650815fbf02ef23dfdcddce)
by [Unito](https://www.unito.io)
christian-byrne pushed a commit that referenced this pull request Mar 28, 2026
…aph loading (#10623)

## Summary

Adds regression test for
#9531

## Changes

- **What**:  
- registers extension that triggers checkState during
afterConfigureGraph (at this point the workflow data and active graph
are not in sync), previously causing it to overwrite the workflow data
- switches between tabs
- ensures they are not corrupted

Line 35 can be uncommented to cause the test to fail by clearing the
isLoadingGraph flag

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10623-test-Add-test-to-prevent-regression-of-workflow-corruption-during-graph-loading-3306d73d3650815fbf02ef23dfdcddce)
by [Unito](https://www.unito.io)
christian-byrne added a commit that referenced this pull request Mar 29, 2026
- Remove module-level comment block
- Rename describe to 'Workflow Persistence'
- Remove redundant UseNewMenu setting (already default in fixture)
- Replace JSDoc PR references with Playwright test.info().annotations
- Remove duplicate G1 tests (covered by merged PR #10623)
- Use waitForWorkflowIdle() helper instead of inline isBusy patterns
- Move API workflow JSON to fixtures/assets
- Reduce excessive comments throughout
- Consolidate localStorage patterns

Addresses review feedback:
#10547 (comment)
#10547 (comment)
#10547 (comment)
#10547 (comment)
#10547 (comment)
#10547 (comment)
#10547 (comment)
#10547 (comment)
#10547 (comment)
#10547 (comment)
#10547 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants