Skip to content

fix(billing): keep top-up working for local users on the free tier - #14589

Closed
christian-byrne wants to merge 3 commits into
mainfrom
glary/fix-local-credits-upgrade-gating
Closed

fix(billing): keep top-up working for local users on the free tier#14589
christian-byrne wants to merge 3 commits into
mainfrom
glary/fix-local-credits-upgrade-gating

Conversation

@christian-byrne

Copy link
Copy Markdown
Contributor

PR Created by the Glary-Bot Agent


Local (desktop/portable) users who are not Cloud subscribers lose the credit purchase flow after opening Settings ▸ Credits, and cannot recover without restarting the app. Reported in #bug-dump; related to BE-999 but frontend-only.

Root cause

Clicking "Upgrade to add credits" does nothing and changes nothing. Merely opening Settings ▸ Credits is what breaks the flow.

On a non-cloud build isActiveSubscription is hardwired true (isSubscribedOrIsNotCloud returns true whenever !isCloud), so isFreeTier is the only live term in the top-up subscription gate.

Nothing fetches subscription status on a local boot — useBillingContext's init watcher returns early because activeWorkspace?.id is undefined off cloud. CreditsTile's onMounted(handleRefresh) is the first and only thing that ever calls fetchStatus(), so opening Settings ▸ Credits sets tier: "FREE" and latches isFreeTier true for the shared billing context.

From then on showTopUpCreditsDialog() routes into showSubscriptionRequiredDialog(), which returns immediately when !isCloud — a permanent silent no-op until restart. Independently, CreditsTile rendered v-if="isFreeTier" "Upgrade to add credits" with no distribution guard, whose handler showPricingTable() also returns on !isCloud.

Measured in a real DISTRIBUTION=localhost build, signed in, with /customers/cloud-subscription-status returning {is_active: true, subscription_tier: "FREE"}:

step tier isFreeTier click → dialogStack
popover, before Settings null false ["top-up-credits"]
Settings ▸ Credits mounted "FREE" true
popover, after Settings "FREE" true [] — silent no-op

Changes

  • dialogService.showTopUpCreditsDialog — apply the subscription gate only on cloud. Off cloud there is no subscribe flow, so diverting there strands the purchase dialog. This is the load-bearing fix.
  • CreditsTile.vue — gate the "Upgrade to add credits" CTA on isCloud; local users keep "Add credits".
  • CurrentUserPopoverWorkspace.vue — gate the upgrade CTA, "Plans & pricing", and the subscribe/resubscribe prompt on isCloud, matching guards CurrentUserPopoverLegacy.vue already has. Cloud-side hardening: this component never renders off cloud, since teamWorkspacesEnabled is hard-false there.

Regression lineage

The visible CTA entered ungated in 026b2c4 (#12734, FE-964, 2026-06-25), which replaced LegacyCreditsPanel.vue with the facade-driven CreditsTile. The old panel had no free-tier branch and never called fetchStatus. First shipped in v1.47.4.

It became invisible again in v1.48.4 via 51884bc (#13812), which added hasActiveWorkspace to getPermissions — off cloud activeWorkspace is null, so canTopUp is false and showActionButton suppresses the whole block. That was accidental masking, not a fix.

Visible-CTA window: v1.47.4 → v1.48.3. Reproduced empirically in a v1.47.4 build. The popover was never affected — CurrentUserPopoverLegacy has had its isCloud guard since #11463 (v1.44.7) — which is why the customer saw the button only in Settings ▸ Credits.

The top-up dead-end still exists at HEAD, independent of the CTA: v1.48.4 hid the button but left onMounted(handleRefresh) untouched. That is the part that needs to ship.

Why the e2e suite missed it

Not a coverage-volume problem — a structural one. ComfyPage only mocked auth for @cloud-tagged tests:

if (testInfo.tags.includes('@cloud')) {
  await comfyPage.cloudAuth.mockAuth()
}

@cloud is a project-routing tag: it excludes a spec from the chromium project (grepInvert: /…|@cloud/) and routes it to the cloud project, which runs the frontend-dist-cloud artifact built with pnpm build:cloud. So getting a signed-in user required the tag that guarantees isCloud === true. Every credits/billing spec is @cloud-tagged, making local coverage impossible to write.

The unit layer had the mirror-image blind spot: vitest.setup.ts pins __DISTRIBUTION__ = 'localhost', but CreditsTile.vue never read the distribution, and dialogService.topUpCredits.test.ts hard-stubbed isCloud: true — so those tests asserted cloud semantics while nominally running local.

Fixed by adding an @auth tag so auth mocking is independent of project routing, plus browser_tests/tests/localCreditsGating.spec.ts (@oss @auth) walking the reported journey on the localhost bundle. Unit specs now drive isCloud through a mockable getter and cover both distributions.

Each new test was verified to fail against the unfixed source and pass with the fix.

Verification

  • pnpm typecheck, pnpm typecheck:browser, pnpm lint, pnpm knip clean; pre-commit gates green.
  • 1817 unit tests pass across subscription / billing / services / workspace / topbar / dialog.
  • Manual: real browser against a DISTRIBUTION=localhost dev server (isCloud === false read at runtime), signed in via the CloudAuthHelper Firebase-IndexedDB technique, billing endpoints mocked to a FREE tier. Walked the customer's exact steps with and without the fix, and against a v1.47.4 build.
  • The new Playwright spec was not executed here (no CI backend in the sandbox); it is written against existing fixtures and typechecks under typecheck:browser.

Notes

  • No competing branch exists for this fix. remove-team-ff also edits CurrentUserPopoverWorkspace.vue, so expect a small conflict; it keeps that popover cloud-only (v-if="isCloud"), so there is no behavioural clash.
  • Follow-up, not in this PR: canRunWorkflows folds isFreeTier into free-tier quota, so the same latch could swap the Run button for "Subscribe to run" on local. Currently inert only because freeTierJobAllowanceEnabled uses resolveFlag (default false) rather than being distribution-gated.

Screenshots

v1.47.4 local build, Settings > Credits: the gradient 'Upgrade to add credits' CTA the customer reported. Clicking it is a dead click.

Before the fix: after visiting Settings > Credits, clicking 'Add credits' in the profile popover does nothing - no dialog opens.

After the fix: the same sequence opens the 'Add more credits' top-up dialog as expected.

After the fix: Settings > Credits on a local build shows the balance with no subscribe or upgrade references.

On a non-cloud build `isActiveSubscription` is hardwired true
(`isSubscribedOrIsNotCloud`), so `isFreeTier` is the only live term in the
top-up subscription gate. Nothing fetches subscription status on a local
boot until Settings > Credits mounts CreditsTile, whose
`onMounted(handleRefresh)` sets tier=FREE and latches `isFreeTier` true for
the shared billing context. From then on `showTopUpCreditsDialog` routes
into `showSubscriptionRequiredDialog`, which returns immediately when
`!isCloud` — the purchase flow silently dies until app restart.

Gate that diversion on `isCloud`, and gate the cloud-only upgrade/pricing
CTAs so a local user is never offered a dialog that cannot open.

E2E never caught this: `ComfyPage` only mocked auth for `@cloud`-tagged
tests, and `@cloud` routes a spec to the cloud project (cloud bundle,
`isCloud === true`). Signed-in credits coverage was therefore impossible on
the localhost bundle. Add an `@auth` tag so auth mocking is independent of
project routing, plus an `@oss @auth` spec covering the reported journey.
Third subscribe surface in the same component; its handler bottoms out in
showPricingTable, which returns on !isCloud. The legacy popover already
gates the equivalent block, so this brings the two to parity.
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

🎭 Playwright: ✅ 1781 passed, 0 failed · 1 flaky

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

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 08/03/2026, 02:16:59 AM UTC

Links

📦 Bundle: 8.21 MB gzip 🟢 -28 B

Details

Summary

  • Raw size: 34.5 MB baseline 34.5 MB — 🟢 -240 B
  • Gzip: 8.21 MB baseline 8.21 MB — 🟢 -28 B
  • Brotli: 5.68 MB baseline 5.68 MB — 🟢 -213 B
  • Bundles: 427 current • 427 baseline • 144 added / 144 removed

Category Glance
Data & Services 🟢 -195 B (3.45 MB) · Other 🟢 -45 B (12.7 MB) · Vendor & Third-Party ⚪ 0 B (15.7 MB) · Graph Workspace ⚪ 0 B (1.29 MB) · Panels & Settings ⚪ 0 B (551 kB) · Utilities & Hooks ⚪ 0 B (386 kB) · + 5 more

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

Main entry bundles and manifests

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

Status: 1 added / 1 removed

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

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-CmdLyTh7.js (new) 1.29 MB 🔴 +1.29 MB 🔴 +276 kB 🔴 +208 kB
assets/GraphView-XDLUXkDH.js (removed) 1.29 MB 🟢 -1.29 MB 🟢 -276 kB 🟢 -208 kB

Status: 1 added / 1 removed / 1 unchanged

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

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-ChFRjgMV.js (removed) 24.9 kB 🟢 -24.9 kB 🟢 -6.22 kB 🟢 -5.51 kB
assets/CloudSurveyView-Nt6tjEib.js (new) 24.9 kB 🔴 +24.9 kB 🔴 +6.22 kB 🔴 +5.51 kB
assets/CloudLoginView-5oYb5JLb.js (removed) 11.6 kB 🟢 -11.6 kB 🟢 -3.1 kB 🟢 -2.73 kB
assets/CloudLoginView-Bd006GMT.js (new) 11.6 kB 🔴 +11.6 kB 🔴 +3.11 kB 🔴 +2.73 kB
assets/CloudSignupView-CAJdXG3K.js (new) 9.9 kB 🔴 +9.9 kB 🔴 +2.78 kB 🔴 +2.44 kB
assets/CloudSignupView-CLrDYO90.js (removed) 9.9 kB 🟢 -9.9 kB 🟢 -2.78 kB 🟢 -2.43 kB
assets/CloudLayoutView-D0xF153R.js (removed) 9.48 kB 🟢 -9.48 kB 🟢 -2.31 kB 🟢 -2 kB
assets/CloudLayoutView-D3w6X5-M.js (new) 9.48 kB 🔴 +9.48 kB 🔴 +2.31 kB 🔴 +1.99 kB
assets/UserCheckView-C1tj9jb9.js (new) 8.75 kB 🔴 +8.75 kB 🔴 +2.19 kB 🔴 +1.9 kB
assets/UserCheckView-NjG6l8ZL.js (removed) 8.75 kB 🟢 -8.75 kB 🟢 -2.19 kB 🟢 -1.9 kB
assets/WidgetTextPreview-D6kq-BTs.js (new) 6.07 kB 🔴 +6.07 kB 🔴 +2.13 kB 🔴 +1.9 kB
assets/WidgetTextPreview-DMTkO-nF.js (removed) 6.07 kB 🟢 -6.07 kB 🟢 -2.13 kB 🟢 -1.89 kB
assets/CloudSubscriptionRedirectView-d-QCQ9s7.js (removed) 5.99 kB 🟢 -5.99 kB 🟢 -2.23 kB 🟢 -1.94 kB
assets/CloudSubscriptionRedirectView-LI8V2bRC.js (new) 5.99 kB 🔴 +5.99 kB 🔴 +2.23 kB 🔴 +1.94 kB
assets/UserSelectView-CoRiuaM0.js (new) 5.49 kB 🔴 +5.49 kB 🔴 +1.95 kB 🔴 +1.72 kB
assets/UserSelectView-DwUcbbe6.js (removed) 5.49 kB 🟢 -5.49 kB 🟢 -1.96 kB 🟢 -1.71 kB
assets/CloudForgotPasswordView-CqdgUm9B.js (removed) 5.09 kB 🟢 -5.09 kB 🟢 -1.73 kB 🟢 -1.51 kB
assets/CloudForgotPasswordView-DChQDQct.js (new) 5.09 kB 🔴 +5.09 kB 🔴 +1.73 kB 🔴 +1.51 kB
assets/CloudAuthTimeoutView-BtAbV-R0.js (new) 4.43 kB 🔴 +4.43 kB 🔴 +1.54 kB 🔴 +1.33 kB
assets/CloudAuthTimeoutView-Te_W1KW0.js (removed) 4.43 kB 🟢 -4.43 kB 🟢 -1.53 kB 🟢 -1.34 kB
assets/OAuthLayoutView-DkKrzslK.js (new) 1.31 kB 🔴 +1.31 kB 🔴 +699 B 🔴 +593 B
assets/OAuthLayoutView-r1PkMZS0.js (removed) 1.31 kB 🟢 -1.31 kB 🟢 -700 B 🟢 -594 B
assets/WidgetTextPreview-CFxKgaaa.js (new) 131 B 🔴 +131 B 🔴 +100 B 🔴 +88 B
assets/WidgetTextPreview-DDOekhY3.js (removed) 131 B 🟢 -131 B 🟢 -100 B 🟢 -90 B

Status: 12 added / 12 removed / 4 unchanged

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

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/KeybindingPanel-9V4vAIKa.js (removed) 49.4 kB 🟢 -49.4 kB 🟢 -9.94 kB 🟢 -8.81 kB
assets/KeybindingPanel-CaDrpqaQ.js (new) 49.4 kB 🔴 +49.4 kB 🔴 +9.95 kB 🔴 +8.82 kB
assets/SecretsPanel-cXQYnq92.js (removed) 33.7 kB 🟢 -33.7 kB 🟢 -7.86 kB 🟢 -6.89 kB
assets/SecretsPanel-D9siAwTE.js (new) 33.7 kB 🔴 +33.7 kB 🔴 +7.86 kB 🔴 +6.89 kB
assets/CreditsPanel-4TCkKzBc.js (removed) 15.9 kB 🟢 -15.9 kB 🟢 -4.63 kB 🟢 -4.07 kB
assets/CreditsPanel-DQYsRLdL.js (new) 15.9 kB 🔴 +15.9 kB 🔴 +4.63 kB 🔴 +4.06 kB
assets/SubscriptionPanel-D80v13J1.js (new) 11.5 kB 🔴 +11.5 kB 🔴 +3.64 kB 🔴 +3.21 kB
assets/SubscriptionPanel-qKIGHrKF.js (removed) 11.5 kB 🟢 -11.5 kB 🟢 -3.64 kB 🟢 -3.21 kB
assets/AboutPanel-CAhX8lCv.js (removed) 11.2 kB 🟢 -11.2 kB 🟢 -3.03 kB 🟢 -2.71 kB
assets/AboutPanel-DxHnYsTz.js (new) 11.2 kB 🔴 +11.2 kB 🔴 +3.02 kB 🔴 +2.71 kB
assets/ExtensionPanel-aAXB7dbX.js (removed) 9.19 kB 🟢 -9.19 kB 🟢 -2.51 kB 🟢 -2.22 kB
assets/ExtensionPanel-W52wo3Ou.js (new) 9.19 kB 🔴 +9.19 kB 🔴 +2.51 kB 🔴 +2.22 kB
assets/ServerConfigPanel-B6HnzJSu.js (removed) 6.09 kB 🟢 -6.09 kB 🟢 -1.94 kB 🟢 -1.73 kB
assets/ServerConfigPanel-BDxH2oHE.js (new) 6.09 kB 🔴 +6.09 kB 🔴 +1.94 kB 🔴 +1.73 kB
assets/UserPanel-CkcdGLyk.js (removed) 5.73 kB 🟢 -5.73 kB 🟢 -1.78 kB 🟢 -1.55 kB
assets/UserPanel-KLdfjJn5.js (new) 5.73 kB 🔴 +5.73 kB 🔴 +1.78 kB 🔴 +1.55 kB
assets/refreshRemoteConfig-BlMo88my.js (removed) 2.94 kB 🟢 -2.94 kB 🟢 -1.26 kB 🟢 -1.11 kB
assets/refreshRemoteConfig-nNvdDcME.js (new) 2.94 kB 🔴 +2.94 kB 🔴 +1.26 kB 🔴 +1.12 kB
assets/cloudRemoteConfig-AJQa_UJs.js (removed) 933 B 🟢 -933 B 🟢 -504 B 🟢 -421 B
assets/cloudRemoteConfig-CuynR-sw.js (new) 933 B 🔴 +933 B 🔴 +505 B 🔴 +417 B
assets/refreshRemoteConfig-DqyrS3d3.js (new) 110 B 🔴 +110 B 🔴 +89 B 🔴 +83 B
assets/refreshRemoteConfig-DstvaWCE.js (removed) 110 B 🟢 -110 B 🟢 -89 B 🟢 -88 B

Status: 11 added / 11 removed / 15 unchanged

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

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/SignUpForm-BVysHRzC.js (new) 12.2 kB 🔴 +12.2 kB 🔴 +4.15 kB 🔴 +3.62 kB
assets/SignUpForm-CIg5TYZC.js (removed) 12.2 kB 🟢 -12.2 kB 🟢 -4.15 kB 🟢 -3.62 kB
assets/auth-B52E3v2e.js (removed) 3.65 kB 🟢 -3.65 kB 🟢 -1.27 kB 🟢 -1.09 kB
assets/auth-CuPUWTLW.js (new) 3.65 kB 🔴 +3.65 kB 🔴 +1.27 kB 🔴 +1.09 kB
assets/usePostAuthRedirect-CgQphUWx.js (new) 3.28 kB 🔴 +3.28 kB 🔴 +1.24 kB 🔴 +1.08 kB
assets/usePostAuthRedirect-Cn_0Rc2J.js (removed) 3.28 kB 🟢 -3.28 kB 🟢 -1.24 kB 🟢 -1.08 kB
assets/UpdatePasswordContent-Bc5syrTn.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -839 B 🟢 -726 B
assets/UpdatePasswordContent-Dil_IduK.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +838 B 🔴 +731 B
assets/authStore-CWhqbYK6.js (removed) 128 B 🟢 -128 B 🟢 -107 B 🟢 -103 B
assets/authStore-le4QvFG7.js (new) 128 B 🔴 +128 B 🔴 +107 B 🔴 +99 B
assets/workspaceAuthStore-B2VSSxw6.js (removed) 108 B 🟢 -108 B 🟢 -99 B 🟢 -107 B
assets/workspaceAuthStore-DOrKo8kG.js (new) 108 B 🔴 +108 B 🔴 +99 B 🔴 +112 B
assets/auth-BWJ7BLP0.js (new) 105 B 🔴 +105 B 🔴 +96 B 🔴 +79 B
assets/auth-C4UxgwWt.js (removed) 105 B 🟢 -105 B 🟢 -96 B 🟢 -74 B

Status: 7 added / 7 removed / 3 unchanged

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

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyHubPublishDialog-B14blq7H.js (new) 90 kB 🔴 +90 kB 🔴 +19.2 kB 🔴 +16.4 kB
assets/ComfyHubPublishDialog-CVjdy6Ie.js (removed) 90 kB 🟢 -90 kB 🟢 -19.2 kB 🟢 -16.5 kB
assets/useShareDialog-9PFJSsYa.js (removed) 23.9 kB 🟢 -23.9 kB 🟢 -5.69 kB 🟢 -5.03 kB
assets/useShareDialog-CeRNTySM.js (new) 23.9 kB 🔴 +23.9 kB 🔴 +5.69 kB 🔴 +5.04 kB
assets/feedbackDialog-BWz_hDYd.js (new) 4.45 kB 🔴 +4.45 kB 🔴 +1.87 kB 🔴 +1.59 kB
assets/feedbackDialog-C3znxtOD.js (removed) 4.45 kB 🟢 -4.45 kB 🟢 -1.87 kB 🟢 -1.59 kB
assets/useRangeEditor-BfNjUhnh.js (new) 3.23 kB 🔴 +3.23 kB 🔴 +1.13 kB 🔴 +1.04 kB
assets/useRangeEditor-V8rukiJ6.js (removed) 3.23 kB 🟢 -3.23 kB 🟢 -1.13 kB 🟢 -1.02 kB
assets/ComfyHubPublishDialog-7TzO5kfR.js (new) 143 B 🔴 +143 B 🔴 +105 B 🔴 +87 B
assets/ComfyHubPublishDialog-BqfMraW4.js (removed) 143 B 🟢 -143 B 🟢 -105 B 🟢 -92 B
assets/useSubscriptionDialog-C9C0yBuz.js (removed) 108 B 🟢 -108 B 🟢 -102 B 🟢 -96 B
assets/useSubscriptionDialog-sAHUSzEZ.js (new) 108 B 🔴 +108 B 🔴 +102 B 🔴 +94 B

Status: 6 added / 6 removed / 1 unchanged

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-E8DPbKv9.js (removed) 13.5 kB 🟢 -13.5 kB 🟢 -3.73 kB 🟢 -3.31 kB
assets/ComfyQueueButton-i7rU1nfR.js (new) 13.5 kB 🔴 +13.5 kB 🔴 +3.73 kB 🔴 +3.31 kB
assets/useTerminalTabs-BuNyWdXU.js (new) 11.8 kB 🔴 +11.8 kB 🔴 +3.69 kB 🔴 +3.26 kB
assets/useTerminalTabs-K3sdnI0e.js (removed) 11.8 kB 🟢 -11.8 kB 🟢 -3.69 kB 🟢 -3.26 kB
assets/InviteMembersForm-Bo-GB1il.js (removed) 7.96 kB 🟢 -7.96 kB 🟢 -2.64 kB 🟢 -2.37 kB
assets/InviteMembersForm-C1cCoS4n.js (new) 7.96 kB 🔴 +7.96 kB 🔴 +2.64 kB 🔴 +2.36 kB
assets/SubscribeButton-BPMW-zas.js (removed) 2.13 kB 🟢 -2.13 kB 🟢 -956 B 🟢 -834 B
assets/SubscribeButton-Cd8IHExg.js (new) 2.13 kB 🔴 +2.13 kB 🔴 +955 B 🔴 +833 B
assets/cloudFeedbackTopbarButton-6dnRbnrK.js (removed) 705 B 🟢 -705 B 🟢 -423 B 🟢 -360 B
assets/cloudFeedbackTopbarButton-BGDSrQ81.js (new) 705 B 🔴 +705 B 🔴 +425 B 🔴 +362 B
assets/ComfyQueueButton-Bfy9-iiL.js (new) 128 B 🔴 +128 B 🔴 +99 B 🔴 +90 B
assets/ComfyQueueButton-CEvyUVRD.js (removed) 128 B 🟢 -128 B 🟢 -99 B 🟢 -88 B

Status: 6 added / 6 removed / 9 unchanged

Data & Services — 3.45 MB (baseline 3.45 MB) • 🟢 -195 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/settingStore-Oaca3My7.js (removed) 3.17 MB 🟢 -3.17 MB 🟢 -734 kB 🟢 -553 kB
assets/settingStore-DJ6QweP9.js (new) 3.17 MB 🔴 +3.17 MB 🔴 +734 kB 🔴 +553 kB
assets/load3dService-B_6QhPL4.js (new) 132 kB 🔴 +132 kB 🔴 +29.2 kB 🔴 +24.6 kB
assets/load3dService-DEoJcs-w.js (removed) 132 kB 🟢 -132 kB 🟢 -29.2 kB 🟢 -24.6 kB
assets/api-DUjP5o57.js (removed) 93.4 kB 🟢 -93.4 kB 🟢 -25.8 kB 🟢 -22.1 kB
assets/api-XLFwL4ln.js (new) 93.4 kB 🔴 +93.4 kB 🔴 +25.8 kB 🔴 +22.1 kB
assets/workflowShareService-Br44yKGB.js (removed) 16.4 kB 🟢 -16.4 kB 🟢 -4.89 kB 🟢 -4.33 kB
assets/workflowShareService-CPSE9Kwk.js (new) 16.4 kB 🔴 +16.4 kB 🔴 +4.89 kB 🔴 +4.33 kB
assets/keybindingService-Cb_322Y7.js (removed) 7.08 kB 🟢 -7.08 kB 🟢 -1.82 kB 🟢 -1.58 kB
assets/keybindingService-Cy7KduM_.js (new) 7.08 kB 🔴 +7.08 kB 🔴 +1.82 kB 🔴 +1.58 kB
assets/releaseStore-BRRJPqlz.js (removed) 6.72 kB 🟢 -6.72 kB 🟢 -2.03 kB 🟢 -1.78 kB
assets/releaseStore-bx2t0s9w.js (new) 6.72 kB 🔴 +6.72 kB 🔴 +2.03 kB 🔴 +1.77 kB
assets/systemStatsStore-D1jiOUMQ.js (removed) 4.93 kB 🟢 -4.93 kB 🟢 -1.74 kB 🟢 -1.47 kB
assets/systemStatsStore-DG8gjEDr.js (new) 4.93 kB 🔴 +4.93 kB 🔴 +1.74 kB 🔴 +1.47 kB
assets/userStore-CIAX8ACZ.js (removed) 2.38 kB 🟢 -2.38 kB 🟢 -898 B 🟢 -795 B
assets/userStore-DbCaI2vR.js (new) 2.38 kB 🔴 +2.38 kB 🔴 +898 B 🔴 +794 B
assets/audioService-42KHHZFD.js (removed) 1.71 kB 🟢 -1.71 kB 🟢 -829 B 🟢 -724 B
assets/audioService-DPncouq3.js (new) 1.71 kB 🔴 +1.71 kB 🔴 +830 B 🔴 +723 B
assets/dialogService-BoQoS_8i.js (removed) 98 B 🟢 -98 B 🟢 -97 B 🟢 -84 B
assets/dialogService-D82sEVbC.js (new) 98 B 🔴 +98 B 🔴 +97 B 🔴 +82 B
assets/releaseStore-DDxQL6Pl.js (removed) 95 B 🟢 -95 B 🟢 -86 B 🟢 -85 B
assets/releaseStore-ifKVqCSn.js (new) 95 B 🔴 +95 B 🔴 +86 B 🔴 +77 B
assets/settingStore-CAAhTsdC.js (removed) 95 B 🟢 -95 B 🟢 -86 B 🟢 -86 B
assets/settingStore-DlKjb-Q5.js (new) 95 B 🔴 +95 B 🔴 +86 B 🔴 +90 B
assets/assetsStore-h7xSuLBX.js (new) 94 B 🔴 +94 B 🔴 +92 B 🔴 +85 B
assets/assetsStore-JgIKAfWR.js (removed) 94 B 🟢 -94 B 🟢 -92 B 🟢 -86 B
assets/api-4h7vi_RI.js (new) 62 B 🔴 +62 B 🔴 +74 B 🔴 +66 B
assets/api-Cd7Dz3F7.js (removed) 62 B 🟢 -62 B 🟢 -74 B 🟢 -66 B

Status: 14 added / 14 removed / 3 unchanged

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

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useConflictDetection-BrJCX94r.js (new) 235 kB 🔴 +235 kB 🔴 +52.5 kB 🔴 +42.7 kB
assets/useConflictDetection-C137DYhM.js (removed) 235 kB 🟢 -235 kB 🟢 -52.5 kB 🟢 -42.7 kB
assets/useLoad3d-D5EIyZxq.js (removed) 25.7 kB 🟢 -25.7 kB 🟢 -5.79 kB 🟢 -5.13 kB
assets/useLoad3d-Sy1QBe-7.js (new) 25.7 kB 🔴 +25.7 kB 🔴 +5.79 kB 🔴 +5.13 kB
assets/useLoad3dViewer-COoCDP8k.js (new) 21.2 kB 🔴 +21.2 kB 🔴 +4.98 kB 🔴 +4.37 kB
assets/useLoad3dViewer-yxgZsBfJ.js (removed) 21.2 kB 🟢 -21.2 kB 🟢 -4.98 kB 🟢 -4.38 kB
assets/useImageCrop-Djz8t6bj.js (removed) 15 kB 🟢 -15 kB 🟢 -3.42 kB 🟢 -2.98 kB
assets/useImageCrop-gn4daZv5.js (new) 15 kB 🔴 +15 kB 🔴 +3.42 kB 🔴 +2.98 kB
assets/useDowngradeToPersonal-nlTgxffJ.js (new) 8.85 kB 🔴 +8.85 kB 🔴 +2.53 kB 🔴 +2.17 kB
assets/useDowngradeToPersonal-zMv7v64m.js (removed) 8.85 kB 🟢 -8.85 kB 🟢 -2.53 kB 🟢 -2.17 kB
assets/useFeatureFlags-aWYOxMli.js (new) 7.31 kB 🔴 +7.31 kB 🔴 +2.18 kB 🔴 +1.83 kB
assets/useFeatureFlags-B8zwf5-4.js (removed) 7.31 kB 🟢 -7.31 kB 🟢 -2.18 kB 🟢 -1.83 kB
assets/assetPreviewUtil-BdmstwWs.js (removed) 2.35 kB 🟢 -2.35 kB 🟢 -968 B 🟢 -837 B
assets/assetPreviewUtil-C4odg3Th.js (new) 2.35 kB 🔴 +2.35 kB 🔴 +969 B 🔴 +835 B
assets/useUpstreamValue-Cd1gwQTc.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +759 B 🔴 +675 B
assets/useUpstreamValue-Dw93IDzp.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -759 B 🟢 -677 B
assets/useWorkspaceTierLabel-BaasxS72.js (new) 1.93 kB 🔴 +1.93 kB 🔴 +814 B 🔴 +700 B
assets/useWorkspaceTierLabel-DNIpfQBG.js (removed) 1.93 kB 🟢 -1.93 kB 🟢 -813 B 🟢 -694 B
assets/subscriptionCheckoutUtil-CQ8oAhXa.js (new) 841 B 🔴 +841 B 🔴 +503 B 🔴 +424 B
assets/subscriptionCheckoutUtil-tBvPYNKw.js (removed) 841 B 🟢 -841 B 🟢 -503 B 🟢 -424 B
assets/useSessionCookie-D4DB9NlG.js (new) 692 B 🔴 +692 B 🔴 +355 B 🔴 +312 B
assets/useSessionCookie-DhX30yQg.js (removed) 692 B 🟢 -692 B 🟢 -356 B 🟢 -333 B
assets/useLoad3d-D5JOvDqo.js (removed) 311 B 🟢 -311 B 🟢 -165 B 🟢 -148 B
assets/useLoad3d-eiLj6DDB.js (new) 311 B 🔴 +311 B 🔴 +164 B 🔴 +148 B
assets/useSessionCookie-DbbfPWig.js (new) 101 B 🔴 +101 B 🔴 +86 B 🔴 +83 B
assets/useSessionCookie-DcAz0Rka.js (removed) 101 B 🟢 -101 B 🟢 -86 B 🟢 -80 B
assets/useFeatureFlags-6owpgQ0J.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -82 B
assets/useFeatureFlags-BgcsUfeP.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +82 B
assets/useLoad3dViewer-CgAz47YE.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +85 B
assets/useLoad3dViewer-DxxnBfHI.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -88 B
assets/useCurrentUser-BJRxY-Yg.js (removed) 94 B 🟢 -94 B 🟢 -95 B 🟢 -86 B
assets/useCurrentUser-MQyPuXIX.js (new) 94 B 🔴 +94 B 🔴 +95 B 🔴 +94 B

Status: 16 added / 16 removed / 20 unchanged

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

External libraries and shared vendor chunks

Status: 16 unchanged

Other — 12.7 MB (baseline 12.8 MB) • 🟢 -45 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-5wx5-bfb.js (removed) 111 kB 🟢 -111 kB 🟢 -28.7 kB 🟢 -24.3 kB
assets/core-CL_b-4vw.js (new) 111 kB 🔴 +111 kB 🔴 +28.7 kB 🔴 +24.3 kB
assets/WidgetSelect-CotvGBt7.js (new) 88 kB 🔴 +88 kB 🔴 +19.9 kB 🔴 +17 kB
assets/WidgetSelect-Zl1iJICe.js (removed) 88 kB 🟢 -88 kB 🟢 -19.9 kB 🟢 -17 kB
assets/Load3D-B6yfZMB9.js (removed) 71.3 kB 🟢 -71.3 kB 🟢 -11.7 kB 🟢 -9.99 kB
assets/Load3D-DgQVYv32.js (new) 71.3 kB 🔴 +71.3 kB 🔴 +11.7 kB 🔴 +9.98 kB
assets/WidgetVideoEdit-CRpfKqoM.js (new) 63.4 kB 🔴 +63.4 kB 🔴 +14.6 kB 🔴 +12.8 kB
assets/WidgetVideoEdit-iiQEvXzR.js (removed) 63.4 kB 🟢 -63.4 kB 🟢 -14.6 kB 🟢 -12.9 kB
assets/SubscriptionTransitionPreviewWorkspace-B0zEbvc7.js (removed) 63.1 kB 🟢 -63.1 kB 🟢 -13 kB 🟢 -11.3 kB
assets/SubscriptionTransitionPreviewWorkspace-Be7LuOYZ.js (new) 63.1 kB 🔴 +63.1 kB 🔴 +13 kB 🔴 +11.4 kB
assets/WorkspaceSettingsPanelContent-7jDox8dt.js (new) 61.6 kB 🔴 +61.6 kB 🔴 +13.2 kB 🔴 +11.5 kB
assets/WorkspaceSettingsPanelContent-CT6vpYJO.js (removed) 61.6 kB 🟢 -61.6 kB 🟢 -13.2 kB 🟢 -11.5 kB
assets/Preview3d-B-L2LsJ-.js (new) 50.9 kB 🔴 +50.9 kB 🔴 +8.31 kB 🔴 +7.25 kB
assets/Preview3d-BOzYkxgN.js (removed) 50.9 kB 🟢 -50.9 kB 🟢 -8.31 kB 🟢 -7.23 kB
assets/main-B-v1O9xX.js (removed) 46.9 kB 🟢 -46.9 kB 🟢 -13.8 kB 🟢 -12 kB
assets/main-BgeoHAUN.js (new) 46.9 kB 🔴 +46.9 kB 🔴 +13.8 kB 🔴 +12 kB
assets/SubscriptionRequiredDialogContentUnified-o4jw-_4E.js (removed) 42.7 kB 🟢 -42.7 kB 🟢 -9.42 kB 🟢 -8.21 kB
assets/SubscriptionRequiredDialogContentUnified-PB4nDhA4.js (new) 42.7 kB 🔴 +42.7 kB 🔴 +9.43 kB 🔴 +8.21 kB
assets/MembersPanelContent-B6TRQlcv.js (new) 41.8 kB 🔴 +41.8 kB 🔴 +8.79 kB 🔴 +7.82 kB
assets/MembersPanelContent-KTowO-6E.js (removed) 41.8 kB 🟢 -41.8 kB 🟢 -8.79 kB 🟢 -7.83 kB
assets/WidgetBoundingBoxes-DZnWG_OY.js (removed) 33.7 kB 🟢 -33.7 kB 🟢 -9.16 kB 🟢 -8.13 kB
assets/WidgetBoundingBoxes-XJBCQTsE.js (new) 33.7 kB 🔴 +33.7 kB 🔴 +9.16 kB 🔴 +8.13 kB
assets/WidgetPainter-DHuW_SMQ.js (removed) 32.6 kB 🟢 -32.6 kB 🟢 -7.87 kB 🟢 -6.97 kB
assets/WidgetPainter-DYTE56MG.js (new) 32.6 kB 🔴 +32.6 kB 🔴 +7.87 kB 🔴 +6.96 kB
assets/SubscriptionPanelContentWorkspace-CnZ2sjlA.js (new) 31.8 kB 🔴 +31.8 kB 🔴 +7.05 kB 🔴 +6.2 kB
assets/SubscriptionPanelContentWorkspace-DOoLRcWI.js (removed) 31.8 kB 🟢 -31.8 kB 🟢 -7.05 kB 🟢 -6.21 kB
assets/Load3dViewerContent-C6C2ssKz.js (removed) 30.8 kB 🟢 -30.8 kB 🟢 -6.26 kB 🟢 -5.44 kB
assets/Load3dViewerContent-HgOG6LA5.js (new) 30.8 kB 🔴 +30.8 kB 🔴 +6.26 kB 🔴 +5.44 kB
assets/SubscriptionRequiredDialogContent-BmEYXfxq.js (removed) 26.1 kB 🟢 -26.1 kB 🟢 -6.14 kB 🟢 -5.4 kB
assets/SubscriptionRequiredDialogContent-Bu4XSYPT.js (new) 26.1 kB 🔴 +26.1 kB 🔴 +6.14 kB 🔴 +5.4 kB
assets/SubscriptionRequiredDialogContentWorkspace-DXmhgoUO.js (removed) 25.1 kB 🟢 -25.1 kB 🟢 -5.8 kB 🟢 -5.11 kB
assets/SubscriptionRequiredDialogContentWorkspace-PJGMT5fn.js (new) 25.1 kB 🔴 +25.1 kB 🔴 +5.8 kB 🔴 +5.11 kB
assets/load3d-8YobZW3U.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -5.41 kB 🟢 -4.67 kB
assets/load3d-DqoZd01L.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +5.41 kB 🔴 +4.67 kB
assets/CurrentUserPopoverWorkspace-FI0MJJ1R.js (removed) 20.5 kB 🟢 -20.5 kB 🟢 -4.69 kB 🟢 -4.17 kB
assets/CurrentUserPopoverWorkspace-CtemmRot.js (new) 20.3 kB 🔴 +20.3 kB 🔴 +4.67 kB 🔴 +4.16 kB
assets/SignInContent-C8Gkkgjs.js (removed) 20.2 kB 🟢 -20.2 kB 🟢 -5.1 kB 🟢 -4.45 kB
assets/SignInContent-DHAzEQE8.js (new) 20.2 kB 🔴 +20.2 kB 🔴 +5.1 kB 🔴 +4.45 kB
assets/CreditsTile-R7rkQMUB.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.8 kB 🔴 +4.22 kB
assets/CreditsTile-uE8qOReh.js (removed) 19 kB 🟢 -19 kB 🟢 -4.77 kB 🟢 -4.21 kB
assets/WidgetRecordAudio-C8aHLzNU.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.6 kB 🟢 -4.09 kB
assets/WidgetRecordAudio-R_erBT1M.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.6 kB 🔴 +4.09 kB
assets/WidgetInputNumber-B4VIuMg5.js (new) 13.9 kB 🔴 +13.9 kB 🔴 +3.63 kB 🔴 +3.21 kB
assets/WidgetInputNumber-Ci8KDjhp.js (removed) 13.9 kB 🟢 -13.9 kB 🟢 -3.63 kB 🟢 -3.21 kB
assets/WidgetRange-BTG2oz8U.js (new) 13.7 kB 🔴 +13.7 kB 🔴 +3.54 kB 🔴 +3.12 kB
assets/WidgetRange-Cab1AO0B.js (removed) 13.7 kB 🟢 -13.7 kB 🟢 -3.54 kB 🟢 -3.12 kB
assets/WaveAudioPlayer-BPZN-1xn.js (removed) 12.8 kB 🟢 -12.8 kB 🟢 -3.46 kB 🟢 -3.04 kB
assets/WaveAudioPlayer-nmkyTHKU.js (new) 12.8 kB 🔴 +12.8 kB 🔴 +3.46 kB 🔴 +3.04 kB
assets/WidgetCurve-C55t0adB.js (removed) 11.2 kB 🟢 -11.2 kB 🟢 -3.47 kB 🟢 -3.15 kB
assets/WidgetCurve-C71zDHMF.js (new) 11.2 kB 🔴 +11.2 kB 🔴 +3.48 kB 🔴 +3.15 kB
assets/TeamWorkspacesDialogContent-BOzhqaKa.js (new) 10.3 kB 🔴 +10.3 kB 🔴 +2.97 kB 🔴 +2.63 kB
assets/TeamWorkspacesDialogContent-pajHDBYa.js (removed) 10.3 kB 🟢 -10.3 kB 🟢 -2.97 kB 🟢 -2.63 kB
assets/onboardingCloudRoutes-BaBXZOms.js (new) 9.12 kB 🔴 +9.12 kB 🔴 +2.79 kB 🔴 +2.4 kB
assets/onboardingCloudRoutes-Eb3iU6Gn.js (removed) 9.12 kB 🟢 -9.12 kB 🟢 -2.79 kB 🟢 -2.4 kB
assets/Load3DConfiguration-D2GFfoXL.js (new) 8.91 kB 🔴 +8.91 kB 🔴 +2.61 kB 🔴 +2.3 kB
assets/Load3DConfiguration-UuZ6fQAQ.js (removed) 8.91 kB 🟢 -8.91 kB 🟢 -2.61 kB 🟢 -2.3 kB
assets/WidgetImageCrop-Dp5E3RUA.js (removed) 8.49 kB 🟢 -8.49 kB 🟢 -2.65 kB 🟢 -2.34 kB
assets/WidgetImageCrop-ZQcYrL_y.js (new) 8.49 kB 🔴 +8.49 kB 🔴 +2.65 kB 🔴 +2.34 kB
assets/SetMemberCreditLimitDialogContent-2DSiF08G.js (new) 8.47 kB 🔴 +8.47 kB 🔴 +2.34 kB 🔴 +2.05 kB
assets/SetMemberCreditLimitDialogContent-CpP5BAV_.js (removed) 8.47 kB 🟢 -8.47 kB 🟢 -2.34 kB 🟢 -2.05 kB
assets/nodeTemplates-Bg1es9fV.js (removed) 8.28 kB 🟢 -8.28 kB 🟢 -2.84 kB 🟢 -2.5 kB
assets/nodeTemplates-C42DCiK0.js (new) 8.28 kB 🔴 +8.28 kB 🔴 +2.84 kB 🔴 +2.5 kB
assets/NightlySurveyController-BFd95A7V.js (new) 7.5 kB 🔴 +7.5 kB 🔴 +2.56 kB 🔴 +2.24 kB
assets/NightlySurveyController-CKI3rwwI.js (removed) 7.5 kB 🟢 -7.5 kB 🟢 -2.55 kB 🟢 -2.24 kB
assets/WidgetWithControl-CcKHx_R3.js (removed) 6.37 kB 🟢 -6.37 kB 🟢 -2.59 kB 🟢 -2.3 kB
assets/WidgetWithControl-DFegngqt.js (new) 6.37 kB 🔴 +6.37 kB 🔴 +2.59 kB 🔴 +2.29 kB
assets/tierBenefits-GcmUrmyo.js (removed) 6.2 kB 🟢 -6.2 kB 🟢 -1.97 kB 🟢 -1.71 kB
assets/tierBenefits-kSSr5Ymx.js (new) 6.2 kB 🔴 +6.2 kB 🔴 +1.97 kB 🔴 +1.71 kB
assets/CancelSubscriptionDialogContent-DTcrrkkB.js (new) 5.97 kB 🔴 +5.97 kB 🔴 +1.98 kB 🔴 +1.74 kB
assets/CancelSubscriptionDialogContent-DteegBRn.js (removed) 5.97 kB 🟢 -5.97 kB 🟢 -1.98 kB 🟢 -1.74 kB
assets/load3dPreviewExtensions-C2BU_JGZ.js (removed) 5.88 kB 🟢 -5.88 kB 🟢 -1.81 kB 🟢 -1.6 kB
assets/load3dPreviewExtensions-ezcCEuyY.js (new) 5.88 kB 🔴 +5.88 kB 🔴 +1.81 kB 🔴 +1.6 kB
assets/missingModelDownload-Cy6TQ0G8.js (new) 5.88 kB 🔴 +5.88 kB 🔴 +2.07 kB 🔴 +1.81 kB
assets/missingModelDownload-D4oanbco.js (removed) 5.88 kB 🟢 -5.88 kB 🟢 -2.07 kB 🟢 -1.81 kB
assets/launchCancellationFlow-BiOwnrEl.js (removed) 5.18 kB 🟢 -5.18 kB 🟢 -1.78 kB 🟢 -1.55 kB
assets/launchCancellationFlow-DGDTf_Nu.js (new) 5.18 kB 🔴 +5.18 kB 🔴 +1.78 kB 🔴 +1.56 kB
assets/CreateWorkspaceDialogContent-CuKBFEJj.js (new) 5.12 kB 🔴 +5.12 kB 🔴 +1.79 kB 🔴 +1.55 kB
assets/CreateWorkspaceDialogContent-RsavlTgd.js (removed) 5.12 kB 🟢 -5.12 kB 🟢 -1.79 kB 🟢 -1.55 kB
assets/ChangeMemberRoleDialogContent-CSmGBJl6.js (new) 4.97 kB 🔴 +4.97 kB 🔴 +1.63 kB 🔴 +1.43 kB
assets/ChangeMemberRoleDialogContent-WwLzTHfX.js (removed) 4.97 kB 🟢 -4.97 kB 🟢 -1.63 kB 🟢 -1.43 kB
assets/EditWorkspaceDialogContent-igDOhiPd.js (new) 4.93 kB 🔴 +4.93 kB 🔴 +1.76 kB 🔴 +1.52 kB
assets/EditWorkspaceDialogContent-whTnHJ1f.js (removed) 4.93 kB 🟢 -4.93 kB 🟢 -1.76 kB 🟢 -1.52 kB
assets/WidgetTextarea-Cf1lBvGM.js (new) 4.81 kB 🔴 +4.81 kB 🔴 +1.87 kB 🔴 +1.63 kB
assets/WidgetTextarea-DCIBXkCx.js (removed) 4.81 kB 🟢 -4.81 kB 🟢 -1.87 kB 🟢 -1.63 kB
assets/saveMesh-C8BnL4cy.js (removed) 4.76 kB 🟢 -4.76 kB 🟢 -1.52 kB 🟢 -1.34 kB
assets/saveMesh-Drq57QWN.js (new) 4.76 kB 🔴 +4.76 kB 🔴 +1.52 kB 🔴 +1.34 kB
assets/WorkspacePanelContent-7fAmEVov.js (new) 4.72 kB 🔴 +4.72 kB 🔴 +1.6 kB 🔴 +1.4 kB
assets/WorkspacePanelContent-CTsWD08C.js (removed) 4.72 kB 🟢 -4.72 kB 🟢 -1.6 kB 🟢 -1.4 kB
assets/InviteMemberDialogContent-BBECGk3j.js (removed) 4.68 kB 🟢 -4.68 kB 🟢 -1.58 kB 🟢 -1.38 kB
assets/InviteMemberDialogContent-CkzPHsNA.js (new) 4.68 kB 🔴 +4.68 kB 🔴 +1.58 kB 🔴 +1.37 kB
assets/ValueControlPopover-BZ1hkfA3.js (new) 4.49 kB 🔴 +4.49 kB 🔴 +1.55 kB 🔴 +1.38 kB
assets/ValueControlPopover-C30Z2M41.js (removed) 4.49 kB 🟢 -4.49 kB 🟢 -1.54 kB 🟢 -1.38 kB
assets/DeleteWorkspaceDialogContent-DRNpy33v.js (new) 3.84 kB 🔴 +3.84 kB 🔴 +1.44 kB 🔴 +1.23 kB
assets/DeleteWorkspaceDialogContent-PFcPUicw.js (removed) 3.84 kB 🟢 -3.84 kB 🟢 -1.44 kB 🟢 -1.23 kB
assets/LeaveWorkspaceDialogContent-BQMuGYUT.js (removed) 3.67 kB 🟢 -3.67 kB 🟢 -1.38 kB 🟢 -1.19 kB
assets/LeaveWorkspaceDialogContent-kaZROHwc.js (new) 3.67 kB 🔴 +3.67 kB 🔴 +1.38 kB 🔴 +1.18 kB
assets/RemoveMemberDialogContent-BmwVDH20.js (removed) 3.65 kB 🟢 -3.65 kB 🟢 -1.33 kB 🟢 -1.15 kB
assets/RemoveMemberDialogContent-Cv7DFBIs.js (new) 3.65 kB 🔴 +3.65 kB 🔴 +1.34 kB 🔴 +1.15 kB
assets/RevokeInviteDialogContent-BhsXzKqU.js (new) 3.56 kB 🔴 +3.56 kB 🔴 +1.35 kB 🔴 +1.17 kB
assets/RevokeInviteDialogContent-BLe18j0R.js (removed) 3.56 kB 🟢 -3.56 kB 🟢 -1.35 kB 🟢 -1.17 kB
assets/InviteMemberUpsellDialogContent-BMscDXud.js (new) 3.44 kB 🔴 +3.44 kB 🔴 +1.23 kB 🔴 +1.08 kB
assets/InviteMemberUpsellDialogContent-D_XJCAiI.js (removed) 3.44 kB 🟢 -3.44 kB 🟢 -1.23 kB 🟢 -1.06 kB
assets/workspaceCheckoutTelemetry-BxNKwMoV.js (new) 3.4 kB 🔴 +3.4 kB 🔴 +1.53 kB 🔴 +1.33 kB
assets/workspaceCheckoutTelemetry-Crlu5s5J.js (removed) 3.4 kB 🟢 -3.4 kB 🟢 -1.52 kB 🟢 -1.33 kB
assets/Media3DTop-BG_Un3Ka.js (removed) 3.21 kB 🟢 -3.21 kB 🟢 -1.26 kB 🟢 -1.1 kB
assets/Media3DTop-ChqKL8TG.js (new) 3.21 kB 🔴 +3.21 kB 🔴 +1.26 kB 🔴 +1.1 kB
assets/GlobalToast-BvPadDwg.js (new) 3 kB 🔴 +3 kB 🔴 +1.22 kB 🔴 +1.06 kB
assets/GlobalToast-By6_ApSN.js (removed) 3 kB 🟢 -3 kB 🟢 -1.22 kB 🟢 -1.04 kB
assets/load3dAdvanced-C9QCb9QD.js (removed) 2.82 kB 🟢 -2.82 kB 🟢 -1.09 kB 🟢 -952 B
assets/load3dAdvanced-Ds8bxbNQ.js (new) 2.82 kB 🔴 +2.82 kB 🔴 +1.09 kB 🔴 +950 B
assets/SubscribeToRun-06mSm0SJ.js (removed) 2.39 kB 🟢 -2.39 kB 🟢 -1.03 kB 🟢 -903 B
assets/SubscribeToRun-BzLbdqTJ.js (new) 2.39 kB 🔴 +2.39 kB 🔴 +1.03 kB 🔴 +902 B
assets/MediaAudioTop-BdoOLJJ_.js (removed) 1.62 kB 🟢 -1.62 kB 🟢 -805 B 🟢 -663 B
assets/MediaAudioTop-pVNJ6wMs.js (new) 1.62 kB 🔴 +1.62 kB 🔴 +807 B 🔴 +666 B
assets/CloudRunButtonWrapper-BvuuEoV9.js (new) 1.05 kB 🔴 +1.05 kB 🔴 +514 B 🔴 +475 B
assets/CloudRunButtonWrapper-CXl0C7U9.js (removed) 1.05 kB 🟢 -1.05 kB 🟢 -517 B 🟢 -481 B
assets/cloudSessionCookie-BnzD132r.js (new) 933 B 🔴 +933 B 🔴 +434 B 🔴 +378 B
assets/cloudSessionCookie-BZXn09kY.js (removed) 933 B 🟢 -933 B 🟢 -433 B 🟢 -379 B
assets/cloudBadges-B0eetdrK.js (new) 922 B 🔴 +922 B 🔴 +518 B 🔴 +440 B
assets/cloudBadges-CmUGU6Ua.js (removed) 922 B 🟢 -922 B 🟢 -518 B 🟢 -458 B
assets/Load3DAdvanced-BntGuAmZ.js (removed) 761 B 🟢 -761 B 🟢 -424 B 🟢 -359 B
assets/Load3DAdvanced-CRTWbStR.js (new) 761 B 🔴 +761 B 🔴 +423 B 🔴 +360 B
assets/nightlyBadges-DFFMiQDM.js (new) 411 B 🔴 +411 B 🔴 +275 B 🔴 +229 B
assets/nightlyBadges-ySiAUyvD.js (removed) 411 B 🟢 -411 B 🟢 -273 B 🟢 -265 B
assets/missingModelDownload-Biv6l6ew.js (new) 371 B 🔴 +371 B 🔴 +205 B 🔴 +172 B
assets/missingModelDownload-C9qJ3TwK.js (removed) 371 B 🟢 -371 B 🟢 -201 B 🟢 -173 B
assets/SubscriptionPanelContentWorkspace-BBpChnSo.js (removed) 179 B 🟢 -179 B 🟢 -117 B 🟢 -93 B
assets/SubscriptionPanelContentWorkspace-DvXg_CIS.js (new) 179 B 🔴 +179 B 🔴 +117 B 🔴 +94 B
assets/Load3dViewerContent-C1CiLA9e.js (new) 137 B 🔴 +137 B 🔴 +103 B 🔴 +109 B
assets/Load3dViewerContent-CFEBZUU4.js (removed) 137 B 🟢 -137 B 🟢 -103 B 🟢 -99 B
assets/Load3DAdvanced-1N8-DIoz.js (new) 122 B 🔴 +122 B 🔴 +97 B 🔴 +87 B
assets/Load3DAdvanced-DH4TYeqW.js (removed) 122 B 🟢 -122 B 🟢 -97 B 🟢 -88 B
assets/WidgetLegacy-C12CGJUo.js (new) 117 B 🔴 +117 B 🔴 +106 B 🔴 +104 B
assets/WidgetLegacy-qPAVv68R.js (removed) 117 B 🟢 -117 B 🟢 -106 B 🟢 -104 B
assets/workflowDraftStoreV2-BQ8z_dmR.js (removed) 112 B 🟢 -112 B 🟢 -101 B 🟢 -110 B
assets/workflowDraftStoreV2-CnT5KChP.js (new) 112 B 🔴 +112 B 🔴 +101 B 🔴 +106 B
assets/Load3D-9AtojeMG.js (removed) 98 B 🟢 -98 B 🟢 -89 B 🟢 -83 B
assets/Load3D-CG2DmQr4.js (new) 98 B 🔴 +98 B 🔴 +89 B 🔴 +88 B
assets/changeTracker-6QPxFiEz.js (new) 91 B 🔴 +91 B 🔴 +93 B 🔴 +83 B
assets/changeTracker-sZG4RvJq.js (removed) 91 B 🟢 -91 B 🟢 -93 B 🟢 -85 B

Status: 70 added / 70 removed / 211 unchanged

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 56.5 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 47.3 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 72.3 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 53.3 MB heap
large-graph-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 64.7 MB heap
large-graph-pan: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.3 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.8 MB heap
minimap-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.6 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 53.7 MB heap
subgraph-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 69.0 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 53.2 MB heap
subgraph-transition-enter: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 153ms TBT · 93.8 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 68.7 MB heap
vue-large-graph-idle: · 56.3 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 158.6 MB heap
vue-large-graph-pan: · 56.2 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 407ms TBT · 158.0 MB heap
workflow-execution: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 48.4 MB heap

⚠️ 11 regressions detected

Show regressions
Metric Baseline PR (median) Δ Sig
canvas-idle: task duration 497ms 625ms +26% ⚠️ z=7.4
canvas-zoom-sweep: task duration 384ms 457ms +19% ⚠️ z=5.7
dom-widget-clipping: task duration 400ms 400ms +0% ⚠️ z=2.2
large-graph-idle: task duration 712ms 793ms +11% ⚠️ z=4.6
large-graph-idle: script duration 121ms 127ms +5% ⚠️ z=2.3
large-graph-pan: task duration 1348ms 1425ms +6% ⚠️ z=8.0
large-graph-pan: script duration 459ms 470ms +2% ⚠️ z=3.1
minimap-idle: task duration 685ms 846ms +23% ⚠️ z=6.7
minimap-idle: script duration 109ms 133ms +22% ⚠️ z=3.6
subgraph-dom-widget-clipping: task duration 403ms 417ms +3% ⚠️ z=2.1
subgraph-idle: task duration 474ms 555ms +17% ⚠️ z=5.9
All metrics
Metric Baseline PR (median) Δ Sig
canvas-idle: avg frame time 17ms 17ms -0% z=-0.5
canvas-idle: p95 frame time 17ms 17ms +1%
canvas-idle: layout duration 0ms 0ms +0%
canvas-idle: style recalc duration 9ms 9ms -1% z=-1.8
canvas-idle: layout count 0 0 +0%
canvas-idle: style recalc count 10 8 -25% z=-6.5
canvas-idle: task duration 497ms 625ms +26% ⚠️ z=7.4
canvas-idle: script duration 20ms 25ms +27% z=-0.2
canvas-idle: TBT 0ms 0ms +0%
canvas-idle: heap used 69.4 MB 56.5 MB -19%
canvas-idle: DOM nodes 20 15 -25% z=-5.9
canvas-idle: event listeners 4 -72 -1900% z=-17.7
canvas-mouse-sweep: avg frame time 17ms 17ms +0% z=-0.4
canvas-mouse-sweep: p95 frame time 17ms 17ms +0%
canvas-mouse-sweep: layout duration 4ms 4ms -5% z=-0.3
canvas-mouse-sweep: style recalc duration 41ms 40ms -3% z=-0.7
canvas-mouse-sweep: layout count 12 12 +0%
canvas-mouse-sweep: style recalc count 78 76 -3% z=-1.1
canvas-mouse-sweep: task duration 911ms 951ms +4% z=1.5
canvas-mouse-sweep: script duration 127ms 134ms +5% z=-0.3
canvas-mouse-sweep: TBT 0ms 0ms +0%
canvas-mouse-sweep: heap used 49.3 MB 47.3 MB -4%
canvas-mouse-sweep: DOM nodes -278 -279 +0% z=-132.0
canvas-mouse-sweep: event listeners -148 -148 +0% z=-37.5
canvas-zoom-sweep: avg frame time 17ms 17ms -0% z=-0.3
canvas-zoom-sweep: p95 frame time 17ms 17ms -0%
canvas-zoom-sweep: layout duration 1ms 1ms +12% z=1.4
canvas-zoom-sweep: style recalc duration 18ms 20ms +16% z=0.8
canvas-zoom-sweep: layout count 6 6 +0%
canvas-zoom-sweep: style recalc count 32 33 +2% z=2.7
canvas-zoom-sweep: task duration 384ms 457ms +19% ⚠️ z=5.7
canvas-zoom-sweep: script duration 21ms 28ms +36% z=0.4
canvas-zoom-sweep: TBT 0ms 0ms +0%
canvas-zoom-sweep: heap used 72.3 MB 72.3 MB +0%
canvas-zoom-sweep: DOM nodes 79 79 -1% z=-0.9
canvas-zoom-sweep: event listeners 19 19 +0% z=-0.9
dom-widget-clipping: avg frame time 17ms 17ms +0% z=0.1
dom-widget-clipping: p95 frame time 17ms 17ms -1%
dom-widget-clipping: layout duration 0ms 0ms +0%
dom-widget-clipping: style recalc duration 10ms 8ms -12% z=-1.8
dom-widget-clipping: layout count 0 0 +0%
dom-widget-clipping: style recalc count 13 12 -8% z=-2.2
dom-widget-clipping: task duration 400ms 400ms +0% ⚠️ z=2.2
dom-widget-clipping: script duration 61ms 61ms +1% z=-2.0
dom-widget-clipping: TBT 0ms 0ms +0%
dom-widget-clipping: heap used 53.0 MB 53.3 MB +1%
dom-widget-clipping: DOM nodes 22 20 -9% z=-1.5
dom-widget-clipping: event listeners 2 1 -50% variance too high
large-graph-idle: avg frame time 17ms 17ms +0% z=0.2
large-graph-idle: p95 frame time 17ms 17ms +0%
large-graph-idle: layout duration 0ms 0ms +0%
large-graph-idle: style recalc duration 8ms 8ms -2% z=-4.3
large-graph-idle: layout count 0 0 +0%
large-graph-idle: style recalc count 8 8 -6% z=-13.1
large-graph-idle: task duration 712ms 793ms +11% ⚠️ z=4.6
large-graph-idle: script duration 121ms 127ms +5% ⚠️ z=2.3
large-graph-idle: TBT 0ms 0ms +0%
large-graph-idle: heap used 64.3 MB 64.7 MB +1%
large-graph-idle: DOM nodes -283 -283 -0% z=-339.9
large-graph-idle: event listeners -144 -144 +0% z=-27.9
large-graph-pan: avg frame time 17ms 17ms +0% z=0.8
large-graph-pan: p95 frame time 17ms 17ms +0%
large-graph-pan: layout duration 0ms 0ms +0%
large-graph-pan: style recalc duration 14ms 13ms -3% z=-5.0
large-graph-pan: layout count 0 0 +0%
large-graph-pan: style recalc count 68 68 -1% z=-3.2
large-graph-pan: task duration 1348ms 1425ms +6% ⚠️ z=8.0
large-graph-pan: script duration 459ms 470ms +2% ⚠️ z=3.1
large-graph-pan: TBT 0ms 0ms +0%
large-graph-pan: heap used 60.5 MB 65.3 MB +8%
large-graph-pan: DOM nodes -284 -285 +0% z=-184.3
large-graph-pan: event listeners -144 -143 -1% z=-178.6
large-graph-zoom: avg frame time 17ms 17ms +0%
large-graph-zoom: p95 frame time 17ms 17ms +0%
large-graph-zoom: layout duration 7ms 8ms +5%
large-graph-zoom: style recalc duration 16ms 15ms -6%
large-graph-zoom: layout count 60 60 +0%
large-graph-zoom: style recalc count 64 64 +0%
large-graph-zoom: task duration 1537ms 1656ms +8%
large-graph-zoom: script duration 538ms 580ms +8%
large-graph-zoom: TBT 0ms 0ms +0%
large-graph-zoom: heap used 60.8 MB 65.8 MB +8%
large-graph-zoom: DOM nodes -287 -289 +1%
large-graph-zoom: event listeners -148 -147 -1%
minimap-idle: avg frame time 17ms 17ms +0% z=0.7
minimap-idle: p95 frame time 17ms 17ms +0%
minimap-idle: layout duration 0ms 0ms +0%
minimap-idle: style recalc duration 7ms 8ms +17% z=-1.4
minimap-idle: layout count 0 0 +0%
minimap-idle: style recalc count 8 8 -6% z=-3.0
minimap-idle: task duration 685ms 846ms +23% ⚠️ z=6.7
minimap-idle: script duration 109ms 133ms +22% ⚠️ z=3.6
minimap-idle: TBT 0ms 0ms +0%
minimap-idle: heap used 65.5 MB 65.6 MB +0%
minimap-idle: DOM nodes -283 -283 +0% z=-220.9
minimap-idle: event listeners -144 -145 +1% z=-226.5
subgraph-dom-widget-clipping: avg frame time 17ms 17ms -0% z=-0.9
subgraph-dom-widget-clipping: p95 frame time 17ms 17ms +0%
subgraph-dom-widget-clipping: layout duration 0ms 0ms +0%
subgraph-dom-widget-clipping: style recalc duration 11ms 10ms -14% z=-3.3
subgraph-dom-widget-clipping: layout count 0 0 +0%
subgraph-dom-widget-clipping: style recalc count 47 45 -4% z=-5.0
subgraph-dom-widget-clipping: task duration 403ms 417ms +3% ⚠️ z=2.1
subgraph-dom-widget-clipping: script duration 119ms 122ms +3% z=-1.0
subgraph-dom-widget-clipping: TBT 0ms 0ms +0%
subgraph-dom-widget-clipping: heap used 54.5 MB 53.7 MB -1%
subgraph-dom-widget-clipping: DOM nodes 20 16 -20% z=-5.5
subgraph-dom-widget-clipping: event listeners 6 8 +33% z=-1.4
subgraph-idle: avg frame time 17ms 17ms +0% z=0.4
subgraph-idle: p95 frame time 17ms 17ms +0%
subgraph-idle: layout duration 0ms 0ms +0%
subgraph-idle: style recalc duration 9ms 10ms +5% z=-0.7
subgraph-idle: layout count 0 0 +0%
subgraph-idle: style recalc count 10 9 -15% z=-3.7
subgraph-idle: task duration 474ms 555ms +17% ⚠️ z=5.9
subgraph-idle: script duration 15ms 21ms +39% z=0.2
subgraph-idle: TBT 0ms 0ms +0%
subgraph-idle: heap used 69.0 MB 69.0 MB +0%
subgraph-idle: DOM nodes 20 17 -15% z=-3.2
subgraph-idle: event listeners 4 4 +0% variance too high
subgraph-mouse-sweep: avg frame time 17ms 17ms -0% z=0.4
subgraph-mouse-sweep: p95 frame time 17ms 17ms -0%
subgraph-mouse-sweep: layout duration 4ms 5ms +17% z=1.8
subgraph-mouse-sweep: style recalc duration 37ms 42ms +14% z=-0.2
subgraph-mouse-sweep: layout count 16 16 +0%
subgraph-mouse-sweep: style recalc count 76 76 +0% z=-2.1
subgraph-mouse-sweep: task duration 817ms 879ms +8% z=1.6
subgraph-mouse-sweep: script duration 94ms 103ms +9% z=0.3
subgraph-mouse-sweep: TBT 0ms 0ms +0%
subgraph-mouse-sweep: heap used 45.5 MB 53.2 MB +17%
subgraph-mouse-sweep: DOM nodes -279 -108 -61% z=-78.3
subgraph-mouse-sweep: event listeners -148 -72 -51% variance too high
subgraph-transition-enter: avg frame time 17ms 17ms -0%
subgraph-transition-enter: p95 frame time 17ms 17ms -0%
subgraph-transition-enter: layout duration 13ms 14ms +11%
subgraph-transition-enter: style recalc duration 31ms 34ms +11%
subgraph-transition-enter: layout count 14 15 +7%
subgraph-transition-enter: style recalc count 18 19 +6%
subgraph-transition-enter: task duration 959ms 1062ms +11%
subgraph-transition-enter: script duration 35ms 51ms +47%
subgraph-transition-enter: TBT 130ms 153ms +18%
subgraph-transition-enter: heap used 96.3 MB 93.8 MB -3%
subgraph-transition-enter: DOM nodes 13673 13673 +0%
subgraph-transition-enter: event listeners 2371 2371 +0%
viewport-pan-sweep: avg frame time 17ms 17ms +0%
viewport-pan-sweep: p95 frame time 17ms 17ms +0%
viewport-pan-sweep: layout duration 0ms 0ms +0%
viewport-pan-sweep: style recalc duration 39ms 37ms -4%
viewport-pan-sweep: layout count 0 0 +0%
viewport-pan-sweep: style recalc count 250 248 -1%
viewport-pan-sweep: task duration 4653ms 4865ms +5%
viewport-pan-sweep: script duration 1434ms 1488ms +4%
viewport-pan-sweep: TBT 0ms 0ms +0%
viewport-pan-sweep: heap used 67.5 MB 68.7 MB +2%
viewport-pan-sweep: DOM nodes -280 -282 +1%
viewport-pan-sweep: event listeners -126 -126 +0%
vue-large-graph-idle: avg frame time 18ms 18ms +0%
vue-large-graph-idle: p95 frame time 17ms 17ms +1%
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 17385ms 17714ms +2%
vue-large-graph-idle: script duration 582ms 612ms +5%
vue-large-graph-idle: TBT 0ms 0ms +0%
vue-large-graph-idle: heap used 159.6 MB 158.6 MB -1%
vue-large-graph-idle: DOM nodes -8312 -8312 +0%
vue-large-graph-idle: event listeners -16387 -16390 +0%
vue-large-graph-pan: avg frame time 18ms 18ms +0%
vue-large-graph-pan: p95 frame time 17ms 17ms +0%
vue-large-graph-pan: layout duration 0ms 0ms +0%
vue-large-graph-pan: style recalc duration 18ms 22ms +19%
vue-large-graph-pan: layout count 0 0 +0%
vue-large-graph-pan: style recalc count 145 155 +7%
vue-large-graph-pan: task duration 20805ms 21774ms +5%
vue-large-graph-pan: script duration 875ms 972ms +11%
vue-large-graph-pan: TBT 195ms 407ms +108%
vue-large-graph-pan: heap used 159.5 MB 158.0 MB -1%
vue-large-graph-pan: DOM nodes -8312 -8312 +0%
vue-large-graph-pan: event listeners -16383 -16380 -0%
workflow-execution: avg frame time 17ms 17ms +0% z=1.1
workflow-execution: p95 frame time 17ms 17ms -0%
workflow-execution: layout duration 1ms 1ms -55% z=-6.9
workflow-execution: style recalc duration 18ms 19ms +5% z=-2.4
workflow-execution: layout count 3 3 -17% z=-4.5
workflow-execution: style recalc count 13 13 -4% z=-2.6
workflow-execution: task duration 120ms 123ms +2% z=-0.0
workflow-execution: script duration 11ms 11ms +1% z=-6.1
workflow-execution: TBT 0ms 0ms +0%
workflow-execution: heap used 48.4 MB 48.4 MB -0%
workflow-execution: DOM nodes 119 125 +5% z=-5.1
workflow-execution: event listeners 65 66 +2% z=3.2
Historical variance (last 15 runs)
Metric μ σ CV
canvas-idle: avg frame time 17ms 0ms 0.0%
canvas-idle: layout duration 0ms 0ms 0.0%
canvas-idle: style recalc duration 11ms 1ms 8.2%
canvas-idle: layout count 0 0 0.0%
canvas-idle: style recalc count 11 1 5.0%
canvas-idle: task duration 395ms 31ms 7.9%
canvas-idle: script duration 25ms 2ms 8.8%
canvas-idle: TBT 0ms 0ms 0.0%
canvas-idle: DOM nodes 23 1 5.6%
canvas-idle: event listeners 12 5 40.9%
canvas-mouse-sweep: avg frame time 17ms 0ms 0.0%
canvas-mouse-sweep: layout duration 4ms 0ms 5.4%
canvas-mouse-sweep: style recalc duration 43ms 3ms 7.4%
canvas-mouse-sweep: layout count 12 0 0.0%
canvas-mouse-sweep: style recalc count 79 2 3.0%
canvas-mouse-sweep: task duration 865ms 58ms 6.7%
canvas-mouse-sweep: script duration 136ms 6ms 4.8%
canvas-mouse-sweep: TBT 0ms 0ms 0.0%
canvas-mouse-sweep: DOM nodes 62 3 4.2%
canvas-mouse-sweep: event listeners 8 4 49.4%
canvas-zoom-sweep: avg frame time 17ms 0ms 0.0%
canvas-zoom-sweep: layout duration 1ms 0ms 7.0%
canvas-zoom-sweep: style recalc duration 19ms 2ms 8.0%
canvas-zoom-sweep: layout count 6 0 0.0%
canvas-zoom-sweep: style recalc count 31 0 1.5%
canvas-zoom-sweep: task duration 327ms 23ms 7.1%
canvas-zoom-sweep: script duration 27ms 3ms 11.1%
canvas-zoom-sweep: TBT 0ms 0ms 0.0%
canvas-zoom-sweep: DOM nodes 79 1 1.0%
canvas-zoom-sweep: event listeners 24 5 21.8%
dom-widget-clipping: avg frame time 17ms 0ms 0.0%
dom-widget-clipping: layout duration 0ms 0ms 0.0%
dom-widget-clipping: style recalc duration 10ms 1ms 8.0%
dom-widget-clipping: layout count 0 0 0.0%
dom-widget-clipping: style recalc count 13 0 3.8%
dom-widget-clipping: task duration 365ms 16ms 4.5%
dom-widget-clipping: script duration 68ms 3ms 4.8%
dom-widget-clipping: TBT 0ms 0ms 0.0%
dom-widget-clipping: DOM nodes 22 1 6.4%
dom-widget-clipping: event listeners 8 6 81.2%
large-graph-idle: avg frame time 17ms 0ms 0.0%
large-graph-idle: layout duration 0ms 0ms 0.0%
large-graph-idle: style recalc duration 12ms 1ms 8.6%
large-graph-idle: layout count 0 0 0.0%
large-graph-idle: style recalc count 12 0 2.7%
large-graph-idle: task duration 542ms 54ms 10.0%
large-graph-idle: script duration 102ms 11ms 10.3%
large-graph-idle: TBT 0ms 0ms 0.0%
large-graph-idle: DOM nodes 25 1 3.7%
large-graph-idle: event listeners 26 6 23.2%
large-graph-pan: avg frame time 17ms 0ms 0.0%
large-graph-pan: layout duration 0ms 0ms 0.0%
large-graph-pan: style recalc duration 17ms 1ms 4.6%
large-graph-pan: layout count 0 0 0.0%
large-graph-pan: style recalc count 70 1 0.9%
large-graph-pan: task duration 1082ms 43ms 4.0%
large-graph-pan: script duration 408ms 20ms 4.8%
large-graph-pan: TBT 0ms 0ms 0.0%
large-graph-pan: DOM nodes 19 2 8.7%
large-graph-pan: event listeners 5 1 16.8%
minimap-idle: avg frame time 17ms 0ms 0.0%
minimap-idle: layout duration 0ms 0ms 0.0%
minimap-idle: style recalc duration 10ms 1ms 8.6%
minimap-idle: layout count 0 0 0.0%
minimap-idle: style recalc count 10 1 7.1%
minimap-idle: task duration 527ms 47ms 9.0%
minimap-idle: script duration 98ms 10ms 10.1%
minimap-idle: TBT 0ms 0ms 0.0%
minimap-idle: DOM nodes 19 1 7.1%
minimap-idle: event listeners 5 1 14.4%
subgraph-dom-widget-clipping: avg frame time 17ms 0ms 0.0%
subgraph-dom-widget-clipping: layout duration 0ms 0ms 0.0%
subgraph-dom-widget-clipping: style recalc duration 13ms 1ms 7.4%
subgraph-dom-widget-clipping: layout count 0 0 0.0%
subgraph-dom-widget-clipping: style recalc count 48 1 1.2%
subgraph-dom-widget-clipping: task duration 378ms 18ms 4.9%
subgraph-dom-widget-clipping: script duration 128ms 6ms 4.9%
subgraph-dom-widget-clipping: TBT 0ms 0ms 0.0%
subgraph-dom-widget-clipping: DOM nodes 22 1 5.0%
subgraph-dom-widget-clipping: event listeners 16 6 36.0%
subgraph-idle: avg frame time 17ms 0ms 0.0%
subgraph-idle: layout duration 0ms 0ms 0.0%
subgraph-idle: style recalc duration 10ms 1ms 7.5%
subgraph-idle: layout count 0 0 0.0%
subgraph-idle: style recalc count 11 1 6.0%
subgraph-idle: task duration 370ms 31ms 8.5%
subgraph-idle: script duration 20ms 3ms 13.2%
subgraph-idle: TBT 0ms 0ms 0.0%
subgraph-idle: DOM nodes 22 1 6.9%
subgraph-idle: event listeners 10 7 64.5%
subgraph-mouse-sweep: avg frame time 17ms 0ms 0.0%
subgraph-mouse-sweep: layout duration 5ms 0ms 6.8%
subgraph-mouse-sweep: style recalc duration 42ms 3ms 7.8%
subgraph-mouse-sweep: layout count 16 0 0.0%
subgraph-mouse-sweep: style recalc count 80 2 2.4%
subgraph-mouse-sweep: task duration 766ms 69ms 9.0%
subgraph-mouse-sweep: script duration 101ms 7ms 6.5%
subgraph-mouse-sweep: TBT 0ms 0ms 0.0%
subgraph-mouse-sweep: DOM nodes 67 2 3.3%
subgraph-mouse-sweep: event listeners 8 4 52.6%
workflow-execution: avg frame time 17ms 0ms 0.0%
workflow-execution: layout duration 2ms 0ms 9.4%
workflow-execution: style recalc duration 24ms 2ms 9.1%
workflow-execution: layout count 5 1 11.0%
workflow-execution: style recalc count 18 2 11.5%
workflow-execution: task duration 123ms 11ms 8.8%
workflow-execution: script duration 29ms 3ms 10.2%
workflow-execution: TBT 0ms 0ms 0.0%
workflow-execution: DOM nodes 161 7 4.4%
workflow-execution: event listeners 52 4 8.4%
Trend (last 15 commits on main)
Metric Trend Dir Latest
canvas-idle: avg frame time ▆▃▆▁▆▃▆█▆▆▄▃▃▄▃ ➡️ 17ms
canvas-idle: p95 frame time ➡️ NaNms
canvas-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: style recalc duration ▇▇▆▆▃█▄▃▄▃▇▄▁▆▇ ➡️ 11ms
canvas-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
canvas-idle: style recalc count █▃▅▂▅▆▃▁▂▁▂▅▆▅▆ ➡️ 12
canvas-idle: task duration ▃▃▃▆▂▃▃▅▆▂█▃▁▃▃ ➡️ 391ms
canvas-idle: script duration ▄▃▅▇▂▅▃▆▇▅█▄▁▅▆ ➡️ 27ms
canvas-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: heap used ➡️ NaN MB
canvas-idle: DOM nodes █▇▆▅▃▇▃▁▂▂▅▆▆▆▇ ➡️ 24
canvas-idle: event listeners ▅█▅▄▁▅▁▁▁▄▅▅▁▅▄ 📉 11
canvas-mouse-sweep: avg frame time ▆█▆▃▁▃▁▆▆▁▃▆▆▃▃ ➡️ 17ms
canvas-mouse-sweep: p95 frame time ➡️ NaNms
canvas-mouse-sweep: layout duration ▁▃▂▄▁▂▁▃▆▂█▇▆▄▃ ➡️ 4ms
canvas-mouse-sweep: style recalc duration ▄▄▂▄▁▂▃▃▅▄█▆▂▄▄ ➡️ 43ms
canvas-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 12
canvas-mouse-sweep: style recalc count █▅▄▃▂▂▁▄▄▅▆▅▂▇▄ ➡️ 79
canvas-mouse-sweep: task duration █▆▄▂▂▃▂▄▄▅█▆▁▆▄ ➡️ 868ms
canvas-mouse-sweep: script duration ▄▅▄▆▄▆▆▆▅▅█▆▁▅▆ ➡️ 139ms
canvas-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-mouse-sweep: heap used ➡️ NaN MB
canvas-mouse-sweep: DOM nodes █▅▃▃▁▂▂▃▂▄▆▅▃▅▅ ➡️ 64
canvas-mouse-sweep: event listeners █▁▁▁▁▁▇▁▁▁██▇▁█ 📈 13
canvas-zoom-sweep: avg frame time ▅▅█▄▅▁▁▁▅▁▁▅▄▅▁ ➡️ 17ms
canvas-zoom-sweep: p95 frame time ➡️ NaNms
canvas-zoom-sweep: layout duration ▆▅▅▄▁▁█▅▃▅▇▆▁▂▆ ➡️ 1ms
canvas-zoom-sweep: style recalc duration ▆▅▄▆▅▃█▆▇▅▇▄▁▃▅ ➡️ 20ms
canvas-zoom-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 6
canvas-zoom-sweep: style recalc count ▁▁▃▄▆▃▆█▄▄▆▁▆▁▆ ➡️ 32
canvas-zoom-sweep: task duration ▄▂▁▇▂▂▄▅▆▃█▄▁▁▅ ➡️ 338ms
canvas-zoom-sweep: script duration ▃▃▂▇▂▂▅▇▆▅█▄▁▂▆ ➡️ 30ms
canvas-zoom-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-zoom-sweep: heap used ➡️ NaN MB
canvas-zoom-sweep: DOM nodes ▄▃▁▅█▁▃▆▄▅▅▃▃▄▃ ➡️ 79
canvas-zoom-sweep: event listeners ▁▁▂▅█▂▁▅▁▅▅▄▁▅▁ ➡️ 19
dom-widget-clipping: avg frame time ▂▄▅▅▂▄█▇▅▇▇▅▅▁▇ ➡️ 17ms
dom-widget-clipping: p95 frame time ➡️ NaNms
dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: style recalc duration ▆▆▂▆▄▃██▄▁▆▇▆▃▅ ➡️ 10ms
dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
dom-widget-clipping: style recalc count ▇█▅█▅▄█▇▇▁▇▄▇▂▅ ➡️ 13
dom-widget-clipping: task duration ▃▃▁▅▄▃▅▆▅▂▇█▁▅▅ ➡️ 371ms
dom-widget-clipping: script duration ▅▄▄▆▆▅▇▇▆▃█▇▁▇▇ ➡️ 71ms
dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: heap used ➡️ NaN MB
dom-widget-clipping: DOM nodes ▇▇▄▇▅▄█▇▅▁▅▄▇▃▄ ➡️ 21
dom-widget-clipping: event listeners ▅▅▅▅▁▅██▁▁▁▁█▁▁ 📉 2
large-graph-idle: avg frame time ▅▅▅▅▅▂▁▂▄▅▄▂▂▅█ ➡️ 17ms
large-graph-idle: p95 frame time ➡️ NaNms
large-graph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: style recalc duration ▅▅▅▆▄▅▃▄▅▅▆█▁▄▆ ➡️ 13ms
large-graph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-idle: style recalc count █▆█▃▃▁▃▆▃▆▆▃▆██ ➡️ 12
large-graph-idle: task duration ▂▃▂▆▂▃▃▇▅▃██▁▂▅ ➡️ 569ms
large-graph-idle: script duration ▄▅▄▆▄▅▅▇▆▅█▆▁▃▆ ➡️ 110ms
large-graph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: heap used ➡️ NaN MB
large-graph-idle: DOM nodes ▆█▅▂▅▃▁▂▃▅▅▆▂▆▅ ➡️ 25
large-graph-idle: event listeners ███▇██▄▁▄▇▇█▂█▇ ➡️ 29
large-graph-pan: avg frame time ▆▃▃▆█▃▁█▆▆▆▆█▁▆ ➡️ 17ms
large-graph-pan: p95 frame time ➡️ NaNms
large-graph-pan: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: style recalc duration ▃▂▄▄▁▅▂▂▁▄▄█▃▁▂ ➡️ 17ms
large-graph-pan: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-pan: style recalc count ▆▃█▂▃▂▂▂▁▇▅▃█▆▃ ➡️ 69
large-graph-pan: task duration ▄▃▄▆▄▄▄▆▄▄█▆▁▂▅ ➡️ 1100ms
large-graph-pan: script duration ▅▄▅▆▆▅▄▆▄▅█▄▁▄▅ ➡️ 413ms
large-graph-pan: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: heap used ➡️ NaN MB
large-graph-pan: DOM nodes ▅▃▆▂▄▁▃▁▁▅▁▂█▅▂ ➡️ 18
large-graph-pan: event listeners █▆█▁▁▆▁▁▃▆▁▃██▃ ➡️ 5
minimap-idle: avg frame time ▃▆▆▃█▁█▆▆▃▃▆█▆█ ➡️ 17ms
minimap-idle: p95 frame time ➡️ NaNms
minimap-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: style recalc duration ▄█▁█▅▅█▅▅▃▅▁▁▄▆ ➡️ 10ms
minimap-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
minimap-idle: style recalc count ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 9
minimap-idle: task duration ▃▄▁▅▁▃▄▅▇▃█▅▁▁▅ ➡️ 547ms
minimap-idle: script duration ▄▆▃▇▃▅▆▆▇▅█▅▁▃▆ ➡️ 106ms
minimap-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: heap used ➡️ NaN MB
minimap-idle: DOM nodes ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 19
minimap-idle: event listeners ▃▃▆▁▁▁▃▁▁▆▁▃█▆▁ ➡️ 4
subgraph-dom-widget-clipping: avg frame time ▅▄▄▄▄▄█▄▄▄▃▁▆▃▃ ➡️ 17ms
subgraph-dom-widget-clipping: p95 frame time ➡️ NaNms
subgraph-dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: style recalc duration ▂▄▃▅▅▃▂▅▇▃▄█▁▄▆ ➡️ 14ms
subgraph-dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-dom-widget-clipping: style recalc count ▇█▆▃▆▃▁▆█▇▃▆▇█▅ ➡️ 48
subgraph-dom-widget-clipping: task duration ▂▃▃▆▅▅▂▅█▂▆█▁▂▇ ➡️ 398ms
subgraph-dom-widget-clipping: script duration ▃▃▃▄▅▅▂▄█▂▅▇▁▂▅ ➡️ 131ms
subgraph-dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: heap used ➡️ NaN MB
subgraph-dom-widget-clipping: DOM nodes ▅▇▅▂▅▂▁▅▅▅▁▇▅█▄ ➡️ 22
subgraph-dom-widget-clipping: event listeners ▅▅▅▂▅▁▅██▁▁█▅█▅ 📈 16
subgraph-idle: avg frame time ▆▆█▁▆▃▆▆▆▃▆▁▃▆█ ➡️ 17ms
subgraph-idle: p95 frame time ➡️ NaNms
subgraph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: style recalc duration ▁▇▃▆▂▄▂▃▃▆▆▄▃▇█ ➡️ 12ms
subgraph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-idle: style recalc count ▃▆▃▃▂▅▁▂▁▆▃▃██▇ ➡️ 12
subgraph-idle: task duration ▁▃▁▇▁▁▃▆▅▂█▅▁▁▄ ➡️ 378ms
subgraph-idle: script duration ▁▃▂▇▁▂▃▇▆▂█▅▂▁▅ ➡️ 22ms
subgraph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: heap used ➡️ NaN MB
subgraph-idle: DOM nodes ▃▅▃▂▁▄▁▂▁▅▃▂▇█▇ ➡️ 24
subgraph-idle: event listeners ▁▅▁▁▁▁▁▁▁▅▄▁███ 📈 21
subgraph-mouse-sweep: avg frame time ▅▄▁▃▃▄▆▄▆▃▃█▁▃▃ ➡️ 17ms
subgraph-mouse-sweep: p95 frame time ➡️ NaNms
subgraph-mouse-sweep: layout duration ▁▄▄▄▃▃▅▅▅▂█▇▂▃▆ ➡️ 5ms
subgraph-mouse-sweep: style recalc duration ▃▂▄▅▂▃▄▅█▃█▆▁▂▅ ➡️ 43ms
subgraph-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 16
subgraph-mouse-sweep: style recalc count ▅▂▅▅▁▄▃▅█▅▆▄▂▄▅ ➡️ 81
subgraph-mouse-sweep: task duration ▃▂▄▅▂▄▄▅▇▄█▆▁▃▅ ➡️ 785ms
subgraph-mouse-sweep: script duration ▄▅▄▇▅▅▆▇▆▅██▁▄▆ ➡️ 105ms
subgraph-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-mouse-sweep: heap used ➡️ NaN MB
subgraph-mouse-sweep: DOM nodes ▅▁▄▅▁▄▃▃█▅▅▄▂▅▃ ➡️ 66
subgraph-mouse-sweep: event listeners ▇▁▂▇▁▂▂▂█▇▂▂▇▇▂ 📈 5
workflow-execution: avg frame time ▆▆▆▄▆▆▃▄▁▄█▆▅▄▆ ➡️ 17ms
workflow-execution: p95 frame time ➡️ NaNms
workflow-execution: layout duration ▁▆▁▃▂▄▃▂▃▃▅█▄▂▅ ➡️ 2ms
workflow-execution: style recalc duration ▃▇▅▇▁▅▆▇█▁██▂▄▆ ➡️ 25ms
workflow-execution: layout count ▁█▂▃▂▃▃▁▃▃▄▃▂▃▂ ➡️ 5
workflow-execution: style recalc count ▃█▅▇▁▄▅▆▅▅▅▅▄▄▂ ➡️ 15
workflow-execution: task duration ▂▅▄▅▁▄▆▆▆▁▇█▁▃▃ ➡️ 120ms
workflow-execution: script duration ▄▃▄▄▃▅▄▅▆▂▇█▁▃▄ ➡️ 29ms
workflow-execution: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
workflow-execution: heap used ➡️ NaN MB
workflow-execution: DOM nodes ▂█▃▆▁▄▃▅▃█▃▃▄▃▁ ➡️ 152
workflow-execution: event listeners ▅███▁▅███▁██▅█▅ ➡️ 49
Raw data
{
  "timestamp": "2026-08-03T02:36:34.130Z",
  "gitSha": "8c56445bdf752757fac7bb126b90d6edc6a83853",
  "branch": "glary/fix-local-credits-upgrade-gating",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2174.7199999999793,
      "styleRecalcs": 6,
      "styleRecalcDurationMs": 9.325999999999997,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 665.3090000000001,
      "heapDeltaBytes": -22360472,
      "heapUsedBytes": 45638880,
      "domNodes": 12,
      "jsHeapTotalBytes": 20176896,
      "scriptDurationMs": 24.314000000000004,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-idle",
      "durationMs": 2035.88400000001,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 9.156,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 584.1370000000001,
      "heapDeltaBytes": 4790864,
      "heapUsedBytes": 72891260,
      "domNodes": 18,
      "jsHeapTotalBytes": 20312064,
      "scriptDurationMs": 25.523999999999997,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1874.1929999999911,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 36.696000000000005,
      "layouts": 12,
      "layoutDurationMs": 3.197,
      "taskDurationMs": 904.7099999999999,
      "heapDeltaBytes": -16225348,
      "heapUsedBytes": 51689232,
      "domNodes": -280,
      "jsHeapTotalBytes": 20963328,
      "scriptDurationMs": 127.004,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1942.56299999995,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 44.134,
      "layouts": 12,
      "layoutDurationMs": 3.9009999999999994,
      "taskDurationMs": 996.47,
      "heapDeltaBytes": -20331524,
      "heapUsedBytes": 47525992,
      "domNodes": -278,
      "jsHeapTotalBytes": 19652608,
      "scriptDurationMs": 140.15800000000002,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1772.7179999999976,
      "styleRecalcs": 33,
      "styleRecalcDurationMs": 21.424,
      "layouts": 6,
      "layoutDurationMs": 0.8150000000000002,
      "taskDurationMs": 454.90200000000004,
      "heapDeltaBytes": 7885708,
      "heapUsedBytes": 75868768,
      "domNodes": 79,
      "jsHeapTotalBytes": 20049920,
      "scriptDurationMs": 28.769999999999996,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1755.9610000000703,
      "styleRecalcs": 32,
      "styleRecalcDurationMs": 19.299000000000003,
      "layouts": 6,
      "layoutDurationMs": 0.593,
      "taskDurationMs": 459.68899999999996,
      "heapDeltaBytes": 7906248,
      "heapUsedBytes": 75830520,
      "domNodes": 78,
      "jsHeapTotalBytes": 20312064,
      "scriptDurationMs": 28.128000000000004,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 595.8459999999945,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 7.853999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 390.36499999999995,
      "heapDeltaBytes": -12270068,
      "heapUsedBytes": 55593972,
      "domNodes": 20,
      "jsHeapTotalBytes": 21884928,
      "scriptDurationMs": 60.342,
      "eventListeners": 0,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 633.0809999999474,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 9.012,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 410.13899999999995,
      "heapDeltaBytes": -11767492,
      "heapUsedBytes": 56156080,
      "domNodes": 20,
      "jsHeapTotalBytes": 20574208,
      "scriptDurationMs": 62.312999999999995,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2058.447000000001,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 8.538999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 752.3280000000001,
      "heapDeltaBytes": 8399604,
      "heapUsedBytes": 67414328,
      "domNodes": -281,
      "jsHeapTotalBytes": 5304320,
      "scriptDurationMs": 125.82099999999998,
      "eventListeners": -144,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2034.0629999999464,
      "styleRecalcs": 6,
      "styleRecalcDurationMs": 6.936000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 833.324,
      "heapDeltaBytes": 8163828,
      "heapUsedBytes": 68233832,
      "domNodes": -284,
      "jsHeapTotalBytes": 3469312,
      "scriptDurationMs": 128.48100000000002,
      "eventListeners": -144,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2221.5759999999705,
      "styleRecalcs": 68,
      "styleRecalcDurationMs": 13.11,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1376.571,
      "heapDeltaBytes": 7864152,
      "heapUsedBytes": 68240472,
      "domNodes": -284,
      "jsHeapTotalBytes": 4481024,
      "scriptDurationMs": 453.092,
      "eventListeners": -142,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2343.4439999999768,
      "styleRecalcs": 67,
      "styleRecalcDurationMs": 13.562999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1474.079,
      "heapDeltaBytes": 8264716,
      "heapUsedBytes": 68705416,
      "domNodes": -286,
      "jsHeapTotalBytes": 5267456,
      "scriptDurationMs": 486.07399999999996,
      "eventListeners": -144,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3330.0540000000183,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 14.626000000000003,
      "layouts": 60,
      "layoutDurationMs": 7.695,
      "taskDurationMs": 1622.8170000000002,
      "heapDeltaBytes": 6136072,
      "heapUsedBytes": 67539396,
      "domNodes": -289,
      "jsHeapTotalBytes": 8450048,
      "scriptDurationMs": 568.727,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3410.7740000000604,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 14.982000000000003,
      "layouts": 60,
      "layoutDurationMs": 7.743999999999999,
      "taskDurationMs": 1688.698,
      "heapDeltaBytes": 8951744,
      "heapUsedBytes": 70440352,
      "domNodes": -288,
      "jsHeapTotalBytes": 6352896,
      "scriptDurationMs": 592.119,
      "eventListeners": -146,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2050.3510000000347,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 9.564000000000004,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 883.1150000000001,
      "heapDeltaBytes": 8426540,
      "heapUsedBytes": 69321072,
      "domNodes": -283,
      "jsHeapTotalBytes": 4517888,
      "scriptDurationMs": 134.29399999999998,
      "eventListeners": -146,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2044.5640000000367,
      "styleRecalcs": 7,
      "styleRecalcDurationMs": 7.266000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 808.156,
      "heapDeltaBytes": 7442708,
      "heapUsedBytes": 68298784,
      "domNodes": -283,
      "jsHeapTotalBytes": 3469312,
      "scriptDurationMs": 132.56400000000002,
      "eventListeners": -144,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 587.8940000000057,
      "styleRecalcs": 44,
      "styleRecalcDurationMs": 8.805,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 405.958,
      "heapDeltaBytes": -11540732,
      "heapUsedBytes": 56591216,
      "domNodes": 14,
      "jsHeapTotalBytes": 21622784,
      "scriptDurationMs": 120.975,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 645.719999999983,
      "styleRecalcs": 46,
      "styleRecalcDurationMs": 10.463999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 427.84,
      "heapDeltaBytes": -12046492,
      "heapUsedBytes": 55932364,
      "domNodes": 18,
      "jsHeapTotalBytes": 22933504,
      "scriptDurationMs": 123.05800000000002,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2021.8699999999785,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 10.873000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 530.5139999999999,
      "heapDeltaBytes": 4471520,
      "heapUsedBytes": 72464040,
      "domNodes": 18,
      "jsHeapTotalBytes": 20836352,
      "scriptDurationMs": 19.577000000000005,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2009.445000000028,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.93,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 579.596,
      "heapDeltaBytes": 4406172,
      "heapUsedBytes": 72300456,
      "domNodes": 16,
      "jsHeapTotalBytes": 21360640,
      "scriptDurationMs": 21.934,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1756.6700000000424,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 39.409,
      "layouts": 16,
      "layoutDurationMs": 4.922000000000001,
      "taskDurationMs": 879.962,
      "heapDeltaBytes": -19669468,
      "heapUsedBytes": 48197416,
      "domNodes": -280,
      "jsHeapTotalBytes": 20701184,
      "scriptDurationMs": 100.57199999999999,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1739.5860000000312,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 43.88,
      "layouts": 16,
      "layoutDurationMs": 5.6240000000000006,
      "taskDurationMs": 877.854,
      "heapDeltaBytes": -4596112,
      "heapUsedBytes": 63437964,
      "domNodes": 64,
      "jsHeapTotalBytes": 21360640,
      "scriptDurationMs": 104.87100000000001,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-transition-enter",
      "durationMs": 1432.5000000000045,
      "styleRecalcs": 19,
      "styleRecalcDurationMs": 34.057,
      "layouts": 15,
      "layoutDurationMs": 14.060999999999996,
      "taskDurationMs": 1061.8809999999999,
      "heapDeltaBytes": 29169808,
      "heapUsedBytes": 98348128,
      "domNodes": 13673,
      "jsHeapTotalBytes": 16252928,
      "scriptDurationMs": 51.47299999999999,
      "eventListeners": 2371,
      "totalBlockingTimeMs": 153,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8507.143999999982,
      "styleRecalcs": 248,
      "styleRecalcDurationMs": 36.818999999999996,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4830.084,
      "heapDeltaBytes": 12732476,
      "heapUsedBytes": 72185460,
      "domNodes": -282,
      "jsHeapTotalBytes": 7331840,
      "scriptDurationMs": 1485.5320000000002,
      "eventListeners": -126,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8676.871000000006,
      "styleRecalcs": 248,
      "styleRecalcDurationMs": 37.024,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4899.4400000000005,
      "heapDeltaBytes": 12615248,
      "heapUsedBytes": 71973916,
      "domNodes": -282,
      "jsHeapTotalBytes": 7069696,
      "scriptDurationMs": 1491.315,
      "eventListeners": -126,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 17988.49100000001,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 17957.678,
      "heapDeltaBytes": -39324364,
      "heapUsedBytes": 165842860,
      "domNodes": -8312,
      "jsHeapTotalBytes": -15405056,
      "scriptDurationMs": 631.6120000000001,
      "eventListeners": -16391,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 17502.12699999997,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 17470.209,
      "heapDeltaBytes": -45808500,
      "heapUsedBytes": 166675552,
      "domNodes": -8312,
      "jsHeapTotalBytes": -16195584,
      "scriptDurationMs": 593.029,
      "eventListeners": -16389,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 22104.573000000015,
      "styleRecalcs": 158,
      "styleRecalcDurationMs": 22.755000000000024,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 22072.978,
      "heapDeltaBytes": -50830256,
      "heapUsedBytes": 164715148,
      "domNodes": -8312,
      "jsHeapTotalBytes": -16195584,
      "scriptDurationMs": 987.8989999999999,
      "eventListeners": -16379,
      "totalBlockingTimeMs": 462,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 21518.44399999993,
      "styleRecalcs": 151,
      "styleRecalcDurationMs": 20.314999999999973,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 21475.944,
      "heapDeltaBytes": -54625136,
      "heapUsedBytes": 166568980,
      "domNodes": -8312,
      "jsHeapTotalBytes": -16977920,
      "scriptDurationMs": 955.8120000000001,
      "eventListeners": -16381,
      "totalBlockingTimeMs": 351,
      "frameDurationMs": 17.779999999999927,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "workflow-execution",
      "durationMs": 487.3539999999821,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 18.712000000000003,
      "layouts": 2,
      "layoutDurationMs": 0.38999999999999996,
      "taskDurationMs": 129.79000000000002,
      "heapDeltaBytes": -15986800,
      "heapUsedBytes": 51048112,
      "domNodes": 130,
      "jsHeapTotalBytes": 7204864,
      "scriptDurationMs": 11.987,
      "eventListeners": 67,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "workflow-execution",
      "durationMs": 480.4900000000316,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 19.058,
      "layouts": 3,
      "layoutDurationMs": 0.704,
      "taskDurationMs": 115.64799999999998,
      "heapDeltaBytes": -16252352,
      "heapUsedBytes": 50506560,
      "domNodes": 119,
      "jsHeapTotalBytes": 7467008,
      "scriptDurationMs": 10.316,
      "eventListeners": 65,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    }
  ]
}

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0d9e2454-444a-41bd-95c8-3e7e5d211d7a

📥 Commits

Reviewing files that changed from the base of the PR and between b6c661e and 8b8f544.

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

📝 Walkthrough

Walkthrough

Local and non-cloud deployments now hide cloud-only upgrade, pricing, and resubscription actions. Top-up dialogs remain available. Authentication fixtures, unit tests, and an authenticated browser test cover the updated behavior.

Changes

Credits gating

Layer / File(s) Summary
Credits tile gating
src/platform/cloud/subscription/components/CreditsTile.vue, src/platform/cloud/subscription/components/CreditsTile.test.ts
The free-tier upgrade action now requires cloud deployment. The add-credits action remains available and has a test identifier.
Workspace and dialog flow
src/platform/workspace/components/CurrentUserPopoverWorkspace.vue, src/platform/workspace/components/CurrentUserPopoverWorkspace.test.ts, src/services/dialogService.ts, src/services/dialogService.topUpCredits.test.ts
Workspace subscription actions and the subscription-required dialog now require cloud deployment. Non-cloud users use the top-up purchase dialog.
Browser authentication and local validation
browser_tests/fixtures/ComfyPage.ts, browser_tests/tests/localCreditsGating.spec.ts, browser_tests/README.md
The @auth tag enables mocked authentication. Local credits tests verify hidden upgrade paths and available top-up behavior.

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

Possibly related PRs

Suggested labels: size:M, core/1.48, cloud/1.48

Suggested reviewers: dante01yoon


Important

Pre-merge checks failed

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

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
End-To-End Regression Coverage For Fixes ❓ Inconclusive Changed files and a concrete Playwright regression test are present, but the PR title and commit subjects are unavailable, so the required bug-fix signal cannot be verified. Provide the PR title and commit subjects to determine whether the bug-fix-language condition applies.
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main fix for local free-tier users' top-up flow.
Description check ✅ Passed The description thoroughly explains the issue, root cause, changes, testing, limitations, and screenshots, although it does not follow every template heading exactly.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Adr Compliance For Entity/Litegraph Changes ✅ Passed The changed files are limited to browser tests, billing, dialog, and workspace components; none are under 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 glary/fix-local-credits-upgrade-gating

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

coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 3, 2026
The OSS boot surfaces startup toasts the mocked cloud boot does not, and a
toast overlay can intercept the avatar click. Mirrors the guard
currentUserPopoverCredits.spec.ts already uses for the same popover.
@glary-bot

glary-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

Thanks — noting the review came back with no actionable comments, and the walkthrough matches intent.

Resolving the inconclusive pre-merge check

End-To-End Regression Coverage For Fixes reported "the PR title and commit subjects are not provided, so the required bug-fix signal cannot be verified." Supplying both, as the resolution asks:

PR title: fix(billing): keep top-up working for local users on the free tier

Commit subjects:

  • fix(billing): keep top-up working for local users on the free tier
  • fix(billing): gate the workspace popover resubscribe prompt on cloud
  • test: clear toasts before driving the local credits popover

On the substance of that check — the e2e regression coverage it looks for is browser_tests/tests/localCreditsGating.spec.ts, which walks the reported journey end to end (popover top-up → Settings ▸ Credits → popover top-up again) on the localhost bundle. It required a fixture change to be writable at all: ComfyPage previously mocked auth only for @cloud-tagged specs, and @cloud routes a spec to the cloud project, so a signed-in test could never run against isCloud === false. The new @auth tag decouples auth mocking from project routing.

Each new test was verified to fail against the unfixed source and pass with the fix — including catching one of my own vacuous assertions (a personal-workspace variant that rendered SubscribeButton rather than a plain button, so it passed either way; rewritten to use the team shape and re-verified red-then-green).

New commit since your review

8b8f544 clears startup toasts before the first avatar click in the new spec. The OSS boot surfaces toasts the mocked cloud boot does not, and a toast overlay can intercept the click — same guard currentUserPopoverCredits.spec.ts already applies to this popover. Test-only; no production behaviour change.

Declining both Finishing Touches

  • Generate docstrings — this repo's AGENTS.md explicitly forbids justification comments on small diffs ("A guard clause that mirrors another file does not need a comment naming that file"). The production diff here is four isCloud && guards; annotating them would violate that rule. I removed one such comment of my own during development for exactly this reason.
  • Generate unit tests — coverage is already in the diff across all three changed modules (CreditsTile.test.ts, dialogService.topUpCredits.test.ts, CurrentUserPopoverWorkspace.test.ts), each case red-before/green-after. Generated tests would duplicate it, and the repo asks for parsimony over redundant tests.

One thing reviewers should weigh that static analysis won't surface: CurrentUserPopoverWorkspace.vue never renders off cloud today (teamWorkspacesEnabled is hard-false there), so those three guards are defensive hardening, not the fix. The load-bearing change is the single isCloud && in dialogService.showTopUpCreditsDialog.

@glary-bot

glary-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

Re-review after 8b8f544 is clean again — no actionable comments, re-approved.

On the one remaining End-To-End Regression Coverage For FixesInconclusive: its explanation improved between runs and now reads "Changed files and a concrete Playwright regression test are present, but the PR title and commit subjects are unavailable, so the required bug-fix signal cannot be verified."

So the check now recognises the regression test; the only missing input is the title and commit subjects, which it reports as unavailable to it rather than absent. They are unambiguously present:

  • Title: fix(billing): keep top-up working for local users on the free tier
  • fix(billing): keep top-up working for local users on the free tier
  • fix(billing): gate the workspace popover resubscribe prompt on cloud
  • test: clear toasts before driving the local credits popover

I posted these already and the check did not pick them up, so this looks like a harness limitation rather than a gap in the change. I'm deliberately not modifying code to chase it — there is no edit to the diff that would supply metadata the checker says it cannot read, and inventing one would be cargo-culting. Flagging for a human to override at merge.

Status otherwise: Storybook built, bundle −28 B gzip, Playwright still running. That run is the first CI execution of localCreditsGating.spec.ts — I could not execute Playwright in the sandbox (no CI backend), so it is the one result worth watching before this comes out of draft. If it goes red I'll fix it.

@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

@@           Coverage Diff           @@
##             main   #14589   +/-   ##
=======================================
  Coverage   79.14%   79.14%           
=======================================
  Files        1769     1769           
  Lines      113307   113308    +1     
  Branches    35242    35243    +1     
=======================================
+ Hits        89678    89679    +1     
+ Misses      23092    23087    -5     
- Partials      537      542    +5     
Flag Coverage Δ
unit 70.26% <100.00%> (+<0.01%) ⬆️

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

Files with missing lines Coverage Δ
...form/cloud/subscription/components/CreditsTile.vue 96.79% <100.00%> (ø)
...rkspace/components/CurrentUserPopoverWorkspace.vue 77.27% <100.00%> (+0.20%) ⬆️
src/services/dialogService.ts 55.16% <100.00%> (ø)

... and 5 files with indirect coverage changes

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

@dante01yoon dante01yoon left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed the frontend behavior and regression coverage at the current head. The Cloud-only subscription gating is applied consistently, local top-up remains available, and the focused unit/E2E coverage exercises the failure path. All current checks are green.

@glary-bot

glary-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

Thanks @dante01yoon. Two things worth pinning down precisely, since "all current checks are green" is nearly true but glosses over a flaky and a bundle warning — I checked both so nobody has to re-litigate them at merge.

The new e2e spec passed in CI. This was the one gap I flagged as genuinely unverified — I could not run Playwright in the sandbox, so this was its first real execution:

tests/localCreditsGating.spec.ts › Credits on a local build without a Cloud subscription › never offers a subscribe/upgrade path and keeps top-up working after Settings ▸ Credits — pass

Overall: 🎭 Playwright: ✅ 1781 passed, 0 failed · 1 flaky.

The 1 flaky is pre-existing and unrelated — not from this PR:

tests/subgraph/subgraphBreadcrumb.spec.ts › Subgraph Breadcrumb › nested breadcrumb renders root + each subgraph level

Subgraph breadcrumb rendering shares nothing with billing gating, and this diff touches no subgraph code. Naming it explicitly so it doesn't get mis-attributed here.

The ⚠️ 11 regressions detected on the bundle report is content-hash churn, not size growth. Every flagged entry is a matched pair at identical byte size with a different filename hash:

removed added size
GraphView-XDLUXkDH.js GraphView-CmdLyTh7.js 1.29 MB
CreditsPanel-4TCkKzBc.js CreditsPanel-DQYsRLdL.js 15.9 kB
SubscriptionPanel-qKIGHrKF.js SubscriptionPanel-D80v13J1.js 11.5 kB

Net is 🟢 -28 B gzip / -213 B brotli. Nothing to action.

Still needs a human at merge: the End-To-End Regression Coverage For Fixes pre-merge check sits at ❓ Inconclusive because it reports the PR title and commit subjects as unavailable to it — they are fix(billing): … on the title and 2 of 3 commits. It now explicitly acknowledges the Playwright regression test is present. No code change can feed it metadata it says it cannot read, so it wants an override rather than a fix.

Otherwise this is ready to come out of draft whenever you want it in the 6pm stable — I've left that call to you since merging is yours.

@christian-byrne

Copy link
Copy Markdown
Contributor Author

Done in another PR.

@glary-bot

glary-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

Done in another PR.

You're right — I verified it. This PR should be closed.

#14587 (b2e3900) landed on main and contains the same fix, line for line:

  • dialogService.tsif (isCloud && (!isActiveSubscription.value || isFreeTier.value))
  • CreditsTile.vuev-if="isCloud && isFreeTier"

It also covers the parts I assumed were still mine: the non-cloud unit cases in both CreditsTile.test.ts and dialogService.topUpCredits.test.ts — even using the same mockable get isCloud() getter — plus browser_tests/fixtures/localAuthFixture.ts and localCreditsNoSubscribeUi.spec.ts, which solve the same e2e gap I hit. Their fixture-based approach and my @auth-tag-on-ComfyPage approach are two mechanisms for one job; theirs is merged, so mine shouldn't land beside it.

The only delta left is three isCloud guards in CurrentUserPopoverWorkspace.vue (upgrade CTA, "Plans & pricing", subscribe/resubscribe). I don't think those justify a follow-up. That component is unreachable off cloud — CurrentUserButton renders it behind teamWorkspacesEnabled, and resolveAuthGatedFlag hard-returns false when !isCloud, so the legacy popover is what renders locally. They'd be dead-code hardening. And remove-team-ff re-gates that component to v-if="isCloud" directly, encoding the same rule structurally. Happy to open a one-liner if you'd rather have them, but I'd leave it.

On the duplication: I checked for an existing fix before starting and reported finding none — that was wrong. I scanned remote branches for commits ahead of origin/main touching these files, which missed #14587's branch. I should have searched open PRs by title and content, not just branch tips. My mistake, and the reason this work was redundant.

Two findings that aren't in #14587 and may be worth keeping as issues rather than code:

  1. Regression lineage — the ungated CTA shipped in v1.47.4 (026b2c4, feat(billing): unify credits into a facade-driven CreditsTile (FE-964) #12734) and was accidentally masked in v1.48.4 (51884bc, fix(workspace): gate billing controls by role #13812), when hasActiveWorkspace made canTopUp false off cloud. So the visible-button window is v1.47.4 → v1.48.3, but the top-up dead-end survived into 1.49.x independently of the button — which is the part fix: hide subscribe/upgrade credits UI on non-cloud distributions #14587 actually fixes. Reproduced in a real v1.47.4 build.
  2. Latent follow-upcanRunWorkflows folds isFreeTier into free-tier quota, so the same latch could swap the Run button for "Subscribe to run" on local. Inert today only because freeTierJobAllowanceEnabled defaults false via resolveFlag rather than being distribution-gated.

Leaving the close to you, since I can't close it myself.

@dante01yoon

Copy link
Copy Markdown
Collaborator

It's duplicate with #14587 , closing

@dante01yoon dante01yoon closed this Aug 4, 2026
@glary-bot

glary-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown

Agreed — closing is right. I'd reached the same conclusion in my comment above after verifying #14587 on main: it carries the same two guards line for line, plus the non-cloud unit cases and an equivalent local-auth e2e fixture. Nothing here should land alongside it.

Two findings from the investigation aren't in #14587, so flagging where they live before this closes:

Sorry for the duplicate work — I checked for an existing fix first but scanned branch tips rather than open PRs, which is why I missed #14587.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants