Skip to content

fix: clamp monthly credits remaining to the plan allowance - #14477

Open
christian-byrne wants to merge 3 commits into
mainfrom
glary/fe-1451-clamp-monthly-remaining-credits
Open

fix: clamp monthly credits remaining to the plan allowance#14477
christian-byrne wants to merge 3 commits into
mainfrom
glary/fe-1451-clamp-monthly-remaining-credits

Conversation

@christian-byrne

Copy link
Copy Markdown
Contributor

PR Created by the Glary-Bot Agent


Summary

The monthly row on the Plan & Credits tile could render more credits left than the plan grants — e.g. 4,201 left of 4,200 — because the two numbers came from different unit systems; this clamps the displayed remaining to the allowance.

Linear: FE-1451

Changes

  • What: computeMonthlyUsage now returns a remaining clamped to 0..monthlyTotal, with used as its complement so used + remaining always equals the allowance. CreditsTile binds both the full and compact left of labels to it.
  • Breaking: none. computeMonthlyUsage has exactly one consumer (CreditsTile.vue).

Why the numbers disagreed

total is the authoritative integer credit grant from the catalog (credit_grant: "4200"). remaining was reconstructed from the cents ledger: the backend converts the grant to cents with ceiling division (grant.go:331, ceil(4200×100/211) = 1991¢) and the frontend converts back (centsToCredits, round(1991 × 2.11) = 4201).

4,200 is not reachable from any integer cents value under round, floor or ceil (1990¢→4198.9, 1991¢→4201.01), so this is not fixable by changing a rounding direction. A grant round-trips losslessly only when credits % 211 == 0, which is why 5 of 7 paid plans drift (standard-monthly +1, standard-annual +2, creator-monthly +2, creator-annual +1, founder-monthly +3) while pro-monthly/annual are clean by coincidence ($100 × 211).

This PR is the display-layer stopgap only — the systemic fix (exposing authoritative integer credits from the API) is written up in detail on FE-1451 and deliberately deferred.

Verification

Rendered the real component with the exact value the backend grants for Standard (1991¢):

before:  Total credits 4,201 remaining | Monthly · Refills Aug 30 | 0 used | 4,201 left of 4,200
after:   Total credits 4,201 remaining | Monthly · Refills Aug 30 | 0 used | 4,200 left of 4,200

The before line reproduces the reported screenshot exactly. Both new tests fail without the source change (verified by reverting only the two source files).

Gates: typecheck clean, lint 0 errors (changed files warning-free), oxfmt --check clean, knip clean, subscription suite 260/260. Full test:unit has 3 failures — all confirmed pre-existing on a clean main (GraphView, onboardingCloudRoutes timeouts, plus one load-dependent flake in previewAny); none touch credits.

Review Focus

Two points raised in review that I deliberately did not change, with evidence:

1. Does the clamp hide legitimate rollover credits? No. The full balance stays on the headline. Rendering a large overage (Pro, 503,805 credits vs a 21,100 allowance):

before:  Total credits 503,805 remaining | 0 used | 503,805 left of 21,100
after:   Total credits 503,805 remaining | 0 used |  21,100 left of 21,100

Total credits still reports 503,805 either way — nothing is hidden from the user, and the monthly row now honours what its own label promises. Note before already showed 0 used next to 503,805 left of 21,100, so it was internally contradictory prior to this change. Monthly subscription credits also aren't designed to roll over (PrioritySubscription = 50 // Subscription credits expire at billing period end), so the overage is normally a conversion artifact rather than real carryover.

2. The headline can still read 1 credit above monthly + additional. Intentional. Clamping the headline would understate a balance the user can genuinely spend (the 4,201st credit is real — it exists in the cents ledger). The breakdown cannot sum exactly while the headline is reconstructed from cents and the allowance is an exact catalog integer; that is precisely the root cause deferred above, and it is not fixable in the view layer without lying about the balance.

Also deliberate: monthlyBonusCredits remains exported from useSubscriptionCredits though this was its last consumer. knip accepts it and it is symmetric with totalCredits/prepaidCredits; removing it would pull in three more files against a minimal fix. Happy to drop it if preferred.

Screenshots

Not included — the tile is gated behind an authenticated Comfy Cloud session with a live Metronome subscription, there is no Storybook story for CreditsTile, and @comfyorg/design-system ships no prebuilt CSS so the themed component can't be rendered standalone without a full workspace build. The diff changes only an interpolated value inside an existing $t() call — no template structure, classes or styles — so there is no visual regression surface. Verified via real-component render output instead (above).

@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown

🎭 Playwright: ✅ 1812 passed, 0 failed

📊 Browser Reports
  • chromium: View Report (✅ 1791 / ❌ 0 / ⚠️ 0 / ⏭️ 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/13/2026, 10:26:06 PM UTC

Links

📦 Bundle: 8.85 MB gzip 🔴 +146 B

Details

Summary

  • Raw size: 37.3 MB baseline 37.3 MB — 🔴 +176 B
  • Gzip: 8.85 MB baseline 8.85 MB — 🔴 +146 B
  • Brotli: 6.18 MB baseline 6.18 MB — 🟢 -118 B
  • Bundles: 439 current • 439 baseline • 145 added / 145 removed

Category Glance
Other 🔴 +176 B (14.2 MB) · Vendor & Third-Party ⚪ 0 B (16.8 MB) · Data & Services ⚪ 0 B (3.51 MB) · Graph Workspace ⚪ 0 B (1.37 MB) · Panels & Settings ⚪ 0 B (565 kB) · Utilities & Hooks ⚪ 0 B (550 kB) · + 5 more

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

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-CcNbCsDe.js (new) 3.71 kB 🔴 +3.71 kB 🔴 +1.86 kB 🔴 +1.61 kB
assets/index-D_Pm-5_s.js (removed) 3.71 kB 🟢 -3.71 kB 🟢 -1.86 kB 🟢 -1.6 kB

Status: 1 added / 1 removed

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

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-_kJN7nDT.js (new) 1.36 MB 🔴 +1.36 MB 🔴 +296 kB 🔴 +222 kB
assets/GraphView-BQAQrceo.js (removed) 1.36 MB 🟢 -1.36 MB 🟢 -296 kB 🟢 -222 kB
assets/WidgetCompositor-Codj9H4y.js (removed) 8.17 kB 🟢 -8.17 kB 🟢 -2.76 kB 🟢 -2.45 kB
assets/WidgetCompositor-DEMUSifN.js (new) 8.17 kB 🔴 +8.17 kB 🔴 +2.76 kB 🔴 +2.45 kB

Status: 2 added / 2 removed / 1 unchanged

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

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView--6ym6tDM.js (removed) 25 kB 🟢 -25 kB 🟢 -6.24 kB 🟢 -5.52 kB
assets/CloudSurveyView-D2YawW-K.js (new) 25 kB 🔴 +25 kB 🔴 +6.25 kB 🔴 +5.52 kB
assets/CloudLayoutView-CHi3wMmj.js (removed) 21.8 kB 🟢 -21.8 kB 🟢 -6.57 kB 🟢 -5.74 kB
assets/CloudLayoutView-xs74nrp7.js (new) 21.8 kB 🔴 +21.8 kB 🔴 +6.57 kB 🔴 +5.75 kB
assets/UserCheckView-hIQpAHos.js (removed) 8.75 kB 🟢 -8.75 kB 🟢 -2.19 kB 🟢 -1.9 kB
assets/UserCheckView-NTst8D2L.js (new) 8.75 kB 🔴 +8.75 kB 🔴 +2.19 kB 🔴 +1.9 kB
assets/CloudLoginView-CvFC-OMy.js (new) 8.74 kB 🔴 +8.74 kB 🔴 +2.55 kB 🔴 +2.26 kB
assets/CloudLoginView-CwPHBV2c.js (removed) 8.74 kB 🟢 -8.74 kB 🟢 -2.55 kB 🟢 -2.26 kB
assets/useCloudAuthPage-DKO1c_Bj.js (removed) 7.08 kB 🟢 -7.08 kB 🟢 -2.51 kB 🟢 -2.2 kB
assets/useCloudAuthPage-Q6uXf8vI.js (new) 7.08 kB 🔴 +7.08 kB 🔴 +2.52 kB 🔴 +2.2 kB
assets/CloudSignupView-B0AzihLv.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +2.17 kB 🔴 +1.91 kB
assets/CloudSignupView-CpS7lD7R.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -2.17 kB 🟢 -1.91 kB
assets/WidgetTextPreview-De-ydnJ7.js (new) 6.07 kB 🔴 +6.07 kB 🔴 +2.13 kB 🔴 +1.89 kB
assets/WidgetTextPreview-TKJ4C5d8.js (removed) 6.07 kB 🟢 -6.07 kB 🟢 -2.13 kB 🟢 -1.89 kB
assets/CloudSubscriptionRedirectView-BLFvwre4.js (new) 6.05 kB 🔴 +6.05 kB 🔴 +2.25 kB 🔴 +1.97 kB
assets/CloudSubscriptionRedirectView-DnYYRMK3.js (removed) 6.05 kB 🟢 -6.05 kB 🟢 -2.25 kB 🟢 -1.96 kB
assets/UserSelectView-CiNnHdcZ.js (removed) 5.49 kB 🟢 -5.49 kB 🟢 -1.96 kB 🟢 -1.72 kB
assets/UserSelectView-DbIBN11A.js (new) 5.49 kB 🔴 +5.49 kB 🔴 +1.96 kB 🔴 +1.71 kB
assets/CloudForgotPasswordView-7SK-8qGi.js (removed) 4.97 kB 🟢 -4.97 kB 🟢 -1.72 kB 🟢 -1.49 kB
assets/CloudForgotPasswordView-DmUeGJR_.js (new) 4.97 kB 🔴 +4.97 kB 🔴 +1.73 kB 🔴 +1.49 kB
assets/CloudAuthTimeoutView-Dq8fWqlC.js (new) 4.43 kB 🔴 +4.43 kB 🔴 +1.54 kB 🔴 +1.34 kB
assets/CloudAuthTimeoutView-Xtd0ecm1.js (removed) 4.43 kB 🟢 -4.43 kB 🟢 -1.54 kB 🟢 -1.34 kB
assets/OAuthLayoutView-B3Xm-9x5.js (removed) 1.31 kB 🟢 -1.31 kB 🟢 -703 B 🟢 -587 B
assets/OAuthLayoutView-DMORTl4B.js (new) 1.31 kB 🔴 +1.31 kB 🔴 +701 B 🔴 +587 B
assets/WidgetTextPreview-D0OM9dU6.js (removed) 131 B 🟢 -131 B 🟢 -100 B 🟢 -89 B
assets/WidgetTextPreview-LJvLzKSC.js (new) 131 B 🔴 +131 B 🔴 +100 B 🔴 +88 B

Status: 13 added / 13 removed / 4 unchanged

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

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/KeybindingPanel-lLYhmT9Y.js (new) 49.4 kB 🔴 +49.4 kB 🔴 +9.95 kB 🔴 +8.79 kB
assets/KeybindingPanel-nk8pvrE7.js (removed) 49.4 kB 🟢 -49.4 kB 🟢 -9.95 kB 🟢 -8.81 kB
assets/SecretsPanel-BYpJlEZ4.js (new) 33.7 kB 🔴 +33.7 kB 🔴 +7.88 kB 🔴 +6.92 kB
assets/SecretsPanel-Dx1Ik4rD.js (removed) 33.7 kB 🟢 -33.7 kB 🟢 -7.87 kB 🟢 -6.9 kB
assets/CreditsPanel-C1PCFzx7.js (new) 11.5 kB 🔴 +11.5 kB 🔴 +3.21 kB 🔴 +2.8 kB
assets/CreditsPanel-CciNkDD9.js (removed) 11.5 kB 🟢 -11.5 kB 🟢 -3.21 kB 🟢 -2.81 kB
assets/AboutPanel-bZpSP629.js (removed) 11.2 kB 🟢 -11.2 kB 🟢 -3.03 kB 🟢 -2.72 kB
assets/AboutPanel-kxrVnqL-.js (new) 11.2 kB 🔴 +11.2 kB 🔴 +3.03 kB 🔴 +2.72 kB
assets/ExtensionPanel-C4az63Yz.js (removed) 9.19 kB 🟢 -9.19 kB 🟢 -2.51 kB 🟢 -2.23 kB
assets/ExtensionPanel-rVLXo_tV.js (new) 9.19 kB 🔴 +9.19 kB 🔴 +2.51 kB 🔴 +2.23 kB
assets/ServerConfigPanel-D4TjSDRq.js (new) 6.09 kB 🔴 +6.09 kB 🔴 +1.94 kB 🔴 +1.72 kB
assets/ServerConfigPanel-DnH9OGMQ.js (removed) 6.09 kB 🟢 -6.09 kB 🟢 -1.94 kB 🟢 -1.72 kB
assets/UserPanel-CRadqZrt.js (new) 5.73 kB 🔴 +5.73 kB 🔴 +1.78 kB 🔴 +1.56 kB
assets/UserPanel-CTXwbDrk.js (removed) 5.73 kB 🟢 -5.73 kB 🟢 -1.78 kB 🟢 -1.56 kB
assets/refreshRemoteConfig-B1U8jmpk.js (new) 3.44 kB 🔴 +3.44 kB 🔴 +1.33 kB 🔴 +1.17 kB
assets/refreshRemoteConfig-CChV6NfY.js (removed) 3.44 kB 🟢 -3.44 kB 🟢 -1.33 kB 🟢 -1.17 kB
assets/cloudRemoteConfig-CikDX5DY.js (removed) 951 B 🟢 -951 B 🟢 -515 B 🟢 -421 B
assets/cloudRemoteConfig-DPnXFA5P.js (new) 951 B 🔴 +951 B 🔴 +516 B 🔴 +435 B
assets/refreshRemoteConfig-Bj82dwLY.js (removed) 110 B 🟢 -110 B 🟢 -89 B 🟢 -90 B
assets/refreshRemoteConfig-CkuWe1v3.js (new) 110 B 🔴 +110 B 🔴 +89 B 🔴 +88 B

Status: 10 added / 10 removed / 16 unchanged

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

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/SignUpForm-BTrItlc8.js (removed) 12.8 kB 🟢 -12.8 kB 🟢 -4.32 kB 🟢 -3.76 kB
assets/SignUpForm-CRpKarSU.js (new) 12.8 kB 🔴 +12.8 kB 🔴 +4.32 kB 🔴 +3.76 kB
assets/auth-BZrMOfVp.js (removed) 3.71 kB 🟢 -3.71 kB 🟢 -1.29 kB 🟢 -1.1 kB
assets/auth-Dm0HlyNa.js (new) 3.71 kB 🔴 +3.71 kB 🔴 +1.29 kB 🔴 +1.1 kB
assets/UpdatePasswordContent-CIy33gM0.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +843 B 🔴 +736 B
assets/UpdatePasswordContent-DNRtFzG_.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -841 B 🟢 -735 B
assets/authStore-C9_ajZk-.js (removed) 128 B 🟢 -128 B 🟢 -107 B 🟢 -104 B
assets/authStore-CbGNk2qD.js (new) 128 B 🔴 +128 B 🔴 +107 B 🔴 +107 B
assets/workspaceAuthStore-BDGMUWCg.js (new) 108 B 🔴 +108 B 🔴 +99 B 🔴 +107 B
assets/workspaceAuthStore-DIg7QMe7.js (removed) 108 B 🟢 -108 B 🟢 -99 B 🟢 -112 B
assets/auth-2lXwoguB.js (new) 105 B 🔴 +105 B 🔴 +96 B 🔴 +80 B
assets/auth-rwzF2fOK.js (removed) 105 B 🟢 -105 B 🟢 -96 B 🟢 -84 B

Status: 6 added / 6 removed / 5 unchanged

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

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyHubPublishDialog-BNibSvyY.js (new) 90.1 kB 🔴 +90.1 kB 🔴 +19.3 kB 🔴 +16.5 kB
assets/ComfyHubPublishDialog-CbJ1NYor.js (removed) 90.1 kB 🟢 -90.1 kB 🟢 -19.3 kB 🟢 -16.5 kB
assets/useShareDialog-C7C2qNpO.js (new) 23.9 kB 🔴 +23.9 kB 🔴 +5.7 kB 🔴 +5.05 kB
assets/useShareDialog-CnvT2LT5.js (removed) 23.9 kB 🟢 -23.9 kB 🟢 -5.7 kB 🟢 -5.04 kB
assets/feedbackDialog-B_aWA4fl.js (removed) 4.45 kB 🟢 -4.45 kB 🟢 -1.86 kB 🟢 -1.59 kB
assets/feedbackDialog-DjL2T6Lh.js (new) 4.45 kB 🔴 +4.45 kB 🔴 +1.86 kB 🔴 +1.59 kB
assets/useRangeEditor-BQH1VPzU.js (new) 3.29 kB 🔴 +3.29 kB 🔴 +1.14 kB 🔴 +1.03 kB
assets/useRangeEditor-BzUfN8z1.js (removed) 3.29 kB 🟢 -3.29 kB 🟢 -1.14 kB 🟢 -1.05 kB
assets/useLayerEditor-BEAHZdT4.js (new) 1.01 kB 🔴 +1.01 kB 🔴 +492 B 🔴 +405 B
assets/useLayerEditor-C9uUI0NH.js (removed) 1.01 kB 🟢 -1.01 kB 🟢 -491 B 🟢 -409 B
assets/ComfyHubPublishDialog-BSHCrfhz.js (new) 143 B 🔴 +143 B 🔴 +105 B 🔴 +92 B
assets/ComfyHubPublishDialog-CmwW0NCg.js (removed) 143 B 🟢 -143 B 🟢 -105 B 🟢 -89 B
assets/useSubscriptionDialog-DbuvlSap.js (new) 108 B 🔴 +108 B 🔴 +102 B 🔴 +90 B
assets/useSubscriptionDialog-h89f_xm7.js (removed) 108 B 🟢 -108 B 🟢 -102 B 🟢 -101 B

Status: 7 added / 7 removed / 1 unchanged

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-BI9yx5_A.js (removed) 14.6 kB 🟢 -14.6 kB 🟢 -3.97 kB 🟢 -3.52 kB
assets/ComfyQueueButton-D3YyVswJ.js (new) 14.6 kB 🔴 +14.6 kB 🔴 +3.97 kB 🔴 +3.53 kB
assets/useTerminalTabs-BRK020Wr.js (new) 11.8 kB 🔴 +11.8 kB 🔴 +3.69 kB 🔴 +3.27 kB
assets/useTerminalTabs-ClyhpSCB.js (removed) 11.8 kB 🟢 -11.8 kB 🟢 -3.69 kB 🟢 -3.27 kB
assets/InviteMembersForm-C1-Phvh6.js (removed) 8.2 kB 🟢 -8.2 kB 🟢 -2.72 kB 🟢 -2.43 kB
assets/InviteMembersForm-X3QxCsbp.js (new) 8.2 kB 🔴 +8.2 kB 🔴 +2.72 kB 🔴 +2.44 kB
assets/SubscribeButton-B6PouRsV.js (removed) 2.15 kB 🟢 -2.15 kB 🟢 -969 B 🟢 -848 B
assets/SubscribeButton-Cnh1v4Vh.js (new) 2.15 kB 🔴 +2.15 kB 🔴 +970 B 🔴 +848 B
assets/cloudFeedbackTopbarButton-BggwoVvu.js (removed) 705 B 🟢 -705 B 🟢 -421 B 🟢 -363 B
assets/cloudFeedbackTopbarButton-Bx3CFm1Y.js (new) 705 B 🔴 +705 B 🔴 +422 B 🔴 +361 B
assets/ComfyQueueButton-aiQ6BrgD.js (removed) 128 B 🟢 -128 B 🟢 -99 B 🟢 -93 B
assets/ComfyQueueButton-DxRK7K0J.js (new) 128 B 🔴 +128 B 🔴 +99 B 🔴 +91 B

Status: 6 added / 6 removed / 8 unchanged

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

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/settingStore-BNVxNcOL.js (new) 3.23 MB 🔴 +3.23 MB 🔴 +749 kB 🔴 +563 kB
assets/settingStore-DGpEh_pm.js (removed) 3.23 MB 🟢 -3.23 MB 🟢 -749 kB 🟢 -564 kB
assets/load3dService-BkfPsMnf.js (new) 132 kB 🔴 +132 kB 🔴 +29.3 kB 🔴 +24.7 kB
assets/load3dService-DClfWp4d.js (removed) 132 kB 🟢 -132 kB 🟢 -29.3 kB 🟢 -24.6 kB
assets/api-CYvHfmoO.js (new) 98.4 kB 🔴 +98.4 kB 🔴 +27.3 kB 🔴 +23.4 kB
assets/api-DhxmpuT1.js (removed) 98.4 kB 🟢 -98.4 kB 🟢 -27.3 kB 🟢 -23.4 kB
assets/workflowShareService-BdI9C94A.js (new) 16.5 kB 🔴 +16.5 kB 🔴 +4.92 kB 🔴 +4.35 kB
assets/workflowShareService-BmvtHaeB.js (removed) 16.5 kB 🟢 -16.5 kB 🟢 -4.91 kB 🟢 -4.35 kB
assets/keybindingService-DE_FwKqF.js (new) 6.89 kB 🔴 +6.89 kB 🔴 +1.73 kB 🔴 +1.5 kB
assets/keybindingService-og24EoEx.js (removed) 6.89 kB 🟢 -6.89 kB 🟢 -1.73 kB 🟢 -1.5 kB
assets/releaseStore-DyhyIk-I.js (new) 6.72 kB 🔴 +6.72 kB 🔴 +2.03 kB 🔴 +1.77 kB
assets/releaseStore-Hj5447L2.js (removed) 6.72 kB 🟢 -6.72 kB 🟢 -2.03 kB 🟢 -1.77 kB
assets/systemStatsStore-CrIcU4QE.js (removed) 4.93 kB 🟢 -4.93 kB 🟢 -1.74 kB 🟢 -1.47 kB
assets/systemStatsStore-up6WK6VW.js (new) 4.93 kB 🔴 +4.93 kB 🔴 +1.74 kB 🔴 +1.47 kB
assets/userStore-BRbRY3MT.js (new) 2.38 kB 🔴 +2.38 kB 🔴 +897 B 🔴 +796 B
assets/userStore-DAKTEpAg.js (removed) 2.38 kB 🟢 -2.38 kB 🟢 -896 B 🟢 -794 B
assets/audioService-CXvm8AEf.js (removed) 1.71 kB 🟢 -1.71 kB 🟢 -829 B 🟢 -734 B
assets/audioService-pTI3-57E.js (new) 1.71 kB 🔴 +1.71 kB 🔴 +831 B 🔴 +722 B
assets/dialogService-CoS3rvc-.js (new) 98 B 🔴 +98 B 🔴 +97 B 🔴 +93 B
assets/dialogService-Dq_wjeOc.js (removed) 98 B 🟢 -98 B 🟢 -97 B 🟢 -83 B
assets/releaseStore-BO_Xzszm.js (new) 95 B 🔴 +95 B 🔴 +86 B 🔴 +84 B
assets/releaseStore-D9FlbFp7.js (removed) 95 B 🟢 -95 B 🟢 -86 B 🟢 -88 B
assets/settingStore-By0Uh_t3.js (new) 95 B 🔴 +95 B 🔴 +86 B 🔴 +84 B
assets/settingStore-DxHfCjSs.js (removed) 95 B 🟢 -95 B 🟢 -86 B 🟢 -79 B
assets/assetsStore-aP_3SMab.js (removed) 94 B 🟢 -94 B 🟢 -92 B 🟢 -83 B
assets/assetsStore-Vg0pyHdP.js (new) 94 B 🔴 +94 B 🔴 +92 B 🔴 +84 B
assets/api-BdNIUkA7.js (new) 62 B 🔴 +62 B 🔴 +74 B 🔴 +66 B
assets/api-Chp0eW55.js (removed) 62 B 🟢 -62 B 🟢 -74 B 🟢 -66 B

Status: 14 added / 14 removed / 3 unchanged

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

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useConflictDetection-BIUs4Wu-.js (new) 236 kB 🔴 +236 kB 🔴 +53 kB 🔴 +43.1 kB
assets/useConflictDetection-DqXFHA_K.js (removed) 236 kB 🟢 -236 kB 🟢 -53 kB 🟢 -43.2 kB
assets/useLayerEditorSession-gNc4M4fc.js (new) 158 kB 🔴 +158 kB 🔴 +40.8 kB 🔴 +34.3 kB
assets/useLayerEditorSession-ns9lsJ_R.js (removed) 158 kB 🟢 -158 kB 🟢 -40.8 kB 🟢 -34.3 kB
assets/useLoad3d-B9rLid3q.js (new) 25.8 kB 🔴 +25.8 kB 🔴 +5.8 kB 🔴 +5.14 kB
assets/useLoad3d-DtBMJ7Zi.js (removed) 25.8 kB 🟢 -25.8 kB 🟢 -5.8 kB 🟢 -5.13 kB
assets/useLoad3dViewer-BI7-ziHf.js (new) 21.2 kB 🔴 +21.2 kB 🔴 +4.98 kB 🔴 +4.36 kB
assets/useLoad3dViewer-BkcjUSAp.js (removed) 21.2 kB 🟢 -21.2 kB 🟢 -4.98 kB 🟢 -4.37 kB
assets/useImageCrop-Bcxu-bBl.js (new) 14.9 kB 🔴 +14.9 kB 🔴 +3.42 kB 🔴 +2.98 kB
assets/useImageCrop-CRq23Dsl.js (removed) 14.9 kB 🟢 -14.9 kB 🟢 -3.42 kB 🟢 -2.98 kB
assets/useDowngradeToPersonal-5gd3jNQd.js (removed) 10.9 kB 🟢 -10.9 kB 🟢 -2.75 kB 🟢 -2.37 kB
assets/useDowngradeToPersonal-C-yES9Y1.js (new) 10.9 kB 🔴 +10.9 kB 🔴 +2.75 kB 🔴 +2.36 kB
assets/useFeatureFlags-B89RNHSD.js (new) 6.99 kB 🔴 +6.99 kB 🔴 +2 kB 🔴 +1.73 kB
assets/useFeatureFlags-D2a7QxCN.js (removed) 6.99 kB 🟢 -6.99 kB 🟢 -2 kB 🟢 -1.7 kB
assets/useCompositorLayers-BVpFRHMn.js (new) 2.94 kB 🔴 +2.94 kB 🔴 +897 B 🔴 +809 B
assets/useCompositorLayers-CNDpuhgF.js (removed) 2.94 kB 🟢 -2.94 kB 🟢 -897 B 🟢 -803 B
assets/assetPreviewUtil-DCALGjbo.js (new) 2.35 kB 🔴 +2.35 kB 🔴 +969 B 🔴 +845 B
assets/assetPreviewUtil-VIR3EJgp.js (removed) 2.35 kB 🟢 -2.35 kB 🟢 -966 B 🟢 -847 B
assets/useUpstreamValue-BsMvqIoY.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +757 B 🔴 +684 B
assets/useUpstreamValue-Dn-VoBim.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -758 B 🟢 -685 B
assets/useWorkspaceTierLabel-BCUJl4iX.js (removed) 1.93 kB 🟢 -1.93 kB 🟢 -811 B 🟢 -697 B
assets/useWorkspaceTierLabel-JADb_9rK.js (new) 1.93 kB 🔴 +1.93 kB 🔴 +812 B 🔴 +697 B
assets/subscriptionCheckoutUtil-C26W6fXI.js (new) 877 B 🔴 +877 B 🔴 +522 B 🔴 +439 B
assets/subscriptionCheckoutUtil-CooRZbIX.js (removed) 877 B 🟢 -877 B 🟢 -523 B 🟢 -439 B
assets/useSessionCookie-D7ao2qn6.js (removed) 652 B 🟢 -652 B 🟢 -335 B 🟢 -291 B
assets/useSessionCookie-DVZBWtMB.js (new) 652 B 🔴 +652 B 🔴 +337 B 🔴 +293 B
assets/useLoad3d-DQt4eGsa.js (new) 311 B 🔴 +311 B 🔴 +163 B 🔴 +150 B
assets/useLoad3d-UFxuYgvt.js (removed) 311 B 🟢 -311 B 🟢 -164 B 🟢 -148 B
assets/useSessionCookie-BKCbhubg.js (removed) 101 B 🟢 -101 B 🟢 -86 B 🟢 -80 B
assets/useSessionCookie-VfUBJWBB.js (new) 101 B 🔴 +101 B 🔴 +86 B 🔴 +82 B
assets/useFeatureFlags-DnW98QGr.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +81 B
assets/useFeatureFlags-Dyr895xh.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -92 B
assets/useLoad3dViewer-BCOZRzLJ.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +83 B
assets/useLoad3dViewer-Bk1fpQ0F.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -84 B
assets/useCurrentUser-D8SGgJS_.js (new) 94 B 🔴 +94 B 🔴 +95 B 🔴 +86 B
assets/useCurrentUser-Dufql39L.js (removed) 94 B 🟢 -94 B 🟢 -95 B 🟢 -85 B

Status: 18 added / 18 removed / 20 unchanged

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

External libraries and shared vendor chunks

Status: 18 unchanged

Other — 14.2 MB (baseline 14.2 MB) • 🔴 +176 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-Cijf9MAM.js (new) 115 kB 🔴 +115 kB 🔴 +29.7 kB 🔴 +25.1 kB
assets/core-D2NN4pwf.js (removed) 115 kB 🟢 -115 kB 🟢 -29.7 kB 🟢 -25.1 kB
assets/WidgetSelect-CM3Jqkwa.js (new) 88.8 kB 🔴 +88.8 kB 🔴 +20.1 kB 🔴 +17.2 kB
assets/WidgetSelect-CY0eiNtK.js (removed) 88.8 kB 🟢 -88.8 kB 🟢 -20.1 kB 🟢 -17.2 kB
assets/SubscriptionPanelContentWorkspace-B771TQfP.js (removed) 80 kB 🟢 -80 kB 🟢 -15.8 kB 🟢 -13.6 kB
assets/SubscriptionPanelContentWorkspace-JAZW70uf.js (new) 80 kB 🔴 +80 kB 🔴 +15.8 kB 🔴 +13.6 kB
assets/Load3D-DhVjgku9.js (removed) 71.3 kB 🟢 -71.3 kB 🟢 -11.7 kB 🟢 -9.97 kB
assets/Load3D-nycPUDdl.js (new) 71.3 kB 🔴 +71.3 kB 🔴 +11.7 kB 🔴 +9.98 kB
assets/WidgetVideoEdit-D0ihA0zi.js (removed) 67.5 kB 🟢 -67.5 kB 🟢 -15.7 kB 🟢 -13.9 kB
assets/WidgetVideoEdit-DA_Vn9ZL.js (new) 67.5 kB 🔴 +67.5 kB 🔴 +15.7 kB 🔴 +13.9 kB
assets/SubscriptionTransitionPreviewWorkspace-CN6bhRd9.js (removed) 66.5 kB 🟢 -66.5 kB 🟢 -13.4 kB 🟢 -11.7 kB
assets/SubscriptionTransitionPreviewWorkspace-pCUkTZea.js (new) 66.5 kB 🔴 +66.5 kB 🔴 +13.4 kB 🔴 +11.7 kB
assets/WorkspaceSettingsPanelContent-BQz9kYk9.js (removed) 58.2 kB 🟢 -58.2 kB 🟢 -12.4 kB 🟢 -10.8 kB
assets/WorkspaceSettingsPanelContent-BRm5bMzs.js (new) 58.2 kB 🔴 +58.2 kB 🔴 +12.4 kB 🔴 +10.8 kB
assets/Preview3d-DH4KsDxE.js (new) 50.9 kB 🔴 +50.9 kB 🔴 +8.32 kB 🔴 +7.24 kB
assets/Preview3d-Ds_fqUGw.js (removed) 50.9 kB 🟢 -50.9 kB 🟢 -8.32 kB 🟢 -7.25 kB
assets/main-nF7xuCBG.js (new) 45.3 kB 🔴 +45.3 kB 🔴 +13.2 kB 🔴 +11.4 kB
assets/main-smPwYg5h.js (removed) 45.3 kB 🟢 -45.3 kB 🟢 -13.2 kB 🟢 -11.4 kB
assets/SubscriptionRequiredDialogContentUnified-C0Y4ILLk.js (new) 42.6 kB 🔴 +42.6 kB 🔴 +9.36 kB 🔴 +8.16 kB
assets/SubscriptionRequiredDialogContentUnified-C6ksYrUv.js (removed) 42.6 kB 🟢 -42.6 kB 🟢 -9.36 kB 🟢 -8.16 kB
assets/LayerEditorContent-2MZ3cPnB.js (new) 42.5 kB 🔴 +42.5 kB 🔴 +9.62 kB 🔴 +8.43 kB
assets/LayerEditorContent-4jGhwBb1.js (removed) 42.5 kB 🟢 -42.5 kB 🟢 -9.62 kB 🟢 -8.43 kB
assets/WidgetBoundingBoxes-3q_oMUR5.js (new) 33.7 kB 🔴 +33.7 kB 🔴 +9.16 kB 🔴 +8.12 kB
assets/WidgetBoundingBoxes-D0A9dUFw.js (removed) 33.7 kB 🟢 -33.7 kB 🟢 -9.16 kB 🟢 -8.12 kB
assets/WidgetPainter-CP5PJdMy.js (removed) 32.6 kB 🟢 -32.6 kB 🟢 -7.88 kB 🟢 -6.98 kB
assets/WidgetPainter-DxNfy3ma.js (new) 32.6 kB 🔴 +32.6 kB 🔴 +7.88 kB 🔴 +6.97 kB
assets/Load3dViewerContent-B-07khQC.js (new) 30.8 kB 🔴 +30.8 kB 🔴 +6.29 kB 🔴 +5.45 kB
assets/Load3dViewerContent-f6IqYRm8.js (removed) 30.8 kB 🟢 -30.8 kB 🟢 -6.29 kB 🟢 -5.44 kB
assets/SubscriptionRequiredDialogContent-B7gZGbTb.js (new) 26.9 kB 🔴 +26.9 kB 🔴 +6.36 kB 🔴 +5.6 kB
assets/SubscriptionRequiredDialogContent-W3Kj0PXU.js (removed) 26.9 kB 🟢 -26.9 kB 🟢 -6.36 kB 🟢 -5.61 kB
assets/SubscriptionRequiredDialogContentWorkspace-CbUFYe2P.js (new) 25.1 kB 🔴 +25.1 kB 🔴 +5.79 kB 🔴 +5.1 kB
assets/SubscriptionRequiredDialogContentWorkspace-DB4mZ0nB.js (removed) 25.1 kB 🟢 -25.1 kB 🟢 -5.79 kB 🟢 -5.11 kB
assets/CreditsTile-BbOFSDPz.js (new) 25 kB 🔴 +25 kB 🔴 +6.68 kB 🔴 +5.87 kB
assets/CreditsTile-mEXs7eCM.js (removed) 24.9 kB 🟢 -24.9 kB 🟢 -6.65 kB 🟢 -5.83 kB
assets/load3d-BliqYMLT.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +5.4 kB 🔴 +4.67 kB
assets/load3d-Ct13gG-f.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -5.4 kB 🟢 -4.67 kB
assets/CurrentUserPopoverWorkspace-BayEXExN.js (removed) 21.5 kB 🟢 -21.5 kB 🟢 -4.85 kB 🟢 -4.31 kB
assets/CurrentUserPopoverWorkspace-Bd5SVt5-.js (new) 21.5 kB 🔴 +21.5 kB 🔴 +4.85 kB 🔴 +4.32 kB
assets/SignInContent-Cb0Tjsp0.js (new) 20.2 kB 🔴 +20.2 kB 🔴 +5.09 kB 🔴 +4.46 kB
assets/SignInContent-D8km7LOo.js (removed) 20.2 kB 🟢 -20.2 kB 🟢 -5.09 kB 🟢 -4.45 kB
assets/WidgetRecordAudio-C4v_PnBa.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.6 kB 🔴 +4.1 kB
assets/WidgetRecordAudio-DtDbKnxC.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.6 kB 🟢 -4.09 kB
assets/WidgetInputNumber-BERrWDTz.js (removed) 13.9 kB 🟢 -13.9 kB 🟢 -3.64 kB 🟢 -3.21 kB
assets/WidgetInputNumber-D0R65hgG.js (new) 13.9 kB 🔴 +13.9 kB 🔴 +3.63 kB 🔴 +3.21 kB
assets/WidgetRange-CHVPl2ou.js (removed) 13.7 kB 🟢 -13.7 kB 🟢 -3.55 kB 🟢 -3.12 kB
assets/WidgetRange-CM9jnLzi.js (new) 13.7 kB 🔴 +13.7 kB 🔴 +3.55 kB 🔴 +3.12 kB
assets/WaveAudioPlayer--Dj1mBKn.js (removed) 12.8 kB 🟢 -12.8 kB 🟢 -3.46 kB 🟢 -3.05 kB
assets/WaveAudioPlayer-HIGraVEY.js (new) 12.8 kB 🔴 +12.8 kB 🔴 +3.46 kB 🔴 +3.05 kB
assets/WidgetCurve-C_ME4sTb.js (removed) 11.2 kB 🟢 -11.2 kB 🟢 -3.48 kB 🟢 -3.15 kB
assets/WidgetCurve-M3FDGDan.js (new) 11.2 kB 🔴 +11.2 kB 🔴 +3.48 kB 🔴 +3.15 kB
assets/TeamWorkspacesDialogContent-C1ITUBkt.js (removed) 10.3 kB 🟢 -10.3 kB 🟢 -2.97 kB 🟢 -2.63 kB
assets/TeamWorkspacesDialogContent-DMVhssjJ.js (new) 10.3 kB 🔴 +10.3 kB 🔴 +2.97 kB 🔴 +2.63 kB
assets/onboardingCloudRoutes-Cxt2SytB.js (removed) 9.39 kB 🟢 -9.39 kB 🟢 -2.85 kB 🟢 -2.44 kB
assets/onboardingCloudRoutes-QGkXO_gK.js (new) 9.39 kB 🔴 +9.39 kB 🔴 +2.85 kB 🔴 +2.45 kB
assets/Load3DConfiguration-CruWwCbR.js (new) 8.91 kB 🔴 +8.91 kB 🔴 +2.61 kB 🔴 +2.3 kB
assets/Load3DConfiguration-Cvj6O09X.js (removed) 8.91 kB 🟢 -8.91 kB 🟢 -2.61 kB 🟢 -2.3 kB
assets/WidgetImageCrop-BecnrvmO.js (new) 8.49 kB 🔴 +8.49 kB 🔴 +2.65 kB 🔴 +2.34 kB
assets/WidgetImageCrop-pC-ZhUB0.js (removed) 8.49 kB 🟢 -8.49 kB 🟢 -2.65 kB 🟢 -2.34 kB
assets/SetMemberCreditLimitDialogContent-Bv-qttgQ.js (removed) 8.47 kB 🟢 -8.47 kB 🟢 -2.34 kB 🟢 -2.05 kB
assets/SetMemberCreditLimitDialogContent-jWP9S3w7.js (new) 8.47 kB 🔴 +8.47 kB 🔴 +2.34 kB 🔴 +2.05 kB
assets/nodeTemplates-C6BDnLwX.js (removed) 8.32 kB 🟢 -8.32 kB 🟢 -2.85 kB 🟢 -2.51 kB
assets/nodeTemplates-CEFr1Geg.js (new) 8.32 kB 🔴 +8.32 kB 🔴 +2.85 kB 🔴 +2.51 kB
assets/NightlySurveyController-CI-rjS2x.js (removed) 7.5 kB 🟢 -7.5 kB 🟢 -2.55 kB 🟢 -2.25 kB
assets/NightlySurveyController-itw9RKYc.js (new) 7.5 kB 🔴 +7.5 kB 🔴 +2.56 kB 🔴 +2.25 kB
assets/CloudRunButtonWrapper-CoQgZTrX.js (removed) 6.84 kB 🟢 -6.84 kB 🟢 -2.18 kB 🟢 -1.91 kB
assets/CloudRunButtonWrapper-gyHAPsuA.js (new) 6.84 kB 🔴 +6.84 kB 🔴 +2.18 kB 🔴 +1.91 kB
assets/WidgetWithControl-BiabRktV.js (new) 6.44 kB 🔴 +6.44 kB 🔴 +2.63 kB 🔴 +2.33 kB
assets/WidgetWithControl-ChSHuF5P.js (removed) 6.44 kB 🟢 -6.44 kB 🟢 -2.63 kB 🟢 -2.33 kB
assets/missingModelMetadata-DDEVbggW.js (removed) 6.17 kB 🟢 -6.17 kB 🟢 -2.13 kB 🟢 -1.86 kB
assets/missingModelMetadata-DO8KQnH1.js (new) 6.17 kB 🔴 +6.17 kB 🔴 +2.13 kB 🔴 +1.86 kB
assets/CancelSubscriptionDialogContent-2fptwaYA.js (removed) 5.97 kB 🟢 -5.97 kB 🟢 -1.98 kB 🟢 -1.75 kB
assets/CancelSubscriptionDialogContent-DEGgEVlF.js (new) 5.97 kB 🔴 +5.97 kB 🔴 +1.98 kB 🔴 +1.75 kB
assets/load3dPreviewExtensions-DbH3pcuK.js (removed) 5.88 kB 🟢 -5.88 kB 🟢 -1.81 kB 🟢 -1.6 kB
assets/load3dPreviewExtensions-DSUnyPFs.js (new) 5.88 kB 🔴 +5.88 kB 🔴 +1.81 kB 🔴 +1.6 kB
assets/launchCancellationFlow-B9yGvtQN.js (new) 5.18 kB 🔴 +5.18 kB 🔴 +1.78 kB 🔴 +1.56 kB
assets/launchCancellationFlow-DXNqPCBy.js (removed) 5.18 kB 🟢 -5.18 kB 🟢 -1.78 kB 🟢 -1.56 kB
assets/CreateWorkspaceDialogContent-B6UWmdFA.js (new) 5.12 kB 🔴 +5.12 kB 🔴 +1.79 kB 🔴 +1.55 kB
assets/CreateWorkspaceDialogContent-CwQT_K5t.js (removed) 5.12 kB 🟢 -5.12 kB 🟢 -1.79 kB 🟢 -1.55 kB
assets/ChangeMemberRoleDialogContent-CWGTEbSn.js (removed) 4.97 kB 🟢 -4.97 kB 🟢 -1.64 kB 🟢 -1.43 kB
assets/ChangeMemberRoleDialogContent-DnHI5gDc.js (new) 4.97 kB 🔴 +4.97 kB 🔴 +1.64 kB 🔴 +1.43 kB
assets/InviteMemberDialogContent-0v4yrD95.js (removed) 4.96 kB 🟢 -4.96 kB 🟢 -1.64 kB 🟢 -1.44 kB
assets/InviteMemberDialogContent-CRcbp-3r.js (new) 4.96 kB 🔴 +4.96 kB 🔴 +1.65 kB 🔴 +1.44 kB
assets/EditWorkspaceDialogContent-CAdxN1fN.js (new) 4.93 kB 🔴 +4.93 kB 🔴 +1.76 kB 🔴 +1.52 kB
assets/EditWorkspaceDialogContent-DnXcNPqN.js (removed) 4.93 kB 🟢 -4.93 kB 🟢 -1.76 kB 🟢 -1.53 kB
assets/WidgetTextarea-CEAsjOUe.js (new) 4.81 kB 🔴 +4.81 kB 🔴 +1.87 kB 🔴 +1.64 kB
assets/WidgetTextarea-DIQmuhC8.js (removed) 4.81 kB 🟢 -4.81 kB 🟢 -1.87 kB 🟢 -1.64 kB
assets/saveMesh-CpSBvMSp.js (new) 4.76 kB 🔴 +4.76 kB 🔴 +1.52 kB 🔴 +1.34 kB
assets/saveMesh-DrTl5Rmv.js (removed) 4.76 kB 🟢 -4.76 kB 🟢 -1.52 kB 🟢 -1.37 kB
assets/WorkspacePanelContent-B17E3zOY.js (new) 4.74 kB 🔴 +4.74 kB 🔴 +1.63 kB 🔴 +1.44 kB
assets/WorkspacePanelContent-Cc2irNPD.js (removed) 4.74 kB 🟢 -4.74 kB 🟢 -1.63 kB 🟢 -1.44 kB
assets/ValueControlPopover-B1uJd78N.js (removed) 4.49 kB 🟢 -4.49 kB 🟢 -1.55 kB 🟢 -1.38 kB
assets/ValueControlPopover-CYpH8oyA.js (new) 4.49 kB 🔴 +4.49 kB 🔴 +1.55 kB 🔴 +1.38 kB
assets/DeleteWorkspaceDialogContent-BZHZt2_0.js (removed) 3.84 kB 🟢 -3.84 kB 🟢 -1.44 kB 🟢 -1.24 kB
assets/DeleteWorkspaceDialogContent-Dk-dL4u1.js (new) 3.84 kB 🔴 +3.84 kB 🔴 +1.44 kB 🔴 +1.24 kB
assets/RemoveMemberDialogContent-BC4vlEV5.js (new) 3.76 kB 🔴 +3.76 kB 🔴 +1.39 kB 🔴 +1.21 kB
assets/RemoveMemberDialogContent-BV3azIJV.js (removed) 3.76 kB 🟢 -3.76 kB 🟢 -1.38 kB 🟢 -1.21 kB
assets/RevokeInviteDialogContent-CDby3a46.js (removed) 3.67 kB 🟢 -3.67 kB 🟢 -1.39 kB 🟢 -1.21 kB
assets/RevokeInviteDialogContent-vjqYnCuw.js (new) 3.67 kB 🔴 +3.67 kB 🔴 +1.39 kB 🔴 +1.21 kB
assets/LeaveWorkspaceDialogContent-B4vlWun0.js (new) 3.67 kB 🔴 +3.67 kB 🔴 +1.39 kB 🔴 +1.21 kB
assets/LeaveWorkspaceDialogContent-Diy3z5Ox.js (removed) 3.67 kB 🟢 -3.67 kB 🟢 -1.39 kB 🟢 -1.21 kB
assets/InviteMemberUpsellDialogContent-DBf_f0zt.js (new) 3.47 kB 🔴 +3.47 kB 🔴 +1.24 kB 🔴 +1.09 kB
assets/InviteMemberUpsellDialogContent-gTvYmOV2.js (removed) 3.47 kB 🟢 -3.47 kB 🟢 -1.24 kB 🟢 -1.09 kB
assets/workspaceCheckoutTelemetry-DtW8w5xe.js (new) 3.4 kB 🔴 +3.4 kB 🔴 +1.52 kB 🔴 +1.33 kB
assets/workspaceCheckoutTelemetry-LszWfAyG.js (removed) 3.4 kB 🟢 -3.4 kB 🟢 -1.52 kB 🟢 -1.33 kB
assets/GlobalToast-Dkk9aGSj.js (new) 3.25 kB 🔴 +3.25 kB 🔴 +1.3 kB 🔴 +1.11 kB
assets/GlobalToast-SkhWtiDm.js (removed) 3.25 kB 🟢 -3.25 kB 🟢 -1.3 kB 🟢 -1.12 kB
assets/Media3DTop--Y8nimKR.js (new) 3.21 kB 🔴 +3.21 kB 🔴 +1.26 kB 🔴 +1.11 kB
assets/Media3DTop-DV5dPpBk.js (removed) 3.21 kB 🟢 -3.21 kB 🟢 -1.27 kB 🟢 -1.11 kB
assets/load3dAdvanced-C0cox3Uf.js (removed) 2.82 kB 🟢 -2.82 kB 🟢 -1.09 kB 🟢 -955 B
assets/load3dAdvanced-mvGaI_lQ.js (new) 2.82 kB 🔴 +2.82 kB 🔴 +1.09 kB 🔴 +954 B
assets/SubscribeToRun-bORgG3sZ.js (new) 2.39 kB 🔴 +2.39 kB 🔴 +1.03 kB 🔴 +907 B
assets/SubscribeToRun-CO6hyhQ0.js (removed) 2.39 kB 🟢 -2.39 kB 🟢 -1.03 kB 🟢 -908 B
assets/MediaAudioTop-BKEcZDEn.js (new) 1.62 kB 🔴 +1.62 kB 🔴 +808 B 🔴 +671 B
assets/MediaAudioTop-CsC761MB.js (removed) 1.62 kB 🟢 -1.62 kB 🟢 -807 B 🟢 -666 B
assets/cloudSessionCookie-C0tntLUZ.js (removed) 933 B 🟢 -933 B 🟢 -432 B 🟢 -376 B
assets/cloudSessionCookie-DkHgFXFp.js (new) 933 B 🔴 +933 B 🔴 +432 B 🔴 +378 B
assets/cloudBadges-B1giIvPE.js (new) 922 B 🔴 +922 B 🔴 +516 B 🔴 +446 B
assets/cloudBadges-DCYRrG_b.js (removed) 922 B 🟢 -922 B 🟢 -515 B 🟢 -464 B
assets/Load3DAdvanced-CfwMLwb1.js (removed) 761 B 🟢 -761 B 🟢 -422 B 🟢 -358 B
assets/Load3DAdvanced-Cnb_PpxM.js (new) 761 B 🔴 +761 B 🔴 +421 B 🔴 +358 B
assets/nightlyBadges-9ZAk2sOR.js (new) 411 B 🔴 +411 B 🔴 +272 B 🔴 +232 B
assets/nightlyBadges-Dw-cI4qU.js (removed) 411 B 🟢 -411 B 🟢 -272 B 🟢 -269 B
assets/Load3dViewerContent-BttbJ6oJ.js (removed) 137 B 🟢 -137 B 🟢 -103 B 🟢 -95 B
assets/Load3dViewerContent-Cvd7ru__.js (new) 137 B 🔴 +137 B 🔴 +103 B 🔴 +92 B
assets/missingModelMetadata-C3_Fltm6.js (removed) 125 B 🟢 -125 B 🟢 -103 B 🟢 -103 B
assets/missingModelMetadata-DlzMbxvN.js (new) 125 B 🔴 +125 B 🔴 +103 B 🔴 +104 B
assets/Load3DAdvanced-B5IhsV-U.js (removed) 122 B 🟢 -122 B 🟢 -97 B 🟢 -90 B
assets/Load3DAdvanced-CihXac1J.js (new) 122 B 🔴 +122 B 🔴 +97 B 🔴 +82 B
assets/WidgetLegacy-BvPWwwYY.js (new) 117 B 🔴 +117 B 🔴 +106 B 🔴 +104 B
assets/WidgetLegacy-Cpsbi5JW.js (removed) 117 B 🟢 -117 B 🟢 -106 B 🟢 -105 B
assets/workflowDraftStoreV2-1wtQp6y_.js (removed) 112 B 🟢 -112 B 🟢 -101 B 🟢 -107 B
assets/workflowDraftStoreV2-XUPeHSub.js (new) 112 B 🔴 +112 B 🔴 +101 B 🔴 +110 B
assets/Load3D-DEa0MbGp.js (new) 98 B 🔴 +98 B 🔴 +89 B 🔴 +77 B
assets/Load3D-DnRbnUEe.js (removed) 98 B 🟢 -98 B 🟢 -89 B 🟢 -81 B
assets/changeTracker-CjQClCZg.js (removed) 91 B 🟢 -91 B 🟢 -93 B 🟢 -87 B
assets/changeTracker-D7SBnGFs.js (new) 91 B 🔴 +91 B 🔴 +93 B 🔴 +83 B

Status: 68 added / 68 removed / 218 unchanged

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 67.4 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 54.1 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 70.2 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 51.0 MB heap
large-graph-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 63.6 MB heap
large-graph-pan: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.5 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 70.8 MB heap
minimap-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 64.8 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 51.7 MB heap
subgraph-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 67.5 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 58.6 MB heap
subgraph-transition-enter: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 137ms TBT · 71.4 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 63.2 MB heap
vue-large-graph-idle: · 55.4 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 156.7 MB heap
vue-large-graph-pan: · 55.4 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 145ms TBT · 161.1 MB heap
workflow-execution: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 64.9 MB heap

⚠️ 5 regressions detected

Show regressions
Metric Baseline PR (median) Δ Sig
large-graph-idle: task duration 729ms 661ms -9% ⚠️ z=2.2
large-graph-pan: task duration 1317ms 1270ms -4% ⚠️ z=4.4
minimap-idle: task duration 695ms 659ms -5% ⚠️ z=2.8
subgraph-idle: task duration 478ms 439ms -8% ⚠️ z=2.2
workflow-execution: event listeners 97 73 -25% ⚠️ z=4.8
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 -0%
canvas-idle: layout duration 0ms 0ms +0%
canvas-idle: style recalc duration 7ms 7ms +6% z=-3.8
canvas-idle: layout count 0 0 +0%
canvas-idle: style recalc count 9 9 +0% z=-3.8
canvas-idle: task duration 490ms 448ms -9% z=1.7
canvas-idle: script duration 17ms 15ms -15% z=-4.8
canvas-idle: TBT 0ms 0ms +0%
canvas-idle: heap used 67.6 MB 67.4 MB -0%
canvas-idle: DOM nodes 18 18 +0% z=-3.6
canvas-idle: event listeners 4 4 +0% z=-1.6
canvas-mouse-sweep: avg frame time 17ms 17ms +0% z=-0.4
canvas-mouse-sweep: p95 frame time 17ms 17ms -0%
canvas-mouse-sweep: layout duration 4ms 3ms -8% z=-0.9
canvas-mouse-sweep: style recalc duration 38ms 39ms +1% z=-1.3
canvas-mouse-sweep: layout count 12 12 +0%
canvas-mouse-sweep: style recalc count 76 75 -1% z=-1.6
canvas-mouse-sweep: task duration 913ms 921ms +1% z=1.0
canvas-mouse-sweep: script duration 121ms 130ms +7% z=-0.9
canvas-mouse-sweep: TBT 0ms 0ms +0%
canvas-mouse-sweep: heap used 45.0 MB 54.1 MB +20%
canvas-mouse-sweep: DOM nodes -278 -110 -60% z=-66.6
canvas-mouse-sweep: event listeners -153 -75 -51% z=-19.9
canvas-zoom-sweep: avg frame time 17ms 17ms -0% z=-0.3
canvas-zoom-sweep: p95 frame time 17ms 17ms -1%
canvas-zoom-sweep: layout duration 1ms 1ms -9% z=-2.3
canvas-zoom-sweep: style recalc duration 15ms 15ms +2% z=-2.4
canvas-zoom-sweep: layout count 6 6 +0%
canvas-zoom-sweep: style recalc count 31 30 -3% z=-2.8
canvas-zoom-sweep: task duration 381ms 357ms -6% z=1.3
canvas-zoom-sweep: script duration 19ms 17ms -7% z=-3.2
canvas-zoom-sweep: TBT 0ms 0ms +0%
canvas-zoom-sweep: heap used 70.3 MB 70.2 MB -0%
canvas-zoom-sweep: DOM nodes 77 76 -1% z=-4.1
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 -0%
dom-widget-clipping: layout duration 0ms 0ms +0%
dom-widget-clipping: style recalc duration 8ms 7ms -1% z=-3.1
dom-widget-clipping: layout count 0 0 +0%
dom-widget-clipping: style recalc count 11 11 +0% z=-4.2
dom-widget-clipping: task duration 379ms 372ms -2% z=0.4
dom-widget-clipping: script duration 57ms 60ms +4% z=-2.4
dom-widget-clipping: TBT 0ms 0ms +0%
dom-widget-clipping: heap used 51.0 MB 51.0 MB +0%
dom-widget-clipping: DOM nodes 18 18 +0% z=-2.9
dom-widget-clipping: event listeners 0 0 +0% variance too high
large-graph-idle: avg frame time 17ms 17ms -0% z=-0.6
large-graph-idle: p95 frame time 17ms 17ms -0%
large-graph-idle: layout duration 0ms 0ms +0%
large-graph-idle: style recalc duration 7ms 7ms -1% z=-4.9
large-graph-idle: layout count 0 0 +0%
large-graph-idle: style recalc count 9 9 -6% z=-9.9
large-graph-idle: task duration 729ms 661ms -9% ⚠️ z=2.2
large-graph-idle: script duration 109ms 99ms -9% z=-0.3
large-graph-idle: TBT 0ms 0ms +0%
large-graph-idle: heap used 64.5 MB 63.6 MB -1%
large-graph-idle: DOM nodes -282 -283 +0% z=-339.9
large-graph-idle: event listeners -149 -149 +0% z=-28.7
large-graph-pan: avg frame time 17ms 17ms +0% z=0.3
large-graph-pan: p95 frame time 17ms 17ms +1%
large-graph-pan: layout duration 0ms 0ms +0%
large-graph-pan: style recalc duration 15ms 13ms -9% z=-4.8
large-graph-pan: layout count 0 0 +0%
large-graph-pan: style recalc count 68 69 +1% z=-0.9
large-graph-pan: task duration 1317ms 1270ms -4% ⚠️ z=4.4
large-graph-pan: script duration 425ms 439ms +3% z=1.6
large-graph-pan: TBT 0ms 0ms +0%
large-graph-pan: heap used 62.1 MB 61.5 MB -1%
large-graph-pan: DOM nodes -286 -284 -1% z=-183.3
large-graph-pan: event listeners -149 -148 -1% z=-184.7
large-graph-zoom: avg frame time 17ms 17ms -0%
large-graph-zoom: p95 frame time 17ms 17ms +0%
large-graph-zoom: layout duration 8ms 7ms -11%
large-graph-zoom: style recalc duration 15ms 14ms -9%
large-graph-zoom: layout count 60 60 +0%
large-graph-zoom: style recalc count 64 65 +2%
large-graph-zoom: task duration 1558ms 1472ms -5%
large-graph-zoom: script duration 534ms 530ms -1%
large-graph-zoom: TBT 0ms 0ms +0%
large-graph-zoom: heap used 59.2 MB 70.8 MB +20%
large-graph-zoom: DOM nodes -287 -138 -52%
large-graph-zoom: event listeners -153 -88 -43%
minimap-idle: avg frame time 17ms 17ms -0% z=-0.4
minimap-idle: p95 frame time 17ms 17ms -0%
minimap-idle: layout duration 0ms 0ms +0%
minimap-idle: style recalc duration 7ms 7ms +7% z=-2.7
minimap-idle: layout count 0 0 +0%
minimap-idle: style recalc count 8 9 +6% z=-1.6
minimap-idle: task duration 695ms 659ms -5% ⚠️ z=2.8
minimap-idle: script duration 99ms 99ms +0% z=0.1
minimap-idle: TBT 0ms 0ms +0%
minimap-idle: heap used 63.5 MB 64.8 MB +2%
minimap-idle: DOM nodes -284 -284 -0% z=-221.3
minimap-idle: event listeners -149 -149 +0% z=-232.6
subgraph-dom-widget-clipping: avg frame time 17ms 17ms +0% z=0.7
subgraph-dom-widget-clipping: p95 frame time 17ms 17ms +1%
subgraph-dom-widget-clipping: layout duration 0ms 0ms +0%
subgraph-dom-widget-clipping: style recalc duration 10ms 10ms +3% z=-2.7
subgraph-dom-widget-clipping: layout count 0 0 +0%
subgraph-dom-widget-clipping: style recalc count 47 47 -1% z=-2.5
subgraph-dom-widget-clipping: task duration 418ms 386ms -8% z=0.4
subgraph-dom-widget-clipping: script duration 125ms 117ms -6% z=-1.7
subgraph-dom-widget-clipping: TBT 0ms 0ms +0%
subgraph-dom-widget-clipping: heap used 51.5 MB 51.7 MB +0%
subgraph-dom-widget-clipping: DOM nodes 20 19 -5% z=-2.8
subgraph-dom-widget-clipping: event listeners 6 7 +17% z=-1.6
subgraph-idle: avg frame time 17ms 17ms -0% z=-0.2
subgraph-idle: p95 frame time 17ms 17ms +0%
subgraph-idle: layout duration 0ms 0ms +0%
subgraph-idle: style recalc duration 8ms 8ms -7% z=-3.3
subgraph-idle: layout count 0 0 +0%
subgraph-idle: style recalc count 10 10 +0% z=-1.4
subgraph-idle: task duration 478ms 439ms -8% ⚠️ z=2.2
subgraph-idle: script duration 15ms 12ms -20% z=-3.0
subgraph-idle: TBT 0ms 0ms +0%
subgraph-idle: heap used 67.6 MB 67.5 MB -0%
subgraph-idle: DOM nodes 20 20 +0% z=-1.2
subgraph-idle: event listeners 4 4 +0% variance too high
subgraph-mouse-sweep: avg frame time 17ms 17ms -0% z=-0.1
subgraph-mouse-sweep: p95 frame time 17ms 17ms +1%
subgraph-mouse-sweep: layout duration 4ms 4ms -11% z=-2.3
subgraph-mouse-sweep: style recalc duration 36ms 34ms -7% z=-2.6
subgraph-mouse-sweep: layout count 16 16 +0%
subgraph-mouse-sweep: style recalc count 76 77 +1% z=-1.9
subgraph-mouse-sweep: task duration 766ms 739ms -4% z=-0.4
subgraph-mouse-sweep: script duration 90ms 89ms -1% z=-1.8
subgraph-mouse-sweep: TBT 0ms 0ms +0%
subgraph-mouse-sweep: heap used 58.7 MB 58.6 MB -0%
subgraph-mouse-sweep: DOM nodes 63 63 +0% z=-1.8
subgraph-mouse-sweep: event listeners 4 4 +0% 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 11ms 13ms +13%
subgraph-transition-enter: style recalc duration 29ms 30ms +4%
subgraph-transition-enter: layout count 13 14 +8%
subgraph-transition-enter: style recalc count 17 18 +6%
subgraph-transition-enter: task duration 924ms 887ms -4%
subgraph-transition-enter: script duration 30ms 28ms -7%
subgraph-transition-enter: TBT 121ms 137ms +13%
subgraph-transition-enter: heap used 95.2 MB 71.4 MB -25%
subgraph-transition-enter: DOM nodes 13673 13673 +0%
subgraph-transition-enter: event listeners 2375 2375 +0%
viewport-pan-sweep: avg frame time 17ms 17ms +0%
viewport-pan-sweep: p95 frame time 17ms 17ms +1%
viewport-pan-sweep: layout duration 0ms 0ms +0%
viewport-pan-sweep: style recalc duration 41ms 36ms -13%
viewport-pan-sweep: layout count 0 0 +0%
viewport-pan-sweep: style recalc count 250 250 -0%
viewport-pan-sweep: task duration 4380ms 4450ms +2%
viewport-pan-sweep: script duration 1323ms 1459ms +10%
viewport-pan-sweep: TBT 0ms 0ms +0%
viewport-pan-sweep: heap used 65.7 MB 63.2 MB -4%
viewport-pan-sweep: DOM nodes -281 -284 +1%
viewport-pan-sweep: event listeners -133 -148 +11%
vue-large-graph-idle: avg frame time 18ms 18ms +2%
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 17424ms 16063ms -8%
vue-large-graph-idle: script duration 562ms 527ms -6%
vue-large-graph-idle: TBT 0ms 0ms +0%
vue-large-graph-idle: heap used 159.9 MB 156.7 MB -2%
vue-large-graph-idle: DOM nodes -8312 -8312 +0%
vue-large-graph-idle: event listeners -16387 -16388 +0%
vue-large-graph-pan: avg frame time 18ms 18ms +2%
vue-large-graph-pan: p95 frame time 17ms 17ms +0%
vue-large-graph-pan: layout duration 0ms 0ms +0%
vue-large-graph-pan: style recalc duration 22ms 15ms -30%
vue-large-graph-pan: layout count 0 0 +0%
vue-large-graph-pan: style recalc count 156 139 -11%
vue-large-graph-pan: task duration 21844ms 20097ms -8%
vue-large-graph-pan: script duration 890ms 882ms -1%
vue-large-graph-pan: TBT 457ms 145ms -68%
vue-large-graph-pan: heap used 168.8 MB 161.1 MB -5%
vue-large-graph-pan: DOM nodes -8312 -8312 +0%
vue-large-graph-pan: event listeners -16383 -16388 +0%
workflow-execution: avg frame time 17ms 17ms +0% z=0.6
workflow-execution: p95 frame time 17ms 17ms +0%
workflow-execution: layout duration 1ms 1ms +28% z=-4.9
workflow-execution: style recalc duration 19ms 17ms -8% z=-3.1
workflow-execution: layout count 3 3 -17% z=-4.5
workflow-execution: style recalc count 12 13 +4% z=-2.6
workflow-execution: task duration 105ms 103ms -2% z=-1.9
workflow-execution: script duration 9ms 8ms -11% z=-7.1
workflow-execution: TBT 0ms 0ms +0%
workflow-execution: heap used 65.9 MB 64.9 MB -1%
workflow-execution: DOM nodes 121 128 +6% z=-4.6
workflow-execution: event listeners 97 73 -25% ⚠️ z=4.8
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-13T22:36:20.098Z",
  "gitSha": "250eee3475d98565a3f1ca15f5b1d2131946ba21",
  "branch": "glary/fe-1451-clamp-monthly-remaining-credits",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2048.171000000025,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 7.373999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 447.85699999999997,
      "heapDeltaBytes": 6026480,
      "heapUsedBytes": 70674588,
      "domNodes": 18,
      "jsHeapTotalBytes": 24641536,
      "scriptDurationMs": 15.366,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-idle",
      "durationMs": 2025.2490000000307,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 7.504999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 447.67199999999997,
      "heapDeltaBytes": 5906168,
      "heapUsedBytes": 70588200,
      "domNodes": 18,
      "jsHeapTotalBytes": 24117248,
      "scriptDurationMs": 13.959000000000003,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 2067.1389999999974,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 41.152,
      "layouts": 12,
      "layoutDurationMs": 3.4099999999999997,
      "taskDurationMs": 1044.77,
      "heapDeltaBytes": -16265824,
      "heapUsedBytes": 48402644,
      "domNodes": -275,
      "jsHeapTotalBytes": 24088576,
      "scriptDurationMs": 138.214,
      "eventListeners": -153,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1758.5219999998571,
      "styleRecalcs": 73,
      "styleRecalcDurationMs": 36.034000000000006,
      "layouts": 12,
      "layoutDurationMs": 3.4680000000000004,
      "taskDurationMs": 797.6229999999999,
      "heapDeltaBytes": 432112,
      "heapUsedBytes": 64964728,
      "domNodes": 55,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 121.64899999999999,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1746.1260000000038,
      "styleRecalcs": 30,
      "styleRecalcDurationMs": 16.612,
      "layouts": 6,
      "layoutDurationMs": 0.5580000000000002,
      "taskDurationMs": 363.602,
      "heapDeltaBytes": 8872384,
      "heapUsedBytes": 73585292,
      "domNodes": 76,
      "jsHeapTotalBytes": 24117248,
      "scriptDurationMs": 17.531000000000006,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1714.9540000000343,
      "styleRecalcs": 30,
      "styleRecalcDurationMs": 14.281,
      "layouts": 6,
      "layoutDurationMs": 0.521,
      "taskDurationMs": 350.82099999999997,
      "heapDeltaBytes": 8814408,
      "heapUsedBytes": 73583888,
      "domNodes": 76,
      "jsHeapTotalBytes": 24379392,
      "scriptDurationMs": 17.319000000000003,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 572.1429999999827,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 7.097000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 371.913,
      "heapDeltaBytes": -11257436,
      "heapUsedBytes": 53557904,
      "domNodes": 18,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 60.239999999999995,
      "eventListeners": 0,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 573.9220000000387,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 7.6930000000000005,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 371.79,
      "heapDeltaBytes": -11127484,
      "heapUsedBytes": 53496432,
      "domNodes": 18,
      "jsHeapTotalBytes": 26214400,
      "scriptDurationMs": 59.772999999999996,
      "eventListeners": 0,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2039.5200000000386,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 7.5340000000000025,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 669.4300000000001,
      "heapDeltaBytes": 7241920,
      "heapUsedBytes": 67094880,
      "domNodes": -281,
      "jsHeapTotalBytes": 2981888,
      "scriptDurationMs": 98.985,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2010.7009999999264,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 6.661999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 653.2130000000001,
      "heapDeltaBytes": 6423000,
      "heapUsedBytes": 66300980,
      "domNodes": -284,
      "jsHeapTotalBytes": 3244032,
      "scriptDurationMs": 98.77,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2130.8950000000095,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 13.364999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1228.9240000000002,
      "heapDeltaBytes": 4429248,
      "heapUsedBytes": 65710824,
      "domNodes": -284,
      "jsHeapTotalBytes": 3698688,
      "scriptDurationMs": 415.85799999999995,
      "eventListeners": -147,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2183.269999999993,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 13.513000000000003,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1311.4050000000002,
      "heapDeltaBytes": 2155816,
      "heapUsedBytes": 63173244,
      "domNodes": -283,
      "jsHeapTotalBytes": 4222976,
      "scriptDurationMs": 462.582,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3164.9909999999863,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 13.931,
      "layouts": 60,
      "layoutDurationMs": 7.113000000000001,
      "taskDurationMs": 1421.504,
      "heapDeltaBytes": 23704716,
      "heapUsedBytes": 86913860,
      "domNodes": 12,
      "jsHeapTotalBytes": 7077888,
      "scriptDurationMs": 510.61199999999997,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3231.5860000001067,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 13.994,
      "layouts": 60,
      "layoutDurationMs": 7.188999999999999,
      "taskDurationMs": 1523.388,
      "heapDeltaBytes": -1236320,
      "heapUsedBytes": 61519968,
      "domNodes": -287,
      "jsHeapTotalBytes": 7176192,
      "scriptDurationMs": 549.933,
      "eventListeners": -183,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2025.0810000000001,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 8.121000000000004,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 663.9110000000001,
      "heapDeltaBytes": 7015604,
      "heapUsedBytes": 67913752,
      "domNodes": -283,
      "jsHeapTotalBytes": 4030464,
      "scriptDurationMs": 100.264,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "minimap-idle",
      "durationMs": 2036.1900000000333,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 6.557,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 654.778,
      "heapDeltaBytes": 7128208,
      "heapUsedBytes": 67970652,
      "domNodes": -284,
      "jsHeapTotalBytes": 4292608,
      "scriptDurationMs": 98.55999999999997,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 578.6960000000363,
      "styleRecalcs": 46,
      "styleRecalcDurationMs": 9.464,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 377.67599999999993,
      "heapDeltaBytes": -10824936,
      "heapUsedBytes": 54154220,
      "domNodes": 18,
      "jsHeapTotalBytes": 26214400,
      "scriptDurationMs": 115.012,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 577.9210000000603,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 10.855,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 393.898,
      "heapDeltaBytes": -10577220,
      "heapUsedBytes": 54219004,
      "domNodes": 20,
      "jsHeapTotalBytes": 26476544,
      "scriptDurationMs": 119.407,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-idle",
      "durationMs": 1995.2260000000024,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 7.808000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 441.88700000000006,
      "heapDeltaBytes": 5892656,
      "heapUsedBytes": 70742160,
      "domNodes": 20,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 12.330999999999998,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2011.9529999999486,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 7.855,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 436.414,
      "heapDeltaBytes": 5948052,
      "heapUsedBytes": 70861688,
      "domNodes": 20,
      "jsHeapTotalBytes": 24641536,
      "scriptDurationMs": 12.245,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1719.3479999999681,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 33.166000000000004,
      "layouts": 16,
      "layoutDurationMs": 3.605,
      "taskDurationMs": 739.37,
      "heapDeltaBytes": -3520552,
      "heapUsedBytes": 61339036,
      "domNodes": 64,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 87.74900000000001,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1689.6489999999176,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 34.284,
      "layouts": 16,
      "layoutDurationMs": 4.288,
      "taskDurationMs": 739.321,
      "heapDeltaBytes": -3445160,
      "heapUsedBytes": 61484352,
      "domNodes": 62,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 90.13199999999999,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-transition-enter",
      "durationMs": 1388.9659999999822,
      "styleRecalcs": 18,
      "styleRecalcDurationMs": 29.721999999999998,
      "layouts": 14,
      "layoutDurationMs": 12.655,
      "taskDurationMs": 887.254,
      "heapDeltaBytes": 2181800,
      "heapUsedBytes": 74860148,
      "domNodes": 13673,
      "jsHeapTotalBytes": 15990784,
      "scriptDurationMs": 28.445999999999998,
      "eventListeners": 2375,
      "totalBlockingTimeMs": 137,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8236.361000000103,
      "styleRecalcs": 249,
      "styleRecalcDurationMs": 35.896,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4322.17,
      "heapDeltaBytes": 8510484,
      "heapUsedBytes": 68881724,
      "domNodes": -284,
      "jsHeapTotalBytes": 5795840,
      "scriptDurationMs": 1371.4189999999999,
      "eventListeners": -133,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.669999999999952,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8242.67400000008,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 35.596999999999994,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4578.637000000001,
      "heapDeltaBytes": 3500956,
      "heapUsedBytes": 63729192,
      "domNodes": -283,
      "jsHeapTotalBytes": 9011200,
      "scriptDurationMs": 1547.299,
      "eventListeners": -163,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 15957.459999999855,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 15937.647,
      "heapDeltaBytes": -52573428,
      "heapUsedBytes": 170595824,
      "domNodes": -8312,
      "jsHeapTotalBytes": -12001280,
      "scriptDurationMs": 504.6280000000001,
      "eventListeners": -16389,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 18.333333333333332,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 16217.330999999831,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 16187.859,
      "heapDeltaBytes": -40298088,
      "heapUsedBytes": 158014572,
      "domNodes": -8312,
      "jsHeapTotalBytes": -3088384,
      "scriptDurationMs": 549.9409999999999,
      "eventListeners": -16387,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 20013.60799999998,
      "styleRecalcs": 136,
      "styleRecalcDurationMs": 15.22100000000004,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 19990.905,
      "heapDeltaBytes": -56210208,
      "heapUsedBytes": 158224520,
      "domNodes": -8312,
      "jsHeapTotalBytes": -9375744,
      "scriptDurationMs": 859.8149999999999,
      "eventListeners": -16389,
      "totalBlockingTimeMs": 159,
      "frameDurationMs": 18.330000000000048,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 20260.181999999986,
      "styleRecalcs": 141,
      "styleRecalcDurationMs": 15.712000000000032,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 20203.405,
      "heapDeltaBytes": -37964036,
      "heapUsedBytes": 179715908,
      "domNodes": -8312,
      "jsHeapTotalBytes": -9711616,
      "scriptDurationMs": 903.196,
      "eventListeners": -16387,
      "totalBlockingTimeMs": 130,
      "frameDurationMs": 17.780000000000047,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "workflow-execution",
      "durationMs": 153.1320000001415,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 14.607,
      "layouts": 2,
      "layoutDurationMs": 0.556,
      "taskDurationMs": 88.94399999999999,
      "heapDeltaBytes": 3119884,
      "heapUsedBytes": 67026056,
      "domNodes": 111,
      "jsHeapTotalBytes": 2883584,
      "scriptDurationMs": 5.549999999999999,
      "eventListeners": 49,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 483.8999999999487,
      "styleRecalcs": 17,
      "styleRecalcDurationMs": 20.251,
      "layouts": 3,
      "layoutDurationMs": 1.133,
      "taskDurationMs": 116.59999999999998,
      "heapDeltaBytes": 5284924,
      "heapUsedBytes": 69090508,
      "domNodes": 145,
      "jsHeapTotalBytes": 5505024,
      "scriptDurationMs": 10.5,
      "eventListeners": 97,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    }
  ]
}

@coderabbitai

coderabbitai Bot commented Jul 31, 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: 78854216-7f1a-4d97-920a-f8b8329974fb

📥 Commits

Reviewing files that changed from the base of the PR and between b586e9e and 3491af1.

📒 Files selected for processing (4)
  • src/platform/cloud/subscription/components/CreditsTile.test.ts
  • src/platform/cloud/subscription/components/CreditsTile.vue
  • src/platform/cloud/subscription/utils/creditsProgress.test.ts
  • src/platform/cloud/subscription/utils/creditsProgress.ts

📝 Walkthrough

Walkthrough

The monthly usage utility now returns clamped remaining credits and derives used credits from that value. CreditsTile uses the computed remainder for full-width and compact displays. Tests cover allowance boundaries, existing usage scenarios, and formatted output.

Changes

Monthly credit usage

Layer / File(s) Summary
Clamped usage calculation
src/platform/cloud/subscription/utils/creditsProgress.ts, src/platform/cloud/subscription/utils/creditsProgress.test.ts
computeMonthlyUsage returns clamped remaining credits and derives used and usedFraction from it. Tests cover existing scenarios, exact allowance matches, and balances above the allowance.
CreditsTile remaining-credit display
src/platform/cloud/subscription/components/CreditsTile.vue, src/platform/cloud/subscription/components/CreditsTile.test.ts
The tile uses computed remaining credits for full-width and compact displays. The regression test verifies the STANDARD allowance is capped at 4,200 credits and uses compact formatting.

Estimated code review effort: 2 (Simple) | ~10 minutes

Mergeability Score: ⚪ Minimal · up to 3491a

This change clamps the monthly credits display to the plan allowance while preserving the full balance, with targeted coverage for the corrected behavior. No actionable merge-blocking risk remains beyond normal checks and review.

Suggested labels: cloud/1.49

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 The changed files are listed, but the PR title and commit subjects are not available; the required bug-fix signal cannot be verified. Provide the PR title and commit subjects, then verify whether the listed src/ changes include a concrete explanation for not adding a browser_tests/ regression test.
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes clamping monthly credits remaining to the plan allowance.
Description check ✅ Passed The description covers the required summary, changes, breaking status, review focus, verification, and screenshot context.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Adr Compliance For Entity/Litegraph Changes ✅ Passed The changed files are under src/platform/cloud/subscription and do not modify litegraph, ECS, or graph-entity files; the ADR check is not applicable.
✨ 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/fe-1451-clamp-monthly-remaining-credits

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@src/platform/cloud/subscription/utils/creditsProgress.ts`:
- Line 24: Replace the manual Math.min/Math.max composition in the remaining
calculation with es-toolkit/math’s clamp, passing monthlyRemaining with 0 as the
minimum and monthlyTotal as the maximum; add the required import and preserve
the existing bounded result.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1bcd5628-d3d4-4167-b1a6-56015861da0e

📥 Commits

Reviewing files that changed from the base of the PR and between e1718da and 97568ff.

📒 Files selected for processing (4)
  • src/platform/cloud/subscription/components/CreditsTile.test.ts
  • src/platform/cloud/subscription/components/CreditsTile.vue
  • src/platform/cloud/subscription/utils/creditsProgress.test.ts
  • src/platform/cloud/subscription/utils/creditsProgress.ts

Comment thread src/platform/cloud/subscription/utils/creditsProgress.ts Outdated
@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

@@           Coverage Diff           @@
##             main   #14477   +/-   ##
=======================================
  Coverage   81.95%   81.95%           
=======================================
  Files        1882     1882           
  Lines      119944   119946    +2     
  Branches    35972    35972           
=======================================
+ Hits        98303    98305    +2     
+ Misses      21175    21166    -9     
- Partials      466      475    +9     
Flag Coverage Δ
unit 72.72% <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 98.94% <100.00%> (+0.01%) ⬆️
...atform/cloud/subscription/utils/creditsProgress.ts 100.00% <100.00%> (ø)

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

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 31, 2026
@christian-byrne

christian-byrne commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Handoff: I'm off the Cloud billing pod, so @dante01yoon owns this now and I've reassigned it to him.

Context that isn't obvious from the assignee change alone: this is one of five of my open billing PRs moved to him on 2026-08-13 (#14867, #14866, #14856, #14865, #14477). They're independent of each other and none is urgent. All of them predate the flag-retirement stack merging, so rebase and re-check CI before reviewing rather than trusting the last green run.

The two that are not in that set and do need thought first: #14964 has changes requested, and #15078 is draft, conflicting, and overlaps #15094 on subscription-status fetch races. Don't revive #15078 without reading #15094 first.

The live one is #15094, a defect that shipped with the retirement stack. That takes priority over anything here.

The monthly row reconstructed remaining credits from the cents balance while
the total came from the catalog credit grant, so an untouched allowance could
render as more left than the plan grants (e.g. "4,201 left of 4,200").

computeMonthlyUsage now returns a clamped remaining whose complement is used,
so used + remaining always equals the allowance and the two labels on the row
cannot contradict each other.
All five plan rows exercised the same clamp branch and duplicated catalog
values that can drift. Keep the Standard repro plus the exact-match boundary.
Repo guidance is to use es-toolkit for utility functions; clamp expresses the
bound directly and is already the convention for this in src/composables/video.
@glary-bot
glary-bot Bot force-pushed the glary/fe-1451-clamp-monthly-remaining-credits branch from c04980f to 3491af1 Compare August 13, 2026 22:24
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@github-actions github-actions Bot added the risk:R3 PR risk grade (advisory shadow check; grader-owned) label Aug 13, 2026
@glary-bot

glary-bot Bot commented Aug 13, 2026

Copy link
Copy Markdown

@christian-byrne thanks — acted on the one item that applies to this PR: rebased onto current main and re-ran CI rather than trusting the previous green run.

Your warning was justified — this PR did break on rebase. It was 258 commits behind (base was Jul 31, main is now b586e9ec5). Git rebased without conflicts, but the build was still broken — so a conflict-free rebase would have been misleading here:

#11464 renamed isActiveSubscriptioncanAccessSubscriptionFeatures, and the tile now also reads tier from billing context separately. My test set the old state.isActiveSubscription key, which silently became a no-op — so showBreakdown was false and the entire monthly breakdown stopped rendering. It failed with expected 'Total credits4,201remaining' to contain '4,200 left of 4,200': the assertion target simply wasn't in the DOM anymore.

Fixed by aligning the test with the current harness (canAccessSubscriptionFeatures + tier), folded into the originating commit so each commit stays bisectable. The production change itself needed no adaptation — computeMonthlyUsage was untouched upstream, and tierKey still derives from subscription.tier.

Re-verified after the rebase:

  • Regression tests still genuinely fail without the fix (reverted just the two source files to origin/main, confirmed 8 failures, restored) — so they're still catching the bug rather than passing incidentally.
  • Local: subscription suite 315/315, plus typecheck, knip, lint (0 errors) and oxfmt --check clean.
  • CI on 3491af166: 54 passed, 0 failures — unit test, lint-and-format, perf-tests, storybook-build, playwright-tests (cloud), and all 16 Chromium shards. mergeable_state: clean.

CodeRabbit re-reviewed the rebased head and approved.

Noted on the rest and deliberately not touching any of it: #15094 is the priority, #14964 has changes requested, and I won't revive #15078 without #15094 being read first. This one is independent and non-urgent, so it's ready whenever @jaeone94 gets to it.

Two open judgement calls for whoever picks it up, both detailed in the PR description: monthlyBonusCredits is now an orphaned export on useSubscriptionCredits (knip is fine with it; removing it pulls in three more files), and this is a display-layer stopgap only — the underlying lossy credits↔cents round-trip affects 5 of 7 paid plans and is written up in full on FE-1451.

@jaeone94

Copy link
Copy Markdown
Collaborator

Small correction on the cc above: it predates the ownership edit in the handoff comment — @dante01yoon owns Cloud billing now, so this one is his whenever he gets to it, not mine.

@benjcooley benjcooley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verdict: COMMENT — the Standard clamp works, but the allowance used as the cap is already stale for Founders.

Severity Count
TRIVIAL 0
SHOULD FIX 1
BLOCKER 0

The regression coverage proves the reported Standard behavior in both full and compact labels. Please align the Founder allowance with the live catalog (or source the allowance authoritatively) so this fix does not underreport that plan's monthly entitlement.


const usedDisplay = computed(() => formatCreditCount(usage.value.used))
const monthlyRemainingDisplay = computed(() =>
formatCreditCount(usage.value.remaining)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

SHOULD FIX: This cap is already wrong for active Founders. The backend catalog defines founder-monthly as exactly 2,588¢ (≈5,461 credits; its contract test expects 5,461), but getTierCredits('founder') returns the stale 5,460 constant. A fresh Founder balance reconstructs as 5,463, so this now renders 5,460 left and 0 used, understating the monthly entitlement while the headline remains 5,463. Align the Founder allowance with the catalog (or source the authoritative allowance) and cover this case before using it as the cap.

@benjcooley benjcooley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved with one non-blocking SHOULD FIX.

Severity Count
TRIVIAL 0
SHOULD FIX 1
BLOCKER 0

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

Labels

risk:R3 PR risk grade (advisory shadow check; grader-owned) size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants