Skip to content

test: add unit tests for commandStore, extensionStore, widgetStore (STORE-04)#10647

Open
christian-byrne wants to merge 5 commits intomainfrom
test/priority-store-tests
Open

test: add unit tests for commandStore, extensionStore, widgetStore (STORE-04)#10647
christian-byrne wants to merge 5 commits intomainfrom
test/priority-store-tests

Conversation

@christian-byrne
Copy link
Copy Markdown
Contributor

@christian-byrne christian-byrne commented Mar 28, 2026

Summary

Adds 43 unit tests covering three priority Pinia stores that previously had zero test coverage.

commandStore (18 tests)

  • registerCommand / registerCommands — single and batch registration, duplicate warning
  • getCommand — retrieval and undefined for missing
  • execute — successful execution, metadata passing, error handler delegation, missing command error
  • isRegistered — presence check
  • loadExtensionCommands — extension command registration with source, skip when no commands
  • ComfyCommandImpl — label/icon/tooltip resolution (string vs function), menubarLabel defaulting

extensionStore (16 tests)

  • registerExtension — name validation, duplicate detection, disabled extension warning
  • isExtensionEnabled / loadDisabledExtensionNames — enable/disable lifecycle
  • Always-disabled hardcoded extensions (pysssss.Locking, pysssss.SnapToGrid, pysssss.FaviconStatus, KJNodes.browserstatus)
  • enabledExtensions — computed filter
  • isExtensionReadOnly — hardcoded list check
  • inactiveDisabledExtensionNames — ghost extension tracking
  • Core extension capture and hasThirdPartyExtensions detection

widgetStore (9 tests)

  • Core widget availability via ComfyWidgets
  • Custom widget registration and core/custom precedence
  • inputIsWidget for both v1 array and v2 object InputSpec formats

Part of

Test Coverage Q2 Overhaul — Phase 5 (Unit & Component Tests)

┆Issue is synchronized with this Notion page by Unito

…TORE-04)

commandStore (18 tests): registerCommand, registerCommands, getCommand,
execute with metadata/errorHandler, isRegistered, loadExtensionCommands,
ComfyCommandImpl label/icon/menubarLabel resolution

extensionStore (16 tests): registerExtension with validation,
enable/disable lifecycle, always-disabled hardcoded extensions,
enabledExtensions filter, isExtensionReadOnly, inactive disabled tracking,
core extension capture and third-party detection

widgetStore (9 tests): core widget availability, custom widget registration,
core/custom precedence, inputIsWidget for v1 and v2 InputSpec formats
@christian-byrne christian-byrne requested a review from a team March 28, 2026 05:04
@christian-byrne christian-byrne added the New Browser Test Expectations New browser test screenshot should be set by github action label Mar 28, 2026
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Mar 28, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 28, 2026

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 03/29/2026, 02:31:57 AM UTC

Links

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 28, 2026

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

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 28, 2026

📝 Walkthrough

Walkthrough

Adds three new Vitest test suites for Pinia stores: commandStore, extensionStore, and widgetStore, covering registration, getters, execution flows, enablement/disablement logic, and widget input detection with mocked dependencies.

Changes

Cohort / File(s) Summary
Command Store Tests
src/stores/commandStore.test.ts
New tests for useCommandStore: command registration (registerCommand, registerCommands), duplicate registration warning, retrieval (getCommand, isRegistered, commands), execution (execute success/failure, metadata passing, errorHandler invocation), loadExtensionCommands, and ComfyCommandImpl label/icon/menubarLabel resolution.
Extension Store Tests
src/stores/extensionStore.test.ts
New tests for useExtensionStore: registerExtension validation and duplicate handling, loadDisabledExtensionNames behavior (including warnings), extensions/enabledExtensions/inactiveDisabledExtensionNames getters, isExtensionInstalled/isExtensionEnabled/isExtensionReadOnly, captureCoreExtensions, and hasThirdPartyExtensions.
Widget Store Tests
src/stores/widgetStore.test.ts
New tests for useWidgetStore: verifies core widget keys, registerCustomWidgets (single and batch), core entries overriding custom registrations, and inputIsWidget detection for v1 (tuple-style) and v2 (object-style) input specs using mocked widget factories and schema helper.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I hopped through tests with nibbling cheer,

Commands registered, extensions near,
Widgets mocked in cozy den,
Assertions lined like carrot pens,
A happy rabbit hops again.


Caution

Pre-merge checks failed

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

  • Ignore (reviewers only)

❌ Failed checks (1 error)

Check name Status Explanation Resolution
End-To-End Regression Coverage For Fixes ❌ Error PR contains bug-fix commits but lacks browser_tests/ files and concrete e2e regression test justification in description. Add Playwright regression tests under browser_tests/ directory or provide explicit explanation in PR description for why e2e tests are not needed.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding unit tests for three Pinia stores (commandStore, extensionStore, widgetStore) with a reference to the tracking issue STORE-04.
Description check ✅ Passed The description is comprehensive and mostly complete, covering all required sections: Summary, Changes (with What, Breaking, Dependencies where applicable), and Review Focus.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Adr Compliance For Entity/Litegraph Changes ✅ Passed PR modifies only test files in src/stores/ directory, not src/lib/litegraph/, src/ecs/, or graph entity files.
✨ 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 test/priority-store-tests

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

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 28, 2026

📦 Bundle: 5.09 MB gzip 🟢 -301 B

Details

Summary

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

Category Glance
Vendor & Third-Party ⚪ 0 B (9.8 MB) · Other ⚪ 0 B (8.43 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-Bm1ksAsC.js (removed) 22.3 kB 🟢 -22.3 kB 🟢 -7.94 kB 🟢 -6.8 kB
assets/index-DcuoCqXP.js (new) 22.3 kB 🔴 +22.3 kB 🔴 +7.93 kB 🔴 +6.82 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-D6IsfL5V.js (removed) 1.14 MB 🟢 -1.14 MB 🟢 -244 kB 🟢 -184 kB
assets/GraphView-ZN7HYUqP.js (new) 1.14 MB 🔴 +1.14 MB 🔴 +244 kB 🔴 +184 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-BZPJgTuM.js (new) 15.7 kB 🔴 +15.7 kB 🔴 +3.4 kB 🔴 +2.9 kB
assets/CloudSurveyView-Df5lrWEB.js (removed) 15.7 kB 🟢 -15.7 kB 🟢 -3.39 kB 🟢 -2.9 kB
assets/CloudLoginView-CxAVztDy.js (new) 12 kB 🔴 +12 kB 🔴 +3.35 kB 🔴 +2.97 kB
assets/CloudLoginView-Dx1QNKpy.js (removed) 12 kB 🟢 -12 kB 🟢 -3.36 kB 🟢 -2.96 kB
assets/CloudSignupView-B8XVkY5u.js (new) 9.78 kB 🔴 +9.78 kB 🔴 +2.85 kB 🔴 +2.5 kB
assets/CloudSignupView-C8U3ZvQy.js (removed) 9.78 kB 🟢 -9.78 kB 🟢 -2.85 kB 🟢 -2.5 kB
assets/UserCheckView-CmEVYhxr.js (removed) 9.04 kB 🟢 -9.04 kB 🟢 -2.33 kB 🟢 -2.03 kB
assets/UserCheckView-MppfXAvS.js (new) 9.04 kB 🔴 +9.04 kB 🔴 +2.33 kB 🔴 +2.03 kB
assets/CloudLayoutView-BNIJHd_T.js (new) 7.54 kB 🔴 +7.54 kB 🔴 +2.36 kB 🔴 +2.04 kB
assets/CloudLayoutView-zsOlRhk4.js (removed) 7.54 kB 🟢 -7.54 kB 🟢 -2.36 kB 🟢 -2.06 kB
assets/CloudForgotPasswordView-CvHsNcyG.js (new) 5.94 kB 🔴 +5.94 kB 🔴 +2.09 kB 🔴 +1.84 kB
assets/CloudForgotPasswordView-TOgarXpN.js (removed) 5.94 kB 🟢 -5.94 kB 🟢 -2.1 kB 🟢 -1.86 kB
assets/CloudAuthTimeoutView-BVXiMrv_.js (new) 5.31 kB 🔴 +5.31 kB 🔴 +1.93 kB 🔴 +1.7 kB
assets/CloudAuthTimeoutView-CIsSgCrT.js (removed) 5.31 kB 🟢 -5.31 kB 🟢 -1.93 kB 🟢 -1.7 kB
assets/CloudSubscriptionRedirectView-Ce5gjO4f.js (new) 5.08 kB 🔴 +5.08 kB 🔴 +1.91 kB 🔴 +1.69 kB
assets/CloudSubscriptionRedirectView-DYS69PEN.js (removed) 5.08 kB 🟢 -5.08 kB 🟢 -1.91 kB 🟢 -1.69 kB
assets/UserSelectView-CYs6vMEY.js (new) 4.71 kB 🔴 +4.71 kB 🔴 +1.74 kB 🔴 +1.55 kB
assets/UserSelectView-D1wJMZPN.js (removed) 4.71 kB 🟢 -4.71 kB 🟢 -1.74 kB 🟢 -1.55 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-B5D1Hl3-.js (new) 46.6 kB 🔴 +46.6 kB 🔴 +9.52 kB 🔴 +8.46 kB
assets/KeybindingPanel-CSAMSx2l.js (removed) 46.6 kB 🟢 -46.6 kB 🟢 -9.52 kB 🟢 -8.47 kB
assets/SecretsPanel-C1EAi8i7.js (new) 22.4 kB 🔴 +22.4 kB 🔴 +5.42 kB 🔴 +4.76 kB
assets/SecretsPanel-CcjFEI7y.js (removed) 22.4 kB 🟢 -22.4 kB 🟢 -5.42 kB 🟢 -4.76 kB
assets/LegacyCreditsPanel-Dyzz9lpB.js (new) 21.5 kB 🔴 +21.5 kB 🔴 +5.81 kB 🔴 +5.13 kB
assets/LegacyCreditsPanel-PeeAs3db.js (removed) 21.5 kB 🟢 -21.5 kB 🟢 -5.81 kB 🟢 -5.13 kB
assets/SubscriptionPanel-5ZuANZCW.js (removed) 19.7 kB 🟢 -19.7 kB 🟢 -5.01 kB 🟢 -4.4 kB
assets/SubscriptionPanel-B8k0DGEg.js (new) 19.7 kB 🔴 +19.7 kB 🔴 +5.01 kB 🔴 +4.41 kB
assets/AboutPanel-B_LogIP4.js (new) 12 kB 🔴 +12 kB 🔴 +3.33 kB 🔴 +2.98 kB
assets/AboutPanel-BzLAtOPT.js (removed) 12 kB 🟢 -12 kB 🟢 -3.33 kB 🟢 -2.98 kB
assets/ExtensionPanel-1hMsJxH5.js (removed) 9.78 kB 🟢 -9.78 kB 🟢 -2.82 kB 🟢 -2.49 kB
assets/ExtensionPanel-CTq5f3JU.js (new) 9.78 kB 🔴 +9.78 kB 🔴 +2.82 kB 🔴 +2.5 kB
assets/ServerConfigPanel-Bqb-Tx4w.js (removed) 6.85 kB 🟢 -6.85 kB 🟢 -2.28 kB 🟢 -2.01 kB
assets/ServerConfigPanel-CS_XhKR2.js (new) 6.85 kB 🔴 +6.85 kB 🔴 +2.27 kB 🔴 +2.06 kB
assets/UserPanel-BEcHVHAl.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -2.16 kB 🟢 -1.89 kB
assets/UserPanel-gvVPpNuL.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +2.15 kB 🔴 +1.9 kB
assets/cloudRemoteConfig-8PgQOi5_.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +902 B 🔴 +799 B
assets/cloudRemoteConfig-CjHlnu8j.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -906 B 🟢 -804 B
assets/refreshRemoteConfig-Dg6a82qN.js (removed) 1.45 kB 🟢 -1.45 kB 🟢 -652 B 🟢 -555 B
assets/refreshRemoteConfig-dnIzne0U.js (new) 1.45 kB 🔴 +1.45 kB 🔴 +648 B 🔴 +556 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-BIJrRd6R.js (new) 3.57 kB 🔴 +3.57 kB 🔴 +1.26 kB 🔴 +1.08 kB
assets/auth-Bpx_VidV.js (removed) 3.57 kB 🟢 -3.57 kB 🟢 -1.26 kB 🟢 -1.08 kB
assets/SignUpForm-3bgB01eU.js (new) 3.16 kB 🔴 +3.16 kB 🔴 +1.28 kB 🔴 +1.14 kB
assets/SignUpForm-Dv4no_i4.js (removed) 3.16 kB 🟢 -3.16 kB 🟢 -1.28 kB 🟢 -1.14 kB
assets/UpdatePasswordContent-BtHlN98Z.js (new) 2.66 kB 🔴 +2.66 kB 🔴 +1.19 kB 🔴 +1.05 kB
assets/UpdatePasswordContent-DzXugo9M.js (removed) 2.66 kB 🟢 -2.66 kB 🟢 -1.19 kB 🟢 -1.06 kB
assets/authStore-Br2XSEkl.js (removed) 989 B 🟢 -989 B 🟢 -485 B 🟢 -426 B
assets/authStore-Dj1Szji5.js (new) 989 B 🔴 +989 B 🔴 +481 B 🔴 +423 B
assets/auth-b_D67FDb.js (removed) 348 B 🟢 -348 B 🟢 -215 B 🟢 -189 B
assets/auth-h0jzhY0p.js (new) 348 B 🔴 +348 B 🔴 +216 B 🔴 +190 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-CqnPo4jJ.js (new) 108 kB 🔴 +108 kB 🔴 +22.4 kB 🔴 +18.9 kB
assets/useShareDialog-U06n_wXz.js (removed) 108 kB 🟢 -108 kB 🟢 -22.4 kB 🟢 -18.9 kB
assets/useSubscriptionDialog-D4shhmZN.js (new) 969 B 🔴 +969 B 🔴 +474 B 🔴 +415 B
assets/useSubscriptionDialog-DMgxyKOu.js (removed) 969 B 🟢 -969 B 🟢 -479 B 🟢 -419 B

Status: 2 added / 2 removed

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-BHHMxMik.js (new) 13.5 kB 🔴 +13.5 kB 🔴 +3.79 kB 🔴 +3.38 kB
assets/ComfyQueueButton-BPgyRu84.js (removed) 13.5 kB 🟢 -13.5 kB 🟢 -3.79 kB 🟢 -3.38 kB
assets/useTerminalTabs-BQcHV9ft.js (removed) 10.7 kB 🟢 -10.7 kB 🟢 -3.6 kB 🟢 -3.16 kB
assets/useTerminalTabs-EZ8kkOyI.js (new) 10.7 kB 🔴 +10.7 kB 🔴 +3.6 kB 🔴 +3.17 kB
assets/SubscribeButton-BfKGFKsf.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.04 kB 🔴 +913 B
assets/SubscribeButton-CiFNOX2P.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.04 kB 🟢 -914 B
assets/cloudFeedbackTopbarButton-C7XkSW5a.js (removed) 1.66 kB 🟢 -1.66 kB 🟢 -846 B 🟢 -748 B
assets/cloudFeedbackTopbarButton-Cn_80KNB.js (new) 1.66 kB 🔴 +1.66 kB 🔴 +840 B 🔴 +770 B
assets/ComfyQueueButton-BeCw_n1i.js (new) 1.03 kB 🔴 +1.03 kB 🔴 +487 B 🔴 +434 B
assets/ComfyQueueButton-C-AGhe9x.js (removed) 1.03 kB 🟢 -1.03 kB 🟢 -492 B 🟢 -438 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-Abt5Gdz_.js (removed) 1.92 MB 🟢 -1.92 MB 🟢 -443 kB 🟢 -336 kB
assets/dialogService-C6_HJrdO.js (new) 1.92 MB 🔴 +1.92 MB 🔴 +443 kB 🔴 +336 kB
assets/api-DOEr8wXN.js (new) 885 kB 🔴 +885 kB 🔴 +211 kB 🔴 +167 kB
assets/api-DoYVVQ7P.js (removed) 885 kB 🟢 -885 kB 🟢 -211 kB 🟢 -167 kB
assets/load3dService-CfbakWyf.js (new) 92.5 kB 🔴 +92.5 kB 🔴 +19.7 kB 🔴 +17 kB
assets/load3dService-CSM_7Qak.js (removed) 92.5 kB 🟢 -92.5 kB 🟢 -19.7 kB 🟢 -16.9 kB
assets/workflowShareService-B3Utiz0R.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.88 kB 🟢 -4.32 kB
assets/workflowShareService-DVyGstLz.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.88 kB 🔴 +4.32 kB
assets/keybindingService-BcKLIhRn.js (removed) 13.8 kB 🟢 -13.8 kB 🟢 -3.67 kB 🟢 -3.21 kB
assets/keybindingService-CdedTlcu.js (new) 13.8 kB 🔴 +13.8 kB 🔴 +3.66 kB 🔴 +3.21 kB
assets/releaseStore-Cp1Q3lGs.js (removed) 8.12 kB 🟢 -8.12 kB 🟢 -2.28 kB 🟢 -2 kB
assets/releaseStore-sFTox25y.js (new) 8.12 kB 🔴 +8.12 kB 🔴 +2.28 kB 🔴 +2 kB
assets/userStore-DcUCd2hh.js (new) 2.24 kB 🔴 +2.24 kB 🔴 +870 B 🔴 +761 B
assets/userStore-DHWWce0C.js (removed) 2.24 kB 🟢 -2.24 kB 🟢 -871 B 🟢 -766 B
assets/audioService-Dy0dYvYG.js (removed) 1.8 kB 🟢 -1.8 kB 🟢 -879 B 🟢 -763 B
assets/audioService-lgh5SF6E.js (new) 1.8 kB 🔴 +1.8 kB 🔴 +878 B 🔴 +765 B
assets/releaseStore-CBt1vodK.js (new) 993 B 🔴 +993 B 🔴 +479 B 🔴 +426 B
assets/releaseStore-CJb-953H.js (removed) 993 B 🟢 -993 B 🟢 -483 B 🟢 -427 B
assets/workflowDraftStore-BAWWRVm1.js (removed) 969 B 🟢 -969 B 🟢 -478 B 🟢 -426 B
assets/workflowDraftStore-DxISCpVT.js (new) 969 B 🔴 +969 B 🔴 +473 B 🔴 +420 B
assets/dialogService-B2KX4QQ_.js (new) 958 B 🔴 +958 B 🔴 +466 B 🔴 +412 B
assets/dialogService-CSxSZMHB.js (removed) 958 B 🟢 -958 B 🟢 -470 B 🟢 -415 B
assets/settingStore-BOfHIl9H.js (new) 956 B 🔴 +956 B 🔴 +469 B 🔴 +410 B
assets/settingStore-W3div-Ao.js (removed) 956 B 🟢 -956 B 🟢 -474 B 🟢 -411 B
assets/assetsStore-BP-5vL8A.js (new) 955 B 🔴 +955 B 🔴 +469 B 🔴 +412 B
assets/assetsStore-CZF2Tzix.js (removed) 955 B 🟢 -955 B 🟢 -474 B 🟢 -417 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-b20FZTw1.js (new) 232 kB 🔴 +232 kB 🔴 +51.3 kB 🔴 +41.8 kB
assets/useConflictDetection-Foe7rxoF.js (removed) 232 kB 🟢 -232 kB 🟢 -51.3 kB 🟢 -41.7 kB
assets/useLoad3dViewer-9z5vP8hd.js (new) 18.7 kB 🔴 +18.7 kB 🔴 +4.44 kB 🔴 +3.9 kB
assets/useLoad3dViewer-BAZ2CK-a.js (removed) 18.7 kB 🟢 -18.7 kB 🟢 -4.44 kB 🟢 -3.9 kB
assets/useLoad3d-BE2Jchtc.js (new) 15 kB 🔴 +15 kB 🔴 +3.79 kB 🔴 +3.35 kB
assets/useLoad3d-YYxDBVq9.js (removed) 15 kB 🟢 -15 kB 🟢 -3.79 kB 🟢 -3.37 kB
assets/useFeatureFlags-BgcEDWFw.js (new) 5.78 kB 🔴 +5.78 kB 🔴 +1.75 kB 🔴 +1.48 kB
assets/useFeatureFlags-BJBC7u7T.js (removed) 5.78 kB 🟢 -5.78 kB 🟢 -1.75 kB 🟢 -1.49 kB
assets/useCopyToClipboard-1rJWlQw7.js (new) 5.29 kB 🔴 +5.29 kB 🔴 +1.86 kB 🔴 +1.57 kB
assets/useCopyToClipboard-Cn_QnZZU.js (removed) 5.29 kB 🟢 -5.29 kB 🟢 -1.86 kB 🟢 -1.57 kB
assets/useWorkspaceUI-B8CBm3Iw.js (removed) 3.34 kB 🟢 -3.34 kB 🟢 -981 B 🟢 -809 B
assets/useWorkspaceUI-CUC84F2Y.js (new) 3.34 kB 🔴 +3.34 kB 🔴 +982 B 🔴 +812 B
assets/subscriptionCheckoutUtil-CWlAIVWk.js (new) 2.97 kB 🔴 +2.97 kB 🔴 +1.31 kB 🔴 +1.14 kB
assets/subscriptionCheckoutUtil-Tqx9RiK5.js (removed) 2.97 kB 🟢 -2.97 kB 🟢 -1.31 kB 🟢 -1.14 kB
assets/assetPreviewUtil-C6QjwWoH.js (new) 2.27 kB 🔴 +2.27 kB 🔴 +960 B 🔴 +834 B
assets/assetPreviewUtil-DXsuRbk-.js (removed) 2.27 kB 🟢 -2.27 kB 🟢 -959 B 🟢 -834 B
assets/useUpstreamValue-DLRTd01u.js (removed) 2.08 kB 🟢 -2.08 kB 🟢 -806 B 🟢 -724 B
assets/useUpstreamValue-Dt3UkXAD.js (new) 2.08 kB 🔴 +2.08 kB 🔴 +806 B 🔴 +719 B
assets/useLoad3d-BIcxxX2-.js (removed) 1.13 kB 🟢 -1.13 kB 🟢 -544 B 🟢 -482 B
assets/useLoad3d-CyAyUvUb.js (new) 1.13 kB 🔴 +1.13 kB 🔴 +537 B 🔴 +479 B
assets/useLoad3dViewer-xDvFsZM4.js (new) 1.07 kB 🔴 +1.07 kB 🔴 +505 B 🔴 +451 B
assets/useLoad3dViewer-XqDLLDex.js (removed) 1.07 kB 🟢 -1.07 kB 🟢 -510 B 🟢 -456 B
assets/useCurrentUser-_vUDEFnT.js (removed) 955 B 🟢 -955 B 🟢 -474 B 🟢 -418 B
assets/useCurrentUser-CY52O6sj.js (new) 955 B 🔴 +955 B 🔴 +469 B 🔴 +416 B
assets/useWorkspaceSwitch-C3N2CtHy.js (new) 747 B 🔴 +747 B 🔴 +388 B 🔴 +332 B
assets/useWorkspaceSwitch-vfqiYP8a.js (removed) 747 B 🟢 -747 B 🟢 -388 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.43 MB (baseline 8.43 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-DeWEbTWJ.js (new) 76.8 kB 🔴 +76.8 kB 🔴 +19.9 kB 🔴 +17 kB
assets/core-DJGCtI5S.js (removed) 76.8 kB 🟢 -76.8 kB 🟢 -19.9 kB 🟢 -16.9 kB
assets/groupNode-Dofy0xHv.js (new) 74 kB 🔴 +74 kB 🔴 +18.5 kB 🔴 +16.3 kB
assets/groupNode-DTq9qJHc.js (removed) 74 kB 🟢 -74 kB 🟢 -18.5 kB 🟢 -16.3 kB
assets/WidgetSelect-C1MILB0Z.js (removed) 64.6 kB 🟢 -64.6 kB 🟢 -14.1 kB 🟢 -12.2 kB
assets/WidgetSelect-Cd44p4hb.js (new) 64.6 kB 🔴 +64.6 kB 🔴 +14.1 kB 🔴 +12.2 kB
assets/SubscriptionRequiredDialogContentWorkspace-CpmKkZrj.js (new) 48.9 kB 🔴 +48.9 kB 🔴 +9.29 kB 🔴 +7.94 kB
assets/SubscriptionRequiredDialogContentWorkspace-DnucMMdN.js (removed) 48.9 kB 🟢 -48.9 kB 🟢 -9.29 kB 🟢 -7.93 kB
assets/WidgetPainter-ByCAvFj0.js (new) 33.3 kB 🔴 +33.3 kB 🔴 +8.11 kB 🔴 +7.19 kB
assets/WidgetPainter-gfXpk8X-.js (removed) 33.3 kB 🟢 -33.3 kB 🟢 -8.11 kB 🟢 -7.2 kB
assets/Load3DControls-CqnRWwfZ.js (new) 32.1 kB 🔴 +32.1 kB 🔴 +5.47 kB 🔴 +4.76 kB
assets/Load3DControls-mOU0rkhS.js (removed) 32.1 kB 🟢 -32.1 kB 🟢 -5.47 kB 🟢 -4.77 kB
assets/WorkspacePanelContent-DnqsHGud.js (removed) 29.9 kB 🟢 -29.9 kB 🟢 -6.33 kB 🟢 -5.54 kB
assets/WorkspacePanelContent-G7w-fE-S.js (new) 29.9 kB 🔴 +29.9 kB 🔴 +6.33 kB 🔴 +5.56 kB
assets/SubscriptionRequiredDialogContent-CRFffdZu.js (removed) 28.2 kB 🟢 -28.2 kB 🟢 -7.16 kB 🟢 -6.3 kB
assets/SubscriptionRequiredDialogContent-DS0KNw17.js (new) 28.2 kB 🔴 +28.2 kB 🔴 +7.17 kB 🔴 +6.31 kB
assets/Load3dViewerContent-BJAQEiFk.js (new) 24.3 kB 🔴 +24.3 kB 🔴 +5.32 kB 🔴 +4.63 kB
assets/Load3dViewerContent-C0OaDIM-.js (removed) 24.3 kB 🟢 -24.3 kB 🟢 -5.32 kB 🟢 -4.63 kB
assets/WidgetImageCrop-BBH6kv-m.js (removed) 23.3 kB 🟢 -23.3 kB 🟢 -5.83 kB 🟢 -5.14 kB
assets/WidgetImageCrop-BQDdlUpY.js (new) 23.3 kB 🔴 +23.3 kB 🔴 +5.82 kB 🔴 +5.15 kB
assets/SubscriptionPanelContentWorkspace-BhrMREbT.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -5.18 kB 🟢 -4.55 kB
assets/SubscriptionPanelContentWorkspace-Dmk4wMMc.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +5.18 kB 🔴 +4.56 kB
assets/SignInContent-Cq7gjqy-.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.29 kB 🟢 -4.63 kB
assets/SignInContent-DpYUMbve.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.29 kB 🔴 +4.63 kB
assets/CurrentUserPopoverWorkspace-0QRZaFED.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +4.84 kB 🔴 +4.33 kB
assets/CurrentUserPopoverWorkspace-CQjKbUWX.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -4.84 kB 🟢 -4.32 kB
assets/WidgetInputNumber-Djs8exsP.js (removed) 19.1 kB 🟢 -19.1 kB 🟢 -4.84 kB 🟢 -4.3 kB
assets/WidgetInputNumber-DQitnkvp.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.84 kB 🔴 +4.29 kB
assets/WidgetRecordAudio-_ItucVv4.js (removed) 18.1 kB 🟢 -18.1 kB 🟢 -5.18 kB 🟢 -4.65 kB
assets/WidgetRecordAudio-D8uw-7rL.js (new) 18.1 kB 🔴 +18.1 kB 🔴 +5.18 kB 🔴 +4.65 kB
assets/Load3D-_Na8o-_1.js (removed) 16.9 kB 🟢 -16.9 kB 🟢 -4.12 kB 🟢 -3.59 kB
assets/Load3D-DvhIajA2.js (new) 16.9 kB 🔴 +16.9 kB 🔴 +4.11 kB 🔴 +3.6 kB
assets/WidgetCurve-Bj0Oa8Id.js (new) 16.1 kB 🔴 +16.1 kB 🔴 +4.97 kB 🔴 +4.45 kB
assets/WidgetCurve-C1GJsdei.js (removed) 16.1 kB 🟢 -16.1 kB 🟢 -4.97 kB 🟢 -4.46 kB
assets/load3d-BeZh2zMf.js (removed) 15 kB 🟢 -15 kB 🟢 -4.32 kB 🟢 -3.73 kB
assets/load3d-oLWglbs3.js (new) 15 kB 🔴 +15 kB 🔴 +4.32 kB 🔴 +3.73 kB
assets/WaveAudioPlayer-C5cbnhRX.js (removed) 13.4 kB 🟢 -13.4 kB 🟢 -3.68 kB 🟢 -3.22 kB
assets/WaveAudioPlayer-Dk9-QHMv.js (new) 13.4 kB 🔴 +13.4 kB 🔴 +3.68 kB 🔴 +3.22 kB
assets/TeamWorkspacesDialogContent-Cv6sGo2N.js (new) 11.1 kB 🔴 +11.1 kB 🔴 +3.33 kB 🔴 +2.96 kB
assets/TeamWorkspacesDialogContent-DgLkxuGr.js (removed) 11.1 kB 🟢 -11.1 kB 🟢 -3.33 kB 🟢 -2.97 kB
assets/nodeTemplates-BUJ-s13g.js (new) 9.58 kB 🔴 +9.58 kB 🔴 +3.37 kB 🔴 +2.96 kB
assets/nodeTemplates-CXswhAja.js (removed) 9.58 kB 🟢 -9.58 kB 🟢 -3.38 kB 🟢 -2.97 kB
assets/InviteMemberDialogContent-CdJX4KkV.js (removed) 7.77 kB 🟢 -7.77 kB 🟢 -2.45 kB 🟢 -2.13 kB
assets/InviteMemberDialogContent-xlcG-cre.js (new) 7.77 kB 🔴 +7.77 kB 🔴 +2.44 kB 🔴 +2.15 kB
assets/Load3DConfiguration-392kVJlm.js (new) 6.6 kB 🔴 +6.6 kB 🔴 +2.04 kB 🔴 +1.78 kB
assets/Load3DConfiguration-Dj-ERhn9.js (removed) 6.6 kB 🟢 -6.6 kB 🟢 -2.04 kB 🟢 -1.78 kB
assets/onboardingCloudRoutes-BsAHYLS8.js (new) 6.53 kB 🔴 +6.53 kB 🔴 +2.04 kB 🔴 +1.76 kB
assets/onboardingCloudRoutes-CC0Fp1YJ.js (removed) 6.53 kB 🟢 -6.53 kB 🟢 -2.04 kB 🟢 -1.76 kB
assets/WidgetWithControl-BqoPda5P.js (new) 5.99 kB 🔴 +5.99 kB 🔴 +2.38 kB 🔴 +2.13 kB
assets/WidgetWithControl-DtYmOtMv.js (removed) 5.99 kB 🟢 -5.99 kB 🟢 -2.38 kB 🟢 -2.12 kB
assets/CreateWorkspaceDialogContent-CuUJm5h5.js (new) 5.95 kB 🔴 +5.95 kB 🔴 +2.15 kB 🔴 +1.87 kB
assets/CreateWorkspaceDialogContent-DNzqkj4t.js (removed) 5.95 kB 🟢 -5.95 kB 🟢 -2.15 kB 🟢 -1.87 kB
assets/FreeTierDialogContent-BsZ70_4B.js (new) 5.82 kB 🔴 +5.82 kB 🔴 +2.05 kB 🔴 +1.8 kB
assets/FreeTierDialogContent-CXMsIm7S.js (removed) 5.82 kB 🟢 -5.82 kB 🟢 -2.05 kB 🟢 -1.8 kB
assets/EditWorkspaceDialogContent-DKs3W4yW.js (new) 5.75 kB 🔴 +5.75 kB 🔴 +2.11 kB 🔴 +1.83 kB
assets/EditWorkspaceDialogContent-OPUqvo_L.js (removed) 5.75 kB 🟢 -5.75 kB 🟢 -2.11 kB 🟢 -1.84 kB
assets/WidgetTextarea-B2q0K22C.js (new) 5.53 kB 🔴 +5.53 kB 🔴 +2.17 kB 🔴 +1.92 kB
assets/WidgetTextarea-DzhPvBez.js (removed) 5.53 kB 🟢 -5.53 kB 🟢 -2.17 kB 🟢 -1.91 kB
assets/Preview3d-DoMz47pg.js (removed) 5.36 kB 🟢 -5.36 kB 🟢 -1.8 kB 🟢 -1.56 kB
assets/Preview3d-GqDMHoaH.js (new) 5.36 kB 🔴 +5.36 kB 🔴 +1.79 kB 🔴 +1.56 kB
assets/ValueControlPopover-BtL-7QKq.js (removed) 5.33 kB 🟢 -5.33 kB 🟢 -1.93 kB 🟢 -1.72 kB
assets/ValueControlPopover-CI2Ke0Od.js (new) 5.33 kB 🔴 +5.33 kB 🔴 +1.93 kB 🔴 +1.73 kB
assets/CancelSubscriptionDialogContent-C_34esxo.js (removed) 5.22 kB 🟢 -5.22 kB 🟢 -1.95 kB 🟢 -1.7 kB
assets/CancelSubscriptionDialogContent-Dg3VwDHr.js (new) 5.22 kB 🔴 +5.22 kB 🔴 +1.95 kB 🔴 +1.7 kB
assets/DeleteWorkspaceDialogContent-CNJwQNqk.js (removed) 4.65 kB 🟢 -4.65 kB 🟢 -1.79 kB 🟢 -1.55 kB
assets/DeleteWorkspaceDialogContent-DY3ebuF-.js (new) 4.65 kB 🔴 +4.65 kB 🔴 +1.79 kB 🔴 +1.55 kB
assets/LeaveWorkspaceDialogContent-CaOVbAAD.js (new) 4.48 kB 🔴 +4.48 kB 🔴 +1.73 kB 🔴 +1.5 kB
assets/LeaveWorkspaceDialogContent-DwdRkJ-I.js (removed) 4.48 kB 🟢 -4.48 kB 🟢 -1.74 kB 🟢 -1.51 kB
assets/RemoveMemberDialogContent-BprHEXe-.js (removed) 4.46 kB 🟢 -4.46 kB 🟢 -1.69 kB 🟢 -1.47 kB
assets/RemoveMemberDialogContent-SVwfEMkX.js (new) 4.46 kB 🔴 +4.46 kB 🔴 +1.69 kB 🔴 +1.47 kB
assets/tierBenefits-7ULnEhlw.js (removed) 4.45 kB 🟢 -4.45 kB 🟢 -1.58 kB 🟢 -1.36 kB
assets/tierBenefits-C_d72oN1.js (new) 4.45 kB 🔴 +4.45 kB 🔴 +1.58 kB 🔴 +1.37 kB
assets/RevokeInviteDialogContent-DrGVUFnX.js (removed) 4.37 kB 🟢 -4.37 kB 🟢 -1.7 kB 🟢 -1.48 kB
assets/RevokeInviteDialogContent-zV4QooLB.js (new) 4.37 kB 🔴 +4.37 kB 🔴 +1.7 kB 🔴 +1.48 kB
assets/InviteMemberUpsellDialogContent-CtPmP5Gp.js (new) 4.27 kB 🔴 +4.27 kB 🔴 +1.56 kB 🔴 +1.36 kB
assets/InviteMemberUpsellDialogContent-WJHzWGaN.js (removed) 4.27 kB 🟢 -4.27 kB 🟢 -1.56 kB 🟢 -1.37 kB
assets/cloudSessionCookie-C_bU6p-a.js (new) 4.12 kB 🔴 +4.12 kB 🔴 +1.49 kB 🔴 +1.29 kB
assets/cloudSessionCookie-DnyWeaoz.js (removed) 4.12 kB 🟢 -4.12 kB 🟢 -1.49 kB 🟢 -1.29 kB
assets/saveMesh-asRG7OXN.js (removed) 3.92 kB 🟢 -3.92 kB 🟢 -1.69 kB 🟢 -1.48 kB
assets/saveMesh-BmDbSAPO.js (new) 3.92 kB 🔴 +3.92 kB 🔴 +1.68 kB 🔴 +1.48 kB
assets/Media3DTop-epih4cks.js (new) 3.85 kB 🔴 +3.85 kB 🔴 +1.62 kB 🔴 +1.43 kB
assets/Media3DTop-GbyKuQXK.js (removed) 3.85 kB 🟢 -3.85 kB 🟢 -1.63 kB 🟢 -1.44 kB
assets/GlobalToast-BrnGSXlf.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.26 kB 🔴 +1.07 kB
assets/GlobalToast-BZpeA5iU.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.25 kB 🟢 -1.07 kB
assets/SubscribeToRun-BuV5yYKP.js (new) 2.13 kB 🔴 +2.13 kB 🔴 +984 B 🔴 +871 B
assets/SubscribeToRun-D6N37zuy.js (removed) 2.13 kB 🟢 -2.13 kB 🟢 -983 B 🟢 -868 B
assets/MediaAudioTop-ClgF-JWG.js (removed) 2.02 kB 🟢 -2.02 kB 🟢 -984 B 🟢 -835 B
assets/MediaAudioTop-qKLRh1dd.js (new) 2.02 kB 🔴 +2.02 kB 🔴 +981 B 🔴 +833 B
assets/CloudRunButtonWrapper-Bir10pxs.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -913 B 🟢 -808 B
assets/CloudRunButtonWrapper-DKHCtCu2.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +909 B 🔴 +807 B
assets/graphHasMissingNodes-_4IwTYhG.js (removed) 1.83 kB 🟢 -1.83 kB 🟢 -863 B 🟢 -756 B
assets/graphHasMissingNodes-BLuc_MhP.js (new) 1.83 kB 🔴 +1.83 kB 🔴 +861 B 🔴 +752 B
assets/cloudBadges-fADEuwsy.js (new) 1.77 kB 🔴 +1.77 kB 🔴 +890 B 🔴 +769 B
assets/cloudBadges-qMsD98rz.js (removed) 1.77 kB 🟢 -1.77 kB 🟢 -894 B 🟢 -775 B
assets/cloudSubscription-BdOXBMTG.js (removed) 1.68 kB 🟢 -1.68 kB 🟢 -817 B 🟢 -712 B
assets/cloudSubscription-C202r_dD.js (new) 1.68 kB 🔴 +1.68 kB 🔴 +812 B 🔴 +703 B
assets/previousFullPath-BCLjcWqi.js (removed) 1.53 kB 🟢 -1.53 kB 🟢 -695 B 🟢 -598 B
assets/previousFullPath-BqPAFBRf.js (new) 1.53 kB 🔴 +1.53 kB 🔴 +694 B 🔴 +598 B
assets/Load3D-BginOIOU.js (new) 1.34 kB 🔴 +1.34 kB 🔴 +611 B 🔴 +539 B
assets/Load3D-mMV-ZgJl.js (removed) 1.34 kB 🟢 -1.34 kB 🟢 -618 B 🟢 -548 B
assets/nightlyBadges-4d2HJOs4.js (new) 1.29 kB 🔴 +1.29 kB 🔴 +656 B 🔴 +580 B
assets/nightlyBadges-hEWiw-LF.js (removed) 1.29 kB 🟢 -1.29 kB 🟢 -660 B 🟢 -583 B
assets/Load3dViewerContent-BuwG6ni0.js (new) 1.23 kB 🔴 +1.23 kB 🔴 +563 B 🔴 +496 B
assets/Load3dViewerContent-kb0acAsX.js (removed) 1.23 kB 🟢 -1.23 kB 🟢 -570 B 🟢 -499 B
assets/SubscriptionPanelContentWorkspace-C47JPhQK.js (removed) 1.15 kB 🟢 -1.15 kB 🟢 -537 B 🟢 -465 B
assets/SubscriptionPanelContentWorkspace-IbvwP5e-.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +533 B 🔴 +462 B
assets/WidgetLegacy-Bgg1CLSJ.js (new) 978 B 🔴 +978 B 🔴 +480 B 🔴 +421 B
assets/WidgetLegacy-DjOvXIUZ.js (removed) 978 B 🟢 -978 B 🟢 -484 B 🟢 -426 B
assets/changeTracker-5HKJt6CJ.js (new) 952 B 🔴 +952 B 🔴 +469 B 🔴 +410 B
assets/changeTracker-B7vNDc9n.js (removed) 952 B 🟢 -952 B 🟢 -474 B 🟢 -412 B

Status: 55 added / 55 removed / 79 unchanged

⚡ Performance Report

⚠️ 2 regressions detected

Metric Baseline PR (median) Δ Sig
canvas-zoom-sweep: frame duration 17ms 17ms -0% ⚠️ z=2.2
subgraph-mouse-sweep: task duration 988ms 908ms -8% ⚠️ z=2.0
All metrics
Metric Baseline PR (median) Δ Sig
canvas-idle: layout duration 0ms 0ms +0%
canvas-idle: style recalc duration 12ms 10ms -19% z=-1.4
canvas-idle: layout count 0 0 +0%
canvas-idle: style recalc count 12 11 -8% z=-0.3
canvas-idle: task duration 433ms 343ms -21% z=-1.6
canvas-idle: script duration 30ms 20ms -33% z=-2.3
canvas-idle: TBT 0ms 0ms +0%
canvas-idle: frame duration 17ms 17ms +0% z=-1.8
canvas-idle: heap used 60.5 MB 60.2 MB -0%
canvas-idle: DOM nodes 23 22 -4% z=-0.5
canvas-idle: event listeners 6 6 +0% z=-1.2
canvas-mouse-sweep: layout duration 4ms 3ms -14% z=-1.0
canvas-mouse-sweep: style recalc duration 47ms 43ms -8% z=0.3
canvas-mouse-sweep: layout count 12 12 +0%
canvas-mouse-sweep: style recalc count 84 81 -4% z=1.0
canvas-mouse-sweep: task duration 1056ms 954ms -10% z=1.5
canvas-mouse-sweep: script duration 148ms 138ms -6% z=0.4
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 56.3 MB +1%
canvas-mouse-sweep: DOM nodes 67 67 +0% z=1.8
canvas-mouse-sweep: event listeners 6 6 +0% z=-0.6
canvas-zoom-sweep: layout duration 1ms 1ms -18% z=-1.7
canvas-zoom-sweep: style recalc duration 20ms 18ms -10% z=-1.0
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 361ms 289ms -20% z=-1.6
canvas-zoom-sweep: script duration 32ms 23ms -28% z=-1.3
canvas-zoom-sweep: TBT 0ms 0ms +0%
canvas-zoom-sweep: frame duration 17ms 17ms -0% ⚠️ z=2.2
canvas-zoom-sweep: heap used 64.6 MB 64.0 MB -1%
canvas-zoom-sweep: DOM nodes 79 79 +0% 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 11ms 9ms -15% z=-1.0
dom-widget-clipping: layout count 0 0 +0%
dom-widget-clipping: style recalc count 13 13 +0% z=-0.2
dom-widget-clipping: task duration 380ms 337ms -11% z=-1.7
dom-widget-clipping: script duration 70ms 65ms -8% z=-0.9
dom-widget-clipping: TBT 0ms 0ms +0%
dom-widget-clipping: frame duration 17ms 17ms -0% z=-1.3
dom-widget-clipping: heap used 46.7 MB 46.7 MB -0%
dom-widget-clipping: DOM nodes 22 22 +0% 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 12ms 9ms -22% z=-2.6
large-graph-idle: layout count 0 0 +0%
large-graph-idle: style recalc count 11 10 -9% z=-5.1
large-graph-idle: task duration 688ms 520ms -24% z=-0.4
large-graph-idle: script duration 122ms 95ms -22% z=-0.7
large-graph-idle: TBT 0ms 0ms +0%
large-graph-idle: frame duration 17ms 17ms +0% z=0.6
large-graph-idle: heap used 52.1 MB 53.3 MB +2%
large-graph-idle: DOM nodes -255 -256 +0% z=-310.6
large-graph-idle: event listeners -125 -125 +0% z=-24.8
large-graph-pan: layout duration 0ms 0ms +0%
large-graph-pan: style recalc duration 16ms 16ms -2% z=-1.7
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 1221ms 1068ms -13% z=-0.3
large-graph-pan: script duration 437ms 388ms -11% z=-1.0
large-graph-pan: TBT 0ms 0ms +0%
large-graph-pan: frame duration 17ms 17ms +0% z=1.3
large-graph-pan: heap used 65.4 MB 65.2 MB -0%
large-graph-pan: DOM nodes -262 -260 -1% z=-169.1
large-graph-pan: event listeners -127 -125 -2% z=-156.9
large-graph-zoom: layout duration 8ms 7ms -5%
large-graph-zoom: style recalc duration 18ms 17ms -2%
large-graph-zoom: layout count 60 60 +0%
large-graph-zoom: style recalc count 65 67 +3%
large-graph-zoom: task duration 1435ms 1304ms -9%
large-graph-zoom: script duration 521ms 486ms -7%
large-graph-zoom: TBT 0ms 0ms +0%
large-graph-zoom: frame duration 17ms 17ms +0%
large-graph-zoom: heap used 59.5 MB 58.7 MB -1%
large-graph-zoom: DOM nodes -269 -262 -3%
large-graph-zoom: event listeners -123 -125 +2%
minimap-idle: layout duration 0ms 0ms +0%
minimap-idle: style recalc duration 10ms 8ms -22% z=-2.1
minimap-idle: layout count 0 0 +0%
minimap-idle: style recalc count 9 8 -11% z=-2.3
minimap-idle: task duration 658ms 504ms -23% z=-0.5
minimap-idle: script duration 111ms 86ms -23% z=-1.2
minimap-idle: TBT 0ms 0ms +0%
minimap-idle: frame duration 17ms 17ms +0% z=1.2
minimap-idle: heap used 53.8 MB 53.8 MB -0%
minimap-idle: DOM nodes -264 -263 -0% z=-206.3
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 12ms -6% z=-0.7
subgraph-dom-widget-clipping: layout count 0 0 +0%
subgraph-dom-widget-clipping: style recalc count 48 48 +0% z=0.1
subgraph-dom-widget-clipping: task duration 383ms 356ms -7% z=-1.2
subgraph-dom-widget-clipping: script duration 135ms 126ms -6% z=-0.3
subgraph-dom-widget-clipping: TBT 0ms 0ms +0%
subgraph-dom-widget-clipping: frame duration 17ms 17ms +0% z=1.2
subgraph-dom-widget-clipping: heap used 47.2 MB 47.1 MB -0%
subgraph-dom-widget-clipping: DOM nodes 22 22 +0% z=-0.2
subgraph-dom-widget-clipping: event listeners 8 8 +0% z=-1.4
subgraph-idle: layout duration 0ms 0ms +0%
subgraph-idle: style recalc duration 11ms 10ms -4% z=0.0
subgraph-idle: layout count 0 0 +0%
subgraph-idle: style recalc count 11 11 +0% z=0.2
subgraph-idle: task duration 435ms 340ms -22% z=-1.0
subgraph-idle: script duration 25ms 19ms -23% z=-0.3
subgraph-idle: TBT 0ms 0ms +0%
subgraph-idle: frame duration 17ms 17ms -0% z=-1.9
subgraph-idle: heap used 60.0 MB 59.9 MB -0%
subgraph-idle: DOM nodes 21 22 +5% z=0.1
subgraph-idle: event listeners 6 6 +0% variance too high
subgraph-mouse-sweep: layout duration 5ms 4ms -16% z=-0.9
subgraph-mouse-sweep: style recalc duration 54ms 46ms -14% z=1.1
subgraph-mouse-sweep: layout count 16 16 +0%
subgraph-mouse-sweep: style recalc count 87 84 -3% z=2.0
subgraph-mouse-sweep: task duration 988ms 908ms -8% ⚠️ z=2.0
subgraph-mouse-sweep: script duration 114ms 100ms -12% z=-0.1
subgraph-mouse-sweep: TBT 0ms 0ms +0%
subgraph-mouse-sweep: frame duration 17ms 17ms +0% z=1.2
subgraph-mouse-sweep: heap used 52.0 MB 52.3 MB +1%
subgraph-mouse-sweep: DOM nodes 73 73 +0% z=2.7
subgraph-mouse-sweep: event listeners 6 6 +0% variance too high
viewport-pan-sweep: layout duration 0ms 0ms +0%
viewport-pan-sweep: style recalc duration 48ms 43ms -9%
viewport-pan-sweep: layout count 0 0 +0%
viewport-pan-sweep: style recalc count 252 251 -0%
viewport-pan-sweep: task duration 4073ms 3682ms -10%
viewport-pan-sweep: script duration 1335ms 1298ms -3%
viewport-pan-sweep: TBT 0ms 0ms +0%
viewport-pan-sweep: frame duration 17ms 17ms +0%
viewport-pan-sweep: heap used 72.6 MB 71.9 MB -1%
viewport-pan-sweep: DOM nodes -257 -257 +0%
viewport-pan-sweep: event listeners -111 -111 +0%
vue-large-graph-idle: layout duration 0ms 0ms +0%
vue-large-graph-idle: style recalc duration 0ms 0ms +0%
vue-large-graph-idle: layout count 0 0 +0%
vue-large-graph-idle: style recalc count 0 0 +0%
vue-large-graph-idle: task duration 12620ms 12038ms -5%
vue-large-graph-idle: script duration 637ms 600ms -6%
vue-large-graph-idle: TBT 0ms 0ms +0%
vue-large-graph-idle: frame duration 18ms 18ms +0%
vue-large-graph-idle: heap used 151.3 MB 158.3 MB +5%
vue-large-graph-idle: DOM nodes -8331 -8331 +0%
vue-large-graph-idle: event listeners -16464 -16462 -0%
vue-large-graph-pan: layout duration 0ms 0ms +0%
vue-large-graph-pan: style recalc duration 16ms 13ms -17%
vue-large-graph-pan: layout count 0 0 +0%
vue-large-graph-pan: style recalc count 71 65 -8%
vue-large-graph-pan: task duration 14886ms 14167ms -5%
vue-large-graph-pan: script duration 921ms 903ms -2%
vue-large-graph-pan: TBT 0ms 0ms +0%
vue-large-graph-pan: frame duration 20ms 18ms -8%
vue-large-graph-pan: heap used 164.0 MB 165.3 MB +1%
vue-large-graph-pan: DOM nodes -8331 -8331 +0%
vue-large-graph-pan: event listeners -16458 -16462 +0%
workflow-execution: layout duration 1ms 2ms +3% z=-0.2
workflow-execution: style recalc duration 26ms 26ms +1% z=0.7
workflow-execution: layout count 5 5 +0% z=0.1
workflow-execution: style recalc count 17 18 +6% z=0.1
workflow-execution: task duration 134ms 120ms -11% z=-0.3
workflow-execution: script duration 31ms 29ms -8% z=-0.1
workflow-execution: TBT 0ms 0ms +0%
workflow-execution: frame duration 17ms 17ms -0% z=-1.4
workflow-execution: heap used 46.8 MB 46.3 MB -1%
workflow-execution: DOM nodes 157 158 +1% z=-0.4
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-29T02:42:27.550Z",
  "gitSha": "4f4f2b221243940de7066247f3161789429c8b8f",
  "branch": "test/priority-store-tests",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2020.955999999984,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.521999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 350.857,
      "heapDeltaBytes": 20949148,
      "heapUsedBytes": 64709432,
      "domNodes": 22,
      "jsHeapTotalBytes": 23068672,
      "scriptDurationMs": 24.249,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "canvas-idle",
      "durationMs": 2015.7770000000141,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 9.574,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 343.353,
      "heapDeltaBytes": 20319788,
      "heapUsedBytes": 62826468,
      "domNodes": 22,
      "jsHeapTotalBytes": 22544384,
      "scriptDurationMs": 20.221,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.659999999999947
    },
    {
      "name": "canvas-idle",
      "durationMs": 2001.846999999998,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 8.36,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 327.407,
      "heapDeltaBytes": 20020360,
      "heapUsedBytes": 63168328,
      "domNodes": 17,
      "jsHeapTotalBytes": 22544384,
      "scriptDurationMs": 14.340000000000002,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.659999999999947
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 2091.790000000003,
      "styleRecalcs": 85,
      "styleRecalcDurationMs": 48.736000000000004,
      "layouts": 12,
      "layoutDurationMs": 3.993,
      "taskDurationMs": 1032.753,
      "heapDeltaBytes": 18002932,
      "heapUsedBytes": 66871840,
      "domNodes": 67,
      "jsHeapTotalBytes": 25427968,
      "scriptDurationMs": 146.411,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1715.1870000000145,
      "styleRecalcs": 73,
      "styleRecalcDurationMs": 34.521,
      "layouts": 12,
      "layoutDurationMs": 3.3379999999999996,
      "taskDurationMs": 700.3340000000001,
      "heapDeltaBytes": 15274748,
      "heapUsedBytes": 58385776,
      "domNodes": 56,
      "jsHeapTotalBytes": 23592960,
      "scriptDurationMs": 123.997,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 2035.712999999987,
      "styleRecalcs": 81,
      "styleRecalcDurationMs": 43.454,
      "layouts": 12,
      "layoutDurationMs": 3.418999999999999,
      "taskDurationMs": 954.0940000000002,
      "heapDeltaBytes": 16731644,
      "heapUsedBytes": 59079616,
      "domNodes": 67,
      "jsHeapTotalBytes": 23330816,
      "scriptDurationMs": 138.34,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.659999999999947
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1741.5260000000217,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 17.872,
      "layouts": 6,
      "layoutDurationMs": 0.5720000000000001,
      "taskDurationMs": 311.051,
      "heapDeltaBytes": 24692148,
      "heapUsedBytes": 67413184,
      "domNodes": 79,
      "jsHeapTotalBytes": 20971520,
      "scriptDurationMs": 26.244,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000073
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1748.3740000000125,
      "styleRecalcs": 32,
      "styleRecalcDurationMs": 17.575,
      "layouts": 6,
      "layoutDurationMs": 0.5640000000000001,
      "taskDurationMs": 289.48799999999994,
      "heapDeltaBytes": 24734000,
      "heapUsedBytes": 67076768,
      "domNodes": 80,
      "jsHeapTotalBytes": 20709376,
      "scriptDurationMs": 22.964000000000002,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1721.104999999966,
      "styleRecalcs": 32,
      "styleRecalcDurationMs": 17.547,
      "layouts": 6,
      "layoutDurationMs": 0.568,
      "taskDurationMs": 288.856,
      "heapDeltaBytes": 24686548,
      "heapUsedBytes": 67106500,
      "domNodes": 79,
      "jsHeapTotalBytes": 20447232,
      "scriptDurationMs": 23.163000000000004,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 604.2290000000037,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 8.011999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 364.178,
      "heapDeltaBytes": 6086304,
      "heapUsedBytes": 48939480,
      "domNodes": 20,
      "jsHeapTotalBytes": 14155776,
      "scriptDurationMs": 69.804,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.65999999999999
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 542.1709999999962,
      "styleRecalcs": 14,
      "styleRecalcDurationMs": 9.898,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 336.53700000000003,
      "heapDeltaBytes": 6786204,
      "heapUsedBytes": 49120132,
      "domNodes": 23,
      "jsHeapTotalBytes": 13107200,
      "scriptDurationMs": 63.153,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000027
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 549.6899999999414,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 9.08,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 333.495,
      "heapDeltaBytes": 6145656,
      "heapUsedBytes": 48968384,
      "domNodes": 22,
      "jsHeapTotalBytes": 14417920,
      "scriptDurationMs": 64.824,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.65999999999999
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2022.0339999999908,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 9.884999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 533.1709999999999,
      "heapDeltaBytes": 5345384,
      "heapUsedBytes": 55863456,
      "domNodes": -255,
      "jsHeapTotalBytes": 16191488,
      "scriptDurationMs": 94.79799999999999,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "large-graph-idle",
      "durationMs": 1995.1340000000073,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 9.463,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 519.795,
      "heapDeltaBytes": 21275976,
      "heapUsedBytes": 72966080,
      "domNodes": -256,
      "jsHeapTotalBytes": 15724544,
      "scriptDurationMs": 91.083,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.67999999999993
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2015.9720000000334,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 8.258000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 518.4960000000001,
      "heapDeltaBytes": 4052240,
      "heapUsedBytes": 55469120,
      "domNodes": -260,
      "jsHeapTotalBytes": 16191488,
      "scriptDurationMs": 97.831,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2147.4249999999984,
      "styleRecalcs": 68,
      "styleRecalcDurationMs": 14.592999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1067.844,
      "heapDeltaBytes": 15025288,
      "heapUsedBytes": 68327244,
      "domNodes": -260,
      "jsHeapTotalBytes": 19017728,
      "scriptDurationMs": 387.17199999999997,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2119.9609999999893,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 15.952000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1042.618,
      "heapDeltaBytes": 17297312,
      "heapUsedBytes": 70599628,
      "domNodes": -261,
      "jsHeapTotalBytes": 18755584,
      "scriptDurationMs": 387.546,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2184.407999999962,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 16.02,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1131.58,
      "heapDeltaBytes": -6783600,
      "heapUsedBytes": 47478692,
      "domNodes": -260,
      "jsHeapTotalBytes": 20705280,
      "scriptDurationMs": 417.407,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000073
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3143.2490000000257,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 16.236,
      "layouts": 60,
      "layoutDurationMs": 7.243,
      "taskDurationMs": 1304.33,
      "heapDeltaBytes": 7110252,
      "heapUsedBytes": 61577476,
      "domNodes": -264,
      "jsHeapTotalBytes": 16715776,
      "scriptDurationMs": 485.50000000000006,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3146.3020000000483,
      "styleRecalcs": 67,
      "styleRecalcDurationMs": 17.185000000000002,
      "layouts": 60,
      "layoutDurationMs": 7.012,
      "taskDurationMs": 1277.1560000000002,
      "heapDeltaBytes": 1379804,
      "heapUsedBytes": 55807396,
      "domNodes": -262,
      "jsHeapTotalBytes": 17764352,
      "scriptDurationMs": 478.01,
      "eventListeners": -123,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3192.421999999965,
      "styleRecalcs": 67,
      "styleRecalcDurationMs": 18.171000000000003,
      "layouts": 60,
      "layoutDurationMs": 7.585999999999999,
      "taskDurationMs": 1410.307,
      "heapDeltaBytes": 14433536,
      "heapUsedBytes": 69973172,
      "domNodes": -261,
      "jsHeapTotalBytes": 16248832,
      "scriptDurationMs": 533.409,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "minimap-idle",
      "durationMs": 2053.7669999999935,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 8.971999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 525.4890000000001,
      "heapDeltaBytes": 4381968,
      "heapUsedBytes": 56412088,
      "domNodes": -258,
      "jsHeapTotalBytes": 16453632,
      "scriptDurationMs": 101.04299999999999,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "minimap-idle",
      "durationMs": 2039.761999999996,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 7.805,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 500.27299999999997,
      "heapDeltaBytes": 2885120,
      "heapUsedBytes": 57027412,
      "domNodes": -263,
      "jsHeapTotalBytes": 15929344,
      "scriptDurationMs": 85.95,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "minimap-idle",
      "durationMs": 2001.263999999992,
      "styleRecalcs": 7,
      "styleRecalcDurationMs": 6.435,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 503.56899999999996,
      "heapDeltaBytes": 621204,
      "heapUsedBytes": 54831868,
      "domNodes": -265,
      "jsHeapTotalBytes": 14880768,
      "scriptDurationMs": 84.46799999999999,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 572.1750000000156,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 12.078999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 355.51200000000006,
      "heapDeltaBytes": 6139400,
      "heapUsedBytes": 49301240,
      "domNodes": 22,
      "jsHeapTotalBytes": 13893632,
      "scriptDurationMs": 126.70100000000001,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.65
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 538.6670000000322,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 12.046999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 359.13100000000003,
      "heapDeltaBytes": 6452332,
      "heapUsedBytes": 50612428,
      "domNodes": 22,
      "jsHeapTotalBytes": 13631488,
      "scriptDurationMs": 126.23299999999999,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 538.7279999999919,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 10.566999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 347.46700000000004,
      "heapDeltaBytes": 6350548,
      "heapUsedBytes": 49348316,
      "domNodes": 20,
      "jsHeapTotalBytes": 14417920,
      "scriptDurationMs": 121.54899999999999,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000027
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2002.5989999999751,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.108,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 334.611,
      "heapDeltaBytes": 19929952,
      "heapUsedBytes": 62919380,
      "domNodes": 22,
      "jsHeapTotalBytes": 22544384,
      "scriptDurationMs": 18.492999999999995,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.659999999999947
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2015.265999999997,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 12.765,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 353.16700000000003,
      "heapDeltaBytes": 19965896,
      "heapUsedBytes": 62760568,
      "domNodes": 25,
      "jsHeapTotalBytes": 22806528,
      "scriptDurationMs": 25.211000000000002,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2007.69600000001,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.433,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 339.727,
      "heapDeltaBytes": 19926388,
      "heapUsedBytes": 62753952,
      "domNodes": 22,
      "jsHeapTotalBytes": 22806528,
      "scriptDurationMs": 19.479,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.659999999999947
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1991.8419999999912,
      "styleRecalcs": 86,
      "styleRecalcDurationMs": 53.64099999999999,
      "layouts": 16,
      "layoutDurationMs": 4.923,
      "taskDurationMs": 907.8919999999999,
      "heapDeltaBytes": 11771132,
      "heapUsedBytes": 54866436,
      "domNodes": 75,
      "jsHeapTotalBytes": 23592960,
      "scriptDurationMs": 102.21699999999998,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1977.8190000000109,
      "styleRecalcs": 84,
      "styleRecalcDurationMs": 46.257999999999996,
      "layouts": 16,
      "layoutDurationMs": 4.394,
      "taskDurationMs": 886.164,
      "heapDeltaBytes": 11856616,
      "heapUsedBytes": 54911776,
      "domNodes": 73,
      "jsHeapTotalBytes": 22020096,
      "scriptDurationMs": 98.545,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1965.6790000000228,
      "styleRecalcs": 83,
      "styleRecalcDurationMs": 43.056,
      "layouts": 16,
      "layoutDurationMs": 4.353,
      "taskDurationMs": 909.9379999999999,
      "heapDeltaBytes": 11773472,
      "heapUsedBytes": 54892912,
      "domNodes": 72,
      "jsHeapTotalBytes": 23068672,
      "scriptDurationMs": 99.958,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8214.75700000002,
      "styleRecalcs": 251,
      "styleRecalcDurationMs": 43.475,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4163.579000000001,
      "heapDeltaBytes": 39591300,
      "heapUsedBytes": 90453396,
      "domNodes": -257,
      "jsHeapTotalBytes": 34222080,
      "scriptDurationMs": 1627.3120000000001,
      "eventListeners": -109,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000073
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8216.404000000011,
      "styleRecalcs": 252,
      "styleRecalcDurationMs": 45.565000000000005,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 3604.418,
      "heapDeltaBytes": 24755376,
      "heapUsedBytes": 75368692,
      "domNodes": -255,
      "jsHeapTotalBytes": 19542016,
      "scriptDurationMs": 1221.0149999999999,
      "eventListeners": -111,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.67999999999993
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8179.8350000000255,
      "styleRecalcs": 249,
      "styleRecalcDurationMs": 41.941,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 3681.836,
      "heapDeltaBytes": 19333728,
      "heapUsedBytes": 71971152,
      "domNodes": -260,
      "jsHeapTotalBytes": 21639168,
      "scriptDurationMs": 1297.925,
      "eventListeners": -111,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999989
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 12263.558999999987,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12252.097,
      "heapDeltaBytes": -35093668,
      "heapUsedBytes": 165955592,
      "domNodes": -8331,
      "jsHeapTotalBytes": 27615232,
      "scriptDurationMs": 608.513,
      "eventListeners": -16462,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 18.32000000000007
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 11835.770999999966,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 11819.184,
      "heapDeltaBytes": -30831388,
      "heapUsedBytes": 165582832,
      "domNodes": -8331,
      "jsHeapTotalBytes": 28139520,
      "scriptDurationMs": 567.083,
      "eventListeners": -16468,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 18.329999999999927
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 12049.90900000007,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12037.541000000001,
      "heapDeltaBytes": -22111580,
      "heapUsedBytes": 186377540,
      "domNodes": -5048,
      "jsHeapTotalBytes": 28139520,
      "scriptDurationMs": 599.843,
      "eventListeners": -16462,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 18.339999999999783
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 14188.022999999986,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 13.30300000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 14166.91,
      "heapDeltaBytes": -16021288,
      "heapUsedBytes": 185125364,
      "domNodes": -8331,
      "jsHeapTotalBytes": 24907776,
      "scriptDurationMs": 924.704,
      "eventListeners": -16462,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 19.990000000000144
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 14075.519000000042,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 12.955999999999968,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 14054.618999999999,
      "heapDeltaBytes": -21617860,
      "heapUsedBytes": 173351520,
      "domNodes": -8331,
      "jsHeapTotalBytes": 24907776,
      "scriptDurationMs": 827.269,
      "eventListeners": -16460,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 18.339999999999783
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 14283.21799999992,
      "styleRecalcs": 67,
      "styleRecalcDurationMs": 13.248999999999983,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 14258.741,
      "heapDeltaBytes": -53356692,
      "heapUsedBytes": 147807576,
      "domNodes": -8333,
      "jsHeapTotalBytes": -958464,
      "scriptDurationMs": 903.171,
      "eventListeners": -16486,
      "totalBlockingTimeMs": 34,
      "frameDurationMs": 18.329999999999927
    },
    {
      "name": "workflow-execution",
      "durationMs": 117.24900000001526,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 25.9,
      "layouts": 5,
      "layoutDurationMs": 2.017,
      "taskDurationMs": 104.64500000000001,
      "heapDeltaBytes": 2948228,
      "heapUsedBytes": 46876180,
      "domNodes": 148,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 26.898000000000007,
      "eventListeners": 37,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.65999999999999
    },
    {
      "name": "workflow-execution",
      "durationMs": 450.0679999999875,
      "styleRecalcs": 18,
      "styleRecalcDurationMs": 23.536,
      "layouts": 5,
      "layoutDurationMs": 1.5190000000000001,
      "taskDurationMs": 120.01899999999999,
      "heapDeltaBytes": 4478504,
      "heapUsedBytes": 48551548,
      "domNodes": 159,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 28.866000000000003,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.65999999999999
    },
    {
      "name": "workflow-execution",
      "durationMs": 457.0620000000645,
      "styleRecalcs": 19,
      "styleRecalcDurationMs": 27.227999999999998,
      "layouts": 5,
      "layoutDurationMs": 1.3019999999999998,
      "taskDurationMs": 137.102,
      "heapDeltaBytes": 4549540,
      "heapUsedBytes": 48509016,
      "domNodes": 158,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 33.551,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.65999999999999
    }
  ]
}

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/stores/widgetStore.test.ts`:
- Around line 73-87: Tests call inputIsWidget with objects missing the required
name field; update each fixture in the three it blocks to include a name
property (e.g., name: 'test_input') so they conform to InputSpecV2.
Specifically, in the tests using useWidgetStore and calling inputIsWidget({
type: 'STRING' }), inputIsWidget({ type: 'LATENT' }), and inputIsWidget({ type:
'MY_WIDGET' }) add name: 'test_input' (or another suitable identifier), leaving
the registerCustomWidgets call and other assertions unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bba183fc-835f-4135-90c8-197668da464f

📥 Commits

Reviewing files that changed from the base of the PR and between 82242f1 and 04c1098.

📒 Files selected for processing (3)
  • src/stores/commandStore.test.ts
  • src/stores/extensionStore.test.ts
  • src/stores/widgetStore.test.ts

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.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/stores/widgetStore.test.ts (1)

10-12: ⚠️ Potential issue | 🟠 Major

Avoid unknown casts that hide invalid InputSpec fixtures

Line 10 and Line 11 bypass type-shape checks, and the v2 fixtures at Line 81, Line 86, and Line 92 still omit required fields like name. This weakens the test contract and can mask schema regressions.

💡 Suggested fix
-const v1 = (spec: unknown) => spec as InputSpecV1
-const v2 = (spec: unknown) => spec as InputSpecV2
+function v1(spec: InputSpecV1): InputSpecV1 {
+  return spec
+}
+
+function v2(spec: InputSpecV2): InputSpecV2 {
+  return spec
+}
@@
-      expect(store.inputIsWidget(v2({ type: 'STRING' }))).toBe(true)
+      expect(
+        store.inputIsWidget(v2({ type: 'STRING', name: 'test_input' }))
+      ).toBe(true)
@@
-      expect(store.inputIsWidget(v2({ type: 'LATENT' }))).toBe(false)
+      expect(
+        store.inputIsWidget(v2({ type: 'LATENT', name: 'test_input' }))
+      ).toBe(false)
@@
-      expect(store.inputIsWidget(v2({ type: 'MY_WIDGET' }))).toBe(true)
+      expect(
+        store.inputIsWidget(v2({ type: 'MY_WIDGET', name: 'test_input' }))
+      ).toBe(true)
#!/bin/bash
set -euo pipefail

SCHEMA_FILE="$(fd -i '^nodeDefSchemaV2.ts$' src | head -n 1)"
echo "Schema file: ${SCHEMA_FILE}"
rg -n -C3 'export type InputSpec|name:' "${SCHEMA_FILE}"

echo
echo "V2 fixtures in src/stores/widgetStore.test.ts:"
rg -n -C1 "v2\\(\\{\\s*type:" src/stores/widgetStore.test.ts

Based on learnings: In test files matching **/*.test.ts under src, prefer using satisfies InterfaceType for shape validation instead of type assertions.

Also applies to: 79-93

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

In `@src/stores/widgetStore.test.ts` around lines 10 - 12, The test helpers v1 and
v2 cast fixtures via "spec as InputSpecV1/InputSpecV2", which hides invalid
shapes; replace these casts by creating literal fixtures with the TypeScript
"satisfies InputSpecV1" / "satisfies InputSpecV2" so the compiler validates
required fields, and update the v2 fixtures that currently omit required
properties (e.g., missing name) to include all required fields of InputSpecV2;
adjust the helper usage so tests use the validated literals (or a small factory
that returns the literal) instead of the unknown casts in functions named v1 and
v2.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/stores/extensionStore.test.ts`:
- Around line 34-45: The test that spies on console.warn in the suite using
useExtensionStore registers a spy in the test body but only calls
warnSpy.mockRestore() at the end, which can leak if the test throws; update the
test that calls loadDisabledExtensionNames and registerExtension to ensure the
spy is always restored by wrapping the test body in try/finally (create warnSpy
via vi.spyOn(console, 'warn') before the try, run the assertions in the try, and
call warnSpy.mockRestore() in finally), or alternatively add an afterEach hook
that calls vi.restoreAllMocks() for the file; reference the test using
useExtensionStore, loadDisabledExtensionNames, registerExtension, and warnSpy
when making the change.

---

Duplicate comments:
In `@src/stores/widgetStore.test.ts`:
- Around line 10-12: The test helpers v1 and v2 cast fixtures via "spec as
InputSpecV1/InputSpecV2", which hides invalid shapes; replace these casts by
creating literal fixtures with the TypeScript "satisfies InputSpecV1" /
"satisfies InputSpecV2" so the compiler validates required fields, and update
the v2 fixtures that currently omit required properties (e.g., missing name) to
include all required fields of InputSpecV2; adjust the helper usage so tests use
the validated literals (or a small factory that returns the literal) instead of
the unknown casts in functions named v1 and v2.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9411c294-ac2d-4563-a328-17b05c51cae0

📥 Commits

Reviewing files that changed from the base of the PR and between 04c1098 and de2a41c.

📒 Files selected for processing (2)
  • src/stores/extensionStore.test.ts
  • src/stores/widgetStore.test.ts

@christian-byrne christian-byrne self-assigned this Mar 29, 2026
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.

Actionable comments posted: 2

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

9-11: Avoid unknown cast helpers for InputSpec fixtures

These helpers erase compile-time fixture validation and can hide schema drift.
Prefer typed literals with satisfies so fixture shape changes fail fast.

Proposed refactor
-/** Cast shorthand — the mock bypasses Zod validation, so we only need the shape `inputIsWidget` reads. */
-const v1 = (spec: unknown) => spec as InputSpecV1
-const v2 = (spec: unknown) => spec as InputSpecV2
+function v1(spec: InputSpecV1): InputSpecV1 {
+  return spec
+}
+
+function v2(spec: InputSpecV2): InputSpecV2 {
+  return spec
+}
-      expect(store.inputIsWidget(v1(['INT', {}]))).toBe(true)
+      const spec = ['INT', {}] satisfies InputSpecV1
+      expect(store.inputIsWidget(v1(spec))).toBe(true)

Based on learnings: "In test files matching **/*.test.ts under src, when creating test helper functions that construct mock objects implementing an interface (e.g., AssetItem), prefer using satisfies InterfaceType for shape validation instead of type assertions like as Partial as InterfaceType or as any."

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

In `@src/stores/widgetStore.test.ts` around lines 9 - 11, The v1 and v2 test
helper functions currently erase compile-time checks by casting an unknown to
InputSpecV1/InputSpecV2; replace them with helpers that return strongly-typed
fixtures using TypeScript's "satisfies" operator or explicit typed object
literals so the shape is validated at compile time (e.g., make v1(spec:
Partial<InputSpecV1>) => ({ ...defaultV1, ...spec } satisfies InputSpecV1) and
similarly for v2 with InputSpecV2), and remove the unsafe "as unknown" casts so
schema drift is caught by the compiler; keep function names v1 and v2 and the
InputSpecV1/InputSpecV2 types to locate the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/stores/extensionStore.test.ts`:
- Around line 79-86: The test can pass falsely if uninstalled extensions are
treated as disabled; update the test that uses useExtensionStore(),
loadDisabledExtensionNames([]) and isExtensionEnabled(...) to first register one
hardcoded-denylisted extension and one normal control extension (using the
store's extension registration/install helper) so their installed/enabled state
is explicit, then assert isExtensionEnabled('pysssss.Locking') is false and the
control extension is true; this ensures the denylist logic (checked by
isExtensionEnabled) is actually exercised rather than relying on default
uninstalled behavior.

In `@src/stores/widgetStore.test.ts`:
- Around line 47-53: The test currently only checks that
store.widgets.get('INT') is not the override, which can pass if the widget is
missing; update the assertion to compare against the expected core widget
function so the test fails on incorrect/missing values. In the test using
useWidgetStore() and registerCustomWidgets({ INT: override }), retrieve the core
widget reference (the known core implementation used by the codebase) and assert
store.widgets.get('INT') === <coreWidgetFunction> (replace <coreWidgetFunction>
with the actual core widget symbol/name used) to ensure core widgets truly take
precedence.

---

Nitpick comments:
In `@src/stores/widgetStore.test.ts`:
- Around line 9-11: The v1 and v2 test helper functions currently erase
compile-time checks by casting an unknown to InputSpecV1/InputSpecV2; replace
them with helpers that return strongly-typed fixtures using TypeScript's
"satisfies" operator or explicit typed object literals so the shape is validated
at compile time (e.g., make v1(spec: Partial<InputSpecV1>) => ({ ...defaultV1,
...spec } satisfies InputSpecV1) and similarly for v2 with InputSpecV2), and
remove the unsafe "as unknown" casts so schema drift is caught by the compiler;
keep function names v1 and v2 and the InputSpecV1/InputSpecV2 types to locate
the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b8b49334-defb-498c-818e-88bbd0a41dc3

📥 Commits

Reviewing files that changed from the base of the PR and between de2a41c and f4f4ea4.

📒 Files selected for processing (2)
  • src/stores/extensionStore.test.ts
  • src/stores/widgetStore.test.ts

Comment on lines +79 to +86
it('always disables hardcoded extensions', () => {
const store = useExtensionStore()
store.loadDisabledExtensionNames([])
expect(store.isExtensionEnabled('pysssss.Locking')).toBe(false)
expect(store.isExtensionEnabled('pysssss.SnapToGrid')).toBe(false)
expect(store.isExtensionEnabled('pysssss.FaviconStatus')).toBe(false)
expect(store.isExtensionEnabled('KJNodes.browserstatus')).toBe(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.

⚠️ Potential issue | 🟡 Minor

Make the hardcoded-disable test unambiguous

Right now this can pass even if the hardcoded denylist logic regresses, depending on how uninstalled extensions are treated.
Register at least one hardcoded extension and a normal control extension before asserting enabled state.

Proposed adjustment
     it('always disables hardcoded extensions', () => {
       const store = useExtensionStore()
       store.loadDisabledExtensionNames([])
+      store.registerExtension({ name: 'pysssss.Locking' })
+      store.registerExtension({ name: 'regular.ext' })
+
       expect(store.isExtensionEnabled('pysssss.Locking')).toBe(false)
       expect(store.isExtensionEnabled('pysssss.SnapToGrid')).toBe(false)
       expect(store.isExtensionEnabled('pysssss.FaviconStatus')).toBe(false)
       expect(store.isExtensionEnabled('KJNodes.browserstatus')).toBe(false)
+      expect(store.isExtensionEnabled('regular.ext')).toBe(true)
     })

As per coding guidelines: "Do not write tests that just test the mocks in Vitest; ensure tests fail when code behaves unexpectedly."

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

In `@src/stores/extensionStore.test.ts` around lines 79 - 86, The test can pass
falsely if uninstalled extensions are treated as disabled; update the test that
uses useExtensionStore(), loadDisabledExtensionNames([]) and
isExtensionEnabled(...) to first register one hardcoded-denylisted extension and
one normal control extension (using the store's extension registration/install
helper) so their installed/enabled state is explicit, then assert
isExtensionEnabled('pysssss.Locking') is false and the control extension is
true; this ensures the denylist logic (checked by isExtensionEnabled) is
actually exercised rather than relying on default uninstalled behavior.

Comment on lines +47 to +53
it('core widgets take precedence over custom widgets with same key', () => {
const store = useWidgetStore()
const override = vi.fn()
store.registerCustomWidgets({ INT: override })
// Core widgets are spread last, so they win
expect(store.widgets.get('INT')).not.toBe(override)
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Strengthen the precedence assertion to avoid false positives

not.toBe(override) still passes if the value is missing/incorrect.
Assert the exact expected core widget function instead.

Proposed fix
+import { ComfyWidgets } from '@/scripts/widgets'
@@
     it('core widgets take precedence over custom widgets with same key', () => {
       const store = useWidgetStore()
       const override = vi.fn()
       store.registerCustomWidgets({ INT: override })
-      // Core widgets are spread last, so they win
-      expect(store.widgets.get('INT')).not.toBe(override)
+      expect(store.widgets.get('INT')).toBe(ComfyWidgets.INT)
     })

As per coding guidelines: "Do not write tests that just test the mocks in Vitest; ensure tests fail when code behaves unexpectedly."

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

In `@src/stores/widgetStore.test.ts` around lines 47 - 53, The test currently only
checks that store.widgets.get('INT') is not the override, which can pass if the
widget is missing; update the assertion to compare against the expected core
widget function so the test fails on incorrect/missing values. In the test using
useWidgetStore() and registerCustomWidgets({ INT: override }), retrieve the core
widget reference (the known core implementation used by the codebase) and assert
store.widgets.get('INT') === <coreWidgetFunction> (replace <coreWidgetFunction>
with the actual core widget symbol/name used) to ensure core widgets truly take
precedence.

@christian-byrne christian-byrne removed the New Browser Test Expectations New browser test screenshot should be set by github action label Mar 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants