Skip to content

refactor(billing): drop the isActiveSubscription alias - #14867

Open
christian-byrne wants to merge 3 commits into
fix/single-source-topup-gatefrom
refactor/drop-isactivesubscription-alias
Open

refactor(billing): drop the isActiveSubscription alias#14867
christian-byrne wants to merge 3 commits into
fix/single-source-topup-gatefrom
refactor/drop-isactivesubscription-alias

Conversation

@christian-byrne

Copy link
Copy Markdown
Contributor

Stacked on #14866.

Summary

#11464 renamed isActiveSubscription to canAccessSubscriptionFeatures because off cloud the value is forced true (useSubscription.ts:48), so the old name asserts something the value does not mean. That rename is what the local-credits P0 was blamed on in review, and it landed — but it kept an alias:

// Alias kept for backward compatibility; equals canAccessSubscriptionFeatures.
const isActiveSubscription = canAccessSubscriptionFeatures

re-exported from useBillingContext and typed as @deprecated in types.ts. So both names stayed live and the misleading one remained in use across the workspace composables, settings, storybook mocks and stories. The hazard the rename existed to remove is still present, now with two names for one value.

This removes the alias and migrates every remaining reference.

Change

Pure rename. The alias was a direct assignment of the same computed, so every call site already read an identical value; there is no behavioural difference. Also removed were the duplicate object keys the collapse exposed — useBillingContext's return object, the storybook mock, and useMembersPanel.test.ts each listed both names pointing at the same source.

20 files, +69/-63.

Checks

pnpm typecheck exit 0, pnpm knip exit 0, 687 tests pass across the 32 affected suites.

@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Aug 7, 2026
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 174a939b-55c3-48c5-abc0-56397bc16d75

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

🎭 Playwright: ⏳ Running...

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 08/17/2026, 06:53:42 PM UTC

Links

📦 Bundle Size

⏳ Size data collection in progress…

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 66.3 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.2 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 69.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.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 67.0 MB heap
large-graph-pan: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.2 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 64.2 MB heap
minimap-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 71.4 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 51.5 MB heap
subgraph-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 66.6 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 57.9 MB heap
subgraph-transition-enter: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 116ms TBT · 75.6 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 77.2 MB heap
vue-large-graph-idle: · 58.1 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 161.9 MB heap
vue-large-graph-pan: · 58.1 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 24ms TBT · 164.6 MB heap
workflow-execution: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.5 MB heap

ℹ️ No baseline found — significance unavailable.

Absolute values
Metric Value
canvas-idle: avg frame time 17ms
canvas-idle: p95 frame time 17ms
canvas-idle: layout duration 0ms
canvas-idle: style recalc duration 6ms
canvas-idle: layout count 0
canvas-idle: style recalc count 10
canvas-idle: task duration 427ms
canvas-idle: script duration 6ms
canvas-idle: TBT 0ms
canvas-idle: heap used 66.3 MB
canvas-idle: DOM nodes 20
canvas-idle: event listeners 4
canvas-mouse-sweep: avg frame time 17ms
canvas-mouse-sweep: p95 frame time 17ms
canvas-mouse-sweep: layout duration 2ms
canvas-mouse-sweep: style recalc duration 25ms
canvas-mouse-sweep: layout count 12
canvas-mouse-sweep: style recalc count 72
canvas-mouse-sweep: task duration 646ms
canvas-mouse-sweep: script duration 80ms
canvas-mouse-sweep: TBT 0ms
canvas-mouse-sweep: heap used 61.2 MB
canvas-mouse-sweep: DOM nodes 56
canvas-mouse-sweep: event listeners 4
canvas-zoom-sweep: avg frame time 17ms
canvas-zoom-sweep: p95 frame time 17ms
canvas-zoom-sweep: layout duration 1ms
canvas-zoom-sweep: style recalc duration 13ms
canvas-zoom-sweep: layout count 6
canvas-zoom-sweep: style recalc count 31
canvas-zoom-sweep: task duration 320ms
canvas-zoom-sweep: script duration 8ms
canvas-zoom-sweep: TBT 0ms
canvas-zoom-sweep: heap used 69.2 MB
canvas-zoom-sweep: DOM nodes 78
canvas-zoom-sweep: event listeners 20
dom-widget-clipping: avg frame time 17ms
dom-widget-clipping: p95 frame time 17ms
dom-widget-clipping: layout duration 0ms
dom-widget-clipping: style recalc duration 7ms
dom-widget-clipping: layout count 0
dom-widget-clipping: style recalc count 13
dom-widget-clipping: task duration 309ms
dom-widget-clipping: script duration 40ms
dom-widget-clipping: TBT 0ms
dom-widget-clipping: heap used 51.0 MB
dom-widget-clipping: DOM nodes 21
dom-widget-clipping: event listeners 1
large-graph-idle: avg frame time 17ms
large-graph-idle: p95 frame time 17ms
large-graph-idle: layout duration 0ms
large-graph-idle: style recalc duration 5ms
large-graph-idle: layout count 0
large-graph-idle: style recalc count 9
large-graph-idle: task duration 535ms
large-graph-idle: script duration 10ms
large-graph-idle: TBT 0ms
large-graph-idle: heap used 67.0 MB
large-graph-idle: DOM nodes -282
large-graph-idle: event listeners -179
large-graph-pan: avg frame time 17ms
large-graph-pan: p95 frame time 17ms
large-graph-pan: layout duration 0ms
large-graph-pan: style recalc duration 10ms
large-graph-pan: layout count 0
large-graph-pan: style recalc count 69
large-graph-pan: task duration 958ms
large-graph-pan: script duration 241ms
large-graph-pan: TBT 0ms
large-graph-pan: heap used 65.2 MB
large-graph-pan: DOM nodes -283
large-graph-pan: event listeners -148
large-graph-zoom: avg frame time 17ms
large-graph-zoom: p95 frame time 17ms
large-graph-zoom: layout duration 7ms
large-graph-zoom: style recalc duration 12ms
large-graph-zoom: layout count 60
large-graph-zoom: style recalc count 65
large-graph-zoom: task duration 1117ms
large-graph-zoom: script duration 287ms
large-graph-zoom: TBT 0ms
large-graph-zoom: heap used 64.2 MB
large-graph-zoom: DOM nodes -138
large-graph-zoom: event listeners -73
minimap-idle: avg frame time 17ms
minimap-idle: p95 frame time 17ms
minimap-idle: layout duration 0ms
minimap-idle: style recalc duration 5ms
minimap-idle: layout count 0
minimap-idle: style recalc count 9
minimap-idle: task duration 538ms
minimap-idle: script duration 12ms
minimap-idle: TBT 0ms
minimap-idle: heap used 71.4 MB
minimap-idle: DOM nodes -283
minimap-idle: event listeners -149
subgraph-dom-widget-clipping: avg frame time 17ms
subgraph-dom-widget-clipping: p95 frame time 17ms
subgraph-dom-widget-clipping: layout duration 0ms
subgraph-dom-widget-clipping: style recalc duration 8ms
subgraph-dom-widget-clipping: layout count 0
subgraph-dom-widget-clipping: style recalc count 48
subgraph-dom-widget-clipping: task duration 324ms
subgraph-dom-widget-clipping: script duration 91ms
subgraph-dom-widget-clipping: TBT 0ms
subgraph-dom-widget-clipping: heap used 51.5 MB
subgraph-dom-widget-clipping: DOM nodes 22
subgraph-dom-widget-clipping: event listeners 7
subgraph-idle: avg frame time 17ms
subgraph-idle: p95 frame time 17ms
subgraph-idle: layout duration 0ms
subgraph-idle: style recalc duration 7ms
subgraph-idle: layout count 0
subgraph-idle: style recalc count 11
subgraph-idle: task duration 403ms
subgraph-idle: script duration 6ms
subgraph-idle: TBT 0ms
subgraph-idle: heap used 66.6 MB
subgraph-idle: DOM nodes 21
subgraph-idle: event listeners 6
subgraph-mouse-sweep: avg frame time 17ms
subgraph-mouse-sweep: p95 frame time 17ms
subgraph-mouse-sweep: layout duration 4ms
subgraph-mouse-sweep: style recalc duration 29ms
subgraph-mouse-sweep: layout count 16
subgraph-mouse-sweep: style recalc count 76
subgraph-mouse-sweep: task duration 625ms
subgraph-mouse-sweep: script duration 59ms
subgraph-mouse-sweep: TBT 0ms
subgraph-mouse-sweep: heap used 57.9 MB
subgraph-mouse-sweep: DOM nodes 62
subgraph-mouse-sweep: event listeners 5
subgraph-transition-enter: avg frame time 17ms
subgraph-transition-enter: p95 frame time 17ms
subgraph-transition-enter: layout duration 9ms
subgraph-transition-enter: style recalc duration 25ms
subgraph-transition-enter: layout count 15
subgraph-transition-enter: style recalc count 20
subgraph-transition-enter: task duration 740ms
subgraph-transition-enter: script duration 12ms
subgraph-transition-enter: TBT 116ms
subgraph-transition-enter: heap used 75.6 MB
subgraph-transition-enter: DOM nodes 13673
subgraph-transition-enter: event listeners 2373
viewport-pan-sweep: avg frame time 17ms
viewport-pan-sweep: p95 frame time 17ms
viewport-pan-sweep: layout duration 0ms
viewport-pan-sweep: style recalc duration 28ms
viewport-pan-sweep: layout count 0
viewport-pan-sweep: style recalc count 250
viewport-pan-sweep: task duration 3392ms
viewport-pan-sweep: script duration 770ms
viewport-pan-sweep: TBT 0ms
viewport-pan-sweep: heap used 77.2 MB
viewport-pan-sweep: DOM nodes -282
viewport-pan-sweep: event listeners -148
vue-large-graph-idle: avg frame time 17ms
vue-large-graph-idle: p95 frame time 17ms
vue-large-graph-idle: layout duration 0ms
vue-large-graph-idle: style recalc duration 0ms
vue-large-graph-idle: layout count 0
vue-large-graph-idle: style recalc count 0
vue-large-graph-idle: task duration 13019ms
vue-large-graph-idle: script duration 96ms
vue-large-graph-idle: TBT 0ms
vue-large-graph-idle: heap used 161.9 MB
vue-large-graph-idle: DOM nodes -8312
vue-large-graph-idle: event listeners -16389
vue-large-graph-pan: avg frame time 17ms
vue-large-graph-pan: p95 frame time 17ms
vue-large-graph-pan: layout duration 0ms
vue-large-graph-pan: style recalc duration 17ms
vue-large-graph-pan: layout count 0
vue-large-graph-pan: style recalc count 127
vue-large-graph-pan: task duration 16178ms
vue-large-graph-pan: script duration 368ms
vue-large-graph-pan: TBT 24ms
vue-large-graph-pan: heap used 164.6 MB
vue-large-graph-pan: DOM nodes -8312
vue-large-graph-pan: event listeners -16386
workflow-execution: avg frame time 17ms
workflow-execution: p95 frame time 17ms
workflow-execution: layout duration 0ms
workflow-execution: style recalc duration 14ms
workflow-execution: layout count 3
workflow-execution: style recalc count 14
workflow-execution: task duration 83ms
workflow-execution: script duration 5ms
workflow-execution: TBT 0ms
workflow-execution: heap used 65.5 MB
workflow-execution: DOM nodes 126
workflow-execution: event listeners 98
Raw data
{
  "timestamp": "2026-08-15T01:16:40.165Z",
  "gitSha": "08e24b1edf5105ac819ed6b914052e718bedfaec",
  "branch": "refactor/drop-isactivesubscription-alias",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2024.0059999999858,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 6.662000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 457.54799999999994,
      "heapDeltaBytes": 4894212,
      "heapUsedBytes": 69588540,
      "domNodes": 20,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 6.212999999999998,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-idle",
      "durationMs": 2000.7329999999683,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 5.932999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 396.702,
      "heapDeltaBytes": 4916136,
      "heapUsedBytes": 69458648,
      "domNodes": 20,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 5.856000000000002,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1744.956000000002,
      "styleRecalcs": 72,
      "styleRecalcDurationMs": 24.598,
      "layouts": 12,
      "layoutDurationMs": 2.525,
      "taskDurationMs": 650.562,
      "heapDeltaBytes": -859432,
      "heapUsedBytes": 63724248,
      "domNodes": 56,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 84.116,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1696.8219999999974,
      "styleRecalcs": 72,
      "styleRecalcDurationMs": 25.244999999999997,
      "layouts": 12,
      "layoutDurationMs": 2.438,
      "taskDurationMs": 640.982,
      "heapDeltaBytes": -121500,
      "heapUsedBytes": 64567416,
      "domNodes": 56,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 75.824,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1729.457000000025,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 14.140000000000002,
      "layouts": 6,
      "layoutDurationMs": 0.593,
      "taskDurationMs": 330.762,
      "heapDeltaBytes": 8095752,
      "heapUsedBytes": 72626392,
      "domNodes": 78,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 8.365,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1684.2269999999644,
      "styleRecalcs": 30,
      "styleRecalcDurationMs": 11.790999999999999,
      "layouts": 6,
      "layoutDurationMs": 0.45400000000000007,
      "taskDurationMs": 308.91,
      "heapDeltaBytes": 7785264,
      "heapUsedBytes": 72444216,
      "domNodes": 78,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 7.305999999999998,
      "eventListeners": 21,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 549.0599999999972,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 8.759999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 320.45799999999997,
      "heapDeltaBytes": -11042472,
      "heapUsedBytes": 53483800,
      "domNodes": 22,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 41.341,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.663333333333338,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 517.7100000000223,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 5.15,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 296.796,
      "heapDeltaBytes": -11051448,
      "heapUsedBytes": 53459560,
      "domNodes": 20,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 39.484,
      "eventListeners": 0,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999727
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2033.1370000000106,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 5.36,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 538.481,
      "heapDeltaBytes": 9791456,
      "heapUsedBytes": 69841004,
      "domNodes": -280,
      "jsHeapTotalBytes": 2457600,
      "scriptDurationMs": 10.633999999999997,
      "eventListeners": -179,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2001.7259999999624,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 5.4689999999999985,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 531.5229999999999,
      "heapDeltaBytes": 10561324,
      "heapUsedBytes": 70680472,
      "domNodes": -284,
      "jsHeapTotalBytes": 2195456,
      "scriptDurationMs": 9.781000000000002,
      "eventListeners": -179,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2088.594999999998,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 11.119,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 987.562,
      "heapDeltaBytes": 4625192,
      "heapUsedBytes": 65607136,
      "domNodes": -284,
      "jsHeapTotalBytes": 4222976,
      "scriptDurationMs": 250.224,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2103.0060000000503,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 9.494999999999997,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 927.6709999999999,
      "heapDeltaBytes": 9796192,
      "heapUsedBytes": 71052044,
      "domNodes": -282,
      "jsHeapTotalBytes": 4485120,
      "scriptDurationMs": 232.638,
      "eventListeners": -147,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3133.0069999999637,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 12.511999999999999,
      "layouts": 60,
      "layoutDurationMs": 7.285000000000001,
      "taskDurationMs": 1188.921,
      "heapDeltaBytes": -7172020,
      "heapUsedBytes": 55539496,
      "domNodes": -287,
      "jsHeapTotalBytes": 2719744,
      "scriptDurationMs": 299.201,
      "eventListeners": -153,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3061.2559999999576,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 11.169000000000002,
      "layouts": 60,
      "layoutDurationMs": 6.142,
      "taskDurationMs": 1045.2599999999998,
      "heapDeltaBytes": 16982148,
      "heapUsedBytes": 79117104,
      "domNodes": 12,
      "jsHeapTotalBytes": 4718592,
      "scriptDurationMs": 274.441,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2022.2180000000094,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 5.121,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 533.102,
      "heapDeltaBytes": 12268992,
      "heapUsedBytes": 73712812,
      "domNodes": -284,
      "jsHeapTotalBytes": 2719744,
      "scriptDurationMs": 13.546999999999997,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2030.144000000064,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 5.431,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 543.679,
      "heapDeltaBytes": 15201824,
      "heapUsedBytes": 76068156,
      "domNodes": -282,
      "jsHeapTotalBytes": 2195456,
      "scriptDurationMs": 10.068000000000001,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 541.2469999999985,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 8.398,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 338.957,
      "heapDeltaBytes": -10502596,
      "heapUsedBytes": 54161668,
      "domNodes": 22,
      "jsHeapTotalBytes": 25952256,
      "scriptDurationMs": 95.938,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 530.0990000000638,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 8.306,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 309.99,
      "heapDeltaBytes": -10839760,
      "heapUsedBytes": 53861592,
      "domNodes": 22,
      "jsHeapTotalBytes": 25952256,
      "scriptDurationMs": 85.923,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999727
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2024.2370000000278,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 6.221000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 397.279,
      "heapDeltaBytes": 5181980,
      "heapUsedBytes": 69867980,
      "domNodes": 20,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 5.742000000000003,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2004.427000000078,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 7.127000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 409.082,
      "heapDeltaBytes": 5022032,
      "heapUsedBytes": 69702576,
      "domNodes": 22,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 5.724,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1694.1449999999918,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 28.003,
      "layouts": 16,
      "layoutDurationMs": 3.316,
      "taskDurationMs": 624.073,
      "heapDeltaBytes": -3981292,
      "heapUsedBytes": 60613552,
      "domNodes": 61,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 58.181,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1691.7300000000068,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 29.065,
      "layouts": 16,
      "layoutDurationMs": 3.7239999999999998,
      "taskDurationMs": 626.595,
      "heapDeltaBytes": -3847192,
      "heapUsedBytes": 60913900,
      "domNodes": 62,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 59.05500000000001,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-transition-enter",
      "durationMs": 933.8259999999536,
      "styleRecalcs": 20,
      "styleRecalcDurationMs": 24.860999999999994,
      "layouts": 15,
      "layoutDurationMs": 9.177,
      "taskDurationMs": 740.472,
      "heapDeltaBytes": -6036412,
      "heapUsedBytes": 79224880,
      "domNodes": 13673,
      "jsHeapTotalBytes": 10223616,
      "scriptDurationMs": 12.276999999999996,
      "eventListeners": 2373,
      "totalBlockingTimeMs": 116,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8156.911000000036,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 31.044,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 3484.752,
      "heapDeltaBytes": 15592184,
      "heapUsedBytes": 75943088,
      "domNodes": -282,
      "jsHeapTotalBytes": 2912256,
      "scriptDurationMs": 803.748,
      "eventListeners": -133,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.80000000000109
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8099.386999999979,
      "styleRecalcs": 249,
      "styleRecalcDurationMs": 25.325,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 3299.668,
      "heapDeltaBytes": 25972648,
      "heapUsedBytes": 85965268,
      "domNodes": -281,
      "jsHeapTotalBytes": 3698688,
      "scriptDurationMs": 735.4999999999999,
      "eventListeners": -163,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 14252.468999999963,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 13254.662999999999,
      "heapDeltaBytes": -25245468,
      "heapUsedBytes": 171776076,
      "domNodes": -8312,
      "jsHeapTotalBytes": -7020544,
      "scriptDurationMs": 100.897,
      "eventListeners": -16389,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.223333333333358,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 13760.359999999991,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12783.338,
      "heapDeltaBytes": -29354608,
      "heapUsedBytes": 167807296,
      "domNodes": -8312,
      "jsHeapTotalBytes": -12001280,
      "scriptDurationMs": 90.63,
      "eventListeners": -16389,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.223333333333358,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 16540.017000000036,
      "styleRecalcs": 115,
      "styleRecalcDurationMs": 15.609000000000012,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 15854.198999999999,
      "heapDeltaBytes": -48338320,
      "heapUsedBytes": 162863384,
      "domNodes": -8312,
      "jsHeapTotalBytes": -13574144,
      "scriptDurationMs": 364.399,
      "eventListeners": -16385,
      "totalBlockingTimeMs": 41,
      "frameDurationMs": 17.223333333333358,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 17177.016999999978,
      "styleRecalcs": 139,
      "styleRecalcDurationMs": 17.509999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 16502.33,
      "heapDeltaBytes": -14953108,
      "heapUsedBytes": 182378412,
      "domNodes": -8312,
      "jsHeapTotalBytes": -11964416,
      "scriptDurationMs": 370.887,
      "eventListeners": -16387,
      "totalBlockingTimeMs": 6,
      "frameDurationMs": 17.223333333333358,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "workflow-execution",
      "durationMs": 438.77300000002606,
      "styleRecalcs": 15,
      "styleRecalcDurationMs": 15.352999999999998,
      "layouts": 3,
      "layoutDurationMs": 0.6120000000000001,
      "taskDurationMs": 90.19800000000001,
      "heapDeltaBytes": 4972484,
      "heapUsedBytes": 68616520,
      "domNodes": 128,
      "jsHeapTotalBytes": 4980736,
      "scriptDurationMs": 5.877000000000001,
      "eventListeners": 97,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "workflow-execution",
      "durationMs": 432.41199999999935,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 12.028,
      "layouts": 2,
      "layoutDurationMs": 0.317,
      "taskDurationMs": 75.41400000000002,
      "heapDeltaBytes": 4934188,
      "heapUsedBytes": 68693420,
      "domNodes": 123,
      "jsHeapTotalBytes": 4980736,
      "scriptDurationMs": 4.886,
      "eventListeners": 99,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000273
    }
  ]
}

@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 50.00000% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/storybook/mocks/useBillingContext.ts 0.00% 3 Missing ⚠️
...c/platform/workspace/composables/useWorkspaceUI.ts 33.33% 2 Missing ⚠️
src/composables/billing/useBillingContext.ts 0.00% 1 Missing ⚠️
@@                      Coverage Diff                       @@
##           fix/single-source-topup-gate   #14867    +/-   ##
==============================================================
  Coverage                         81.87%   81.87%            
==============================================================
  Files                              1884     1884            
  Lines                            118178   118179     +1     
  Branches                          35705    36181   +476     
==============================================================
+ Hits                              96760    96761     +1     
- Misses                            20964    20966     +2     
+ Partials                            454      452     -2     
Flag Coverage Δ
unit 72.84% <50.00%> (+<0.01%) ⬆️

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

Files with missing lines Coverage Δ
...loud/subscription/composables/useTopUpUrlLoader.ts 96.42% <ø> (ø)
...platform/workspace/composables/useBillingBanner.ts 100.00% <100.00%> (ø)
src/platform/workspace/composables/useTeamPlan.ts 100.00% <100.00%> (ø)
...orm/workspace/composables/useWorkspaceMenuItems.ts 98.18% <100.00%> (ø)
src/composables/billing/useBillingContext.ts 88.27% <0.00%> (-0.09%) ⬇️
...c/platform/workspace/composables/useWorkspaceUI.ts 91.66% <33.33%> (-1.56%) ⬇️
src/storybook/mocks/useBillingContext.ts 0.00% <0.00%> (ø)
🚀 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.

@christian-byrne

Copy link
Copy Markdown
Contributor Author

Handoff note — moved to @Jaewon under FE-1585.

Recommendation: Hold. Pure refactor across 20 files, stacked on #14866 — squarely a FE-1585 non-goal ("broad billing refactors during incident stabilization").

Worth finishing afterwards though. #11464 renamed isActiveSubscription to canAccessSubscriptionFeatures precisely because the old name lies — off cloud it is forced unconditionally true — but it kept the old name as a back-compat alias, so it is still live in ~10 production files including inside canRunWorkflows itself. That misleading name is the same class of trap that produced the original local-credits P0.

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

@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 live head 5badea7721b1554ec9d5334b96311b78a1735cb2 against stacked base ca3f895a7ed052ae483d6fb1164990dd84b202bb.

The refactor preserves behavior: the removed alias was the same ComputedRef as canAccessSubscriptionFeatures, and every production/test/storybook consumer now reads that source directly. git grep finds no remaining isActiveSubscription references on the PR head. This does not introduce or reconstruct server state, and it adds no handwritten API response types.

Focused validation: 11 affected Vitest files, 261 tests passed; git diff --check passed. The existing unit CI job is red only because Vitest reported an unrelated EnvironmentTeardownError from TabErrors.test.ts after all 1,109 files / 15,211 tests passed. Other applicable checks, including lint, E2E, Storybook, Codecov, and security, passed.

because off cloud it is forced true, so the old name asserts something
the value does not mean. The alias was kept for compatibility, which left
both names live and the misleading one still in use across the workspace
composables, settings, storybook mocks and stories.

Pure rename: the alias was a direct assignment of the same computed, so
every call site already read the identical value.
@christian-byrne
christian-byrne force-pushed the refactor/drop-isactivesubscription-alias branch from 5badea7 to 673c158 Compare August 15, 2026 01:04
@christian-byrne

Copy link
Copy Markdown
Contributor Author

Restacked on the updated #14866 head and rebased past the flag-retirement merges. Your approval survived the force-push, but the rebase resolved three conflicts by hand, so those are worth a second look:

  • types.ts and useBillingContext.ts: main added showsSubscribeToRunPrompt next to the deprecated alias. Kept it, dropped only the alias.
  • storybook/mocks/useBillingContext.ts: showsSubscribeToRunPrompt now derives from state.value.canAccessSubscriptionFeatures instead of the removed state.value.isActiveSubscription.

The one remaining isActiveSubscription in the tree is useLegacyBilling.test.ts, which mocks useSubscription, a different composable. Out of scope here.

Full unit suite passes locally (1169 files, 16067 tests), typecheck and knip clean. The failing test check was from Aug 7 against then-main and its logs have expired; the rebase should clear it.

@github-actions github-actions Bot added the risk:R3 PR risk grade (advisory shadow check; grader-owned) label Aug 15, 2026
…to refactor/drop-isactivesubscription-alias

# Conflicts:
#	src/platform/workspace/composables/useWorkspaceMenuItems.ts
main added four cancel-plan cases that set `state.isActiveSubscription`.
This branch renames that key to `canAccessSubscriptionFeatures`, so after
the merge those four wrote a key the mock does not have: the flag stayed
true, the first disjunct short-circuited, and the payment_failed and paused
branches they exist to cover were never reached. Reverting the source
condition to the pre-merge expression now fails both `allows cancellation`
cases, which it did not before this change.
@christian-byrne

Copy link
Copy Markdown
Contributor Author

Conflict cleared. Merged the updated base rather than rebasing, so the Update branch merge from Aug 15 stays intact.

One resolution is a behavior decision worth your eye, since it landed after your approval:

useWorkspaceMenuItems.ts canCancelPlan conflicted because main broadened it while this branch only renamed the flag. Kept main's broader condition and applied the rename to it:

(canAccessSubscriptionFeatures.value ||
  ((billingStatus.value === 'payment_failed' ||
    billingStatus.value === 'paused') &&
    Boolean(subscription.value?.planSlug))) &&

That surfaced a second problem the merge would have hidden. main's four new cancel-plan cases set state.isActiveSubscription, the key this branch renames. After the merge they were writing a key the mock no longer has, so the flag stayed true, the first disjunct short-circuited, and the payment_failed / paused branches those tests exist to cover were never reached. They passed either way. Fixed in d9d6ce4, separate from the merge commit so it is reviewable on its own.

Control for that claim: with the source condition reverted to the pre-merge expression, allows cancellation while a payment_failed plan needs payment recovery and allows cancellation while an existing plan is paused both fail. Before the fix they passed against either version.

Full unit suite green: 1171 files, 16096 tests. lint, typecheck, typecheck:browser, typecheck:website, knip all clean.

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.

3 participants