[backport cloud/1.49] fix(billing): stop reporting "processing" while a payment waits on the customer - #14913
Conversation
…e customer (#14910) ## Summary The billing-operation toast is created once when the operation starts and never revised, so an operation that parks on a 3DS challenge kept announcing "Processing payment — setting up your workspace..." while it was in fact waiting on the customer. ## Changes - **What**: Drive the toast from the current `action_url`, which the generated contract defines as present exactly while a pending operation cannot proceed without the customer. The store already tracks that field and already renders a verification prompt from it — only the toast was left behind, so it contradicted the prompt beside it. The toast swaps whenever that answer changes, in either direction, so it can never outlive the action it points at. ## Reproduction Any environment in Stripe test mode: 1. New workspace, no subscription. 2. Subscribe to a monthly plan; complete checkout with the 3DS test card `4000 0027 6000 3184`. 3. The first invoice needs authentication, so the operation parks and the status endpoint returns `status: "pending"` with `action_url` set to the Stripe-hosted invoice page. 4. Observe the toast while parked. **AS IS** — "Processing payment — setting up your workspace..." with a spinner, for the whole time the operation waits on the customer, beside a "Complete verification" affordance rendered from the same `action_url`. A reload does not clear it. **TO BE** — "Verify your payment to finish setting up your workspace" with a prompt icon, for as long as `action_url` is present. The same state is reached before any payment exists, when the operation is waiting for the customer to finish checkout. ## Before / after ```mermaid flowchart TD A["Subscription operation starts"] --> B["⟳ Processing payment —<br/>setting up your workspace…"] B --> C["Poll returns action_url<br/>(bank challenge required)"] C --> D["Before: ⟳ Processing payment —<br/>setting up your workspace…"] C --> E["After: ⚠ Verify your payment to<br/>finish setting up your workspace"] D --> F["Contradicts the 'Complete<br/>verification' prompt beside it"] E --> G["Matches the 'Complete<br/>verification' prompt beside it"] E --> H["action_url clears →<br/>reverts to processing"] ``` ## Review Focus - The toast keys on the **current** `action_url`, not on the sticky `authenticationRequiredSeen` — so it cannot ask for verification after the verification action has gone. `authenticationRequiredSeen` continues to carry only polling cadence and the 23h timeout. - Swapped only when the answer changes, so a toast the customer dismissed is not resurfaced on every poll (cadence is 30s while parked). - `severity: 'warn'` only selects the icon in `GlobalToast`; this toast group renders through a custom `#message` slot, so severity carries no other behaviour here. The state is conveyed in the summary text, not by icon or colour alone. - English strings only — other locales are generated during release PRs. - Deliberately out of scope: the same stale copy appears in the subscription settings panel (`SubscriptionPanelContentWorkspace.vue`). Same fix, different surface — left for a follow-up to keep this reviewable. ## Verification - `billingOperationStore` tests: 56 passed, 4 new. Each new test fails without the store change (verified by stashing it). - `vitest run src/platform/workspace src/components/toast` — 1075 passed. - `vue-tsc --noEmit`, `oxfmt --check`, `oxlint --type-aware`, `eslint` — clean. - Reproduced end to end on a fresh workspace with the 3DS test card before and after the change. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
🎨 Storybook: ✅ Built — View Storybook🎭 Playwright: ✅ 1789 passed, 0 failed · 1 flaky📊 Browser Reports
📦 Bundle Size
⚡ Performance Report
Absolute values
Raw data{
"timestamp": "2026-08-07T21:40:30.423Z",
"gitSha": "a598b1e407c73790524543eb56ce62895372e298",
"branch": "backport-14910-to-cloud-1.49",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2054.279000000008,
"styleRecalcs": 10,
"styleRecalcDurationMs": 9.862,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 472.212,
"heapDeltaBytes": 5318428,
"heapUsedBytes": 73804112,
"domNodes": 20,
"jsHeapTotalBytes": 20299776,
"scriptDurationMs": 16.006,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "canvas-idle",
"durationMs": 2020.4420000000027,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.453999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 451.495,
"heapDeltaBytes": 5282056,
"heapUsedBytes": 73752976,
"domNodes": 20,
"jsHeapTotalBytes": 20037632,
"scriptDurationMs": 15.603000000000002,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 2021.505000000019,
"styleRecalcs": 78,
"styleRecalcDurationMs": 40.224999999999994,
"layouts": 12,
"layoutDurationMs": 3.79,
"taskDurationMs": 975.0770000000001,
"heapDeltaBytes": 323016,
"heapUsedBytes": 69071852,
"domNodes": 58,
"jsHeapTotalBytes": 21086208,
"scriptDurationMs": 131.39199999999997,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1856.6260000000057,
"styleRecalcs": 75,
"styleRecalcDurationMs": 37.102000000000004,
"layouts": 12,
"layoutDurationMs": 3.509,
"taskDurationMs": 865.162,
"heapDeltaBytes": -18006752,
"heapUsedBytes": 50609468,
"domNodes": -282,
"jsHeapTotalBytes": 20951040,
"scriptDurationMs": 124.89999999999999,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1721.2169999999674,
"styleRecalcs": 33,
"styleRecalcDurationMs": 17.146,
"layouts": 6,
"layoutDurationMs": 0.548,
"taskDurationMs": 377.653,
"heapDeltaBytes": 8035224,
"heapUsedBytes": 76611132,
"domNodes": 78,
"jsHeapTotalBytes": 20561920,
"scriptDurationMs": 19.809,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1773.800000000051,
"styleRecalcs": 31,
"styleRecalcDurationMs": 19.496,
"layouts": 6,
"layoutDurationMs": 0.738,
"taskDurationMs": 474.65799999999996,
"heapDeltaBytes": 8099308,
"heapUsedBytes": 76759372,
"domNodes": 79,
"jsHeapTotalBytes": 19775488,
"scriptDurationMs": 28.660000000000004,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "dom-widget-clipping",
"durationMs": 596.5170000000057,
"styleRecalcs": 12,
"styleRecalcDurationMs": 7.599000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 375.904,
"heapDeltaBytes": -12715244,
"heapUsedBytes": 55626124,
"domNodes": 20,
"jsHeapTotalBytes": 22134784,
"scriptDurationMs": 58.182,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "dom-widget-clipping",
"durationMs": 545.4979999999523,
"styleRecalcs": 12,
"styleRecalcDurationMs": 8.705,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 367.195,
"heapDeltaBytes": -11336580,
"heapUsedBytes": 57172364,
"domNodes": 20,
"jsHeapTotalBytes": 19775488,
"scriptDurationMs": 56.89900000000001,
"eventListeners": 0,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2009.9730000000022,
"styleRecalcs": 9,
"styleRecalcDurationMs": 7.819,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 671.814,
"heapDeltaBytes": 7474500,
"heapUsedBytes": 67343552,
"domNodes": -281,
"jsHeapTotalBytes": 5300224,
"scriptDurationMs": 102.10600000000001,
"eventListeners": -179,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-idle",
"durationMs": 2032.6410000000124,
"styleRecalcs": 8,
"styleRecalcDurationMs": 6.7299999999999995,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 650.5240000000001,
"heapDeltaBytes": 8636300,
"heapUsedBytes": 68737132,
"domNodes": -284,
"jsHeapTotalBytes": 4775936,
"scriptDurationMs": 98.978,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2126.055000000008,
"styleRecalcs": 66,
"styleRecalcDurationMs": 11.26,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1217.837,
"heapDeltaBytes": 19242588,
"heapUsedBytes": 80538920,
"domNodes": -287,
"jsHeapTotalBytes": 5525504,
"scriptDurationMs": 417.97499999999997,
"eventListeners": -177,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-pan",
"durationMs": 2171.3179999999284,
"styleRecalcs": 68,
"styleRecalcDurationMs": 13.106,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1256.214,
"heapDeltaBytes": 7887040,
"heapUsedBytes": 68779388,
"domNodes": -287,
"jsHeapTotalBytes": 5787648,
"scriptDurationMs": 418.33099999999996,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "large-graph-zoom",
"durationMs": 3229.039,
"styleRecalcs": 65,
"styleRecalcDurationMs": 14.553000000000003,
"layouts": 60,
"layoutDurationMs": 7.035,
"taskDurationMs": 1505.7450000000001,
"heapDeltaBytes": 822076,
"heapUsedBytes": 63138660,
"domNodes": -288,
"jsHeapTotalBytes": 7921664,
"scriptDurationMs": 525.856,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3260.9500000000935,
"styleRecalcs": 66,
"styleRecalcDurationMs": 14.818000000000001,
"layouts": 60,
"layoutDurationMs": 7.287,
"taskDurationMs": 1523.146,
"heapDeltaBytes": 1917528,
"heapUsedBytes": 64509152,
"domNodes": -288,
"jsHeapTotalBytes": 8183808,
"scriptDurationMs": 549.083,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "minimap-idle",
"durationMs": 2021.3039999999864,
"styleRecalcs": 8,
"styleRecalcDurationMs": 6.567,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 665.3849999999999,
"heapDeltaBytes": 7994072,
"heapUsedBytes": 69685816,
"domNodes": -283,
"jsHeapTotalBytes": 3989504,
"scriptDurationMs": 105.435,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "minimap-idle",
"durationMs": 2037.871999999993,
"styleRecalcs": 7,
"styleRecalcDurationMs": 6.615999999999997,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 662.1429999999999,
"heapDeltaBytes": 8559264,
"heapUsedBytes": 70013440,
"domNodes": -283,
"jsHeapTotalBytes": 4513792,
"scriptDurationMs": 104.518,
"eventListeners": -147,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 574.766000000011,
"styleRecalcs": 48,
"styleRecalcDurationMs": 11.219999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 397.24099999999993,
"heapDeltaBytes": -10890920,
"heapUsedBytes": 57663160,
"domNodes": 22,
"jsHeapTotalBytes": 21086208,
"scriptDurationMs": 116.16499999999999,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 584.9940000000515,
"styleRecalcs": 48,
"styleRecalcDurationMs": 10.706999999999997,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 392.324,
"heapDeltaBytes": -11368400,
"heapUsedBytes": 57285060,
"domNodes": 22,
"jsHeapTotalBytes": 21610496,
"scriptDurationMs": 115.64200000000001,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2004.6649999999886,
"styleRecalcs": 11,
"styleRecalcDurationMs": 8.857000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 439.835,
"heapDeltaBytes": 5356932,
"heapUsedBytes": 73891984,
"domNodes": 22,
"jsHeapTotalBytes": 19775488,
"scriptDurationMs": 13.368000000000002,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2007.9200000000128,
"styleRecalcs": 9,
"styleRecalcDurationMs": 7.982000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 476.354,
"heapDeltaBytes": 5185992,
"heapUsedBytes": 73959668,
"domNodes": 18,
"jsHeapTotalBytes": 20037632,
"scriptDurationMs": 17.558999999999997,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1681.8719999999985,
"styleRecalcs": 76,
"styleRecalcDurationMs": 34.815,
"layouts": 16,
"layoutDurationMs": 4.126,
"taskDurationMs": 742.341,
"heapDeltaBytes": -4026596,
"heapUsedBytes": 64686200,
"domNodes": 62,
"jsHeapTotalBytes": 20299776,
"scriptDurationMs": 88.223,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1673.3199999999897,
"styleRecalcs": 75,
"styleRecalcDurationMs": 35.643,
"layouts": 16,
"layoutDurationMs": 4.6,
"taskDurationMs": 768.7610000000001,
"heapDeltaBytes": -3808432,
"heapUsedBytes": 64702968,
"domNodes": 60,
"jsHeapTotalBytes": 20561920,
"scriptDurationMs": 93.011,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-transition-enter",
"durationMs": 1383.971000000031,
"styleRecalcs": 18,
"styleRecalcDurationMs": 30.201000000000004,
"layouts": 14,
"layoutDurationMs": 12.417000000000002,
"taskDurationMs": 893.5899999999999,
"heapDeltaBytes": 30610328,
"heapUsedBytes": 98312384,
"domNodes": 13673,
"jsHeapTotalBytes": 15990784,
"scriptDurationMs": 42.77600000000001,
"eventListeners": 2375,
"totalBlockingTimeMs": 136,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "viewport-pan-sweep",
"durationMs": 8270.98699999999,
"styleRecalcs": 249,
"styleRecalcDurationMs": 35.13,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4377.807000000001,
"heapDeltaBytes": 11836772,
"heapUsedBytes": 71923488,
"domNodes": -283,
"jsHeapTotalBytes": 7360512,
"scriptDurationMs": 1367.872,
"eventListeners": -133,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8216.510000000086,
"styleRecalcs": 249,
"styleRecalcDurationMs": 35.373000000000005,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4398.692999999999,
"heapDeltaBytes": 13858484,
"heapUsedBytes": 75388620,
"domNodes": -281,
"jsHeapTotalBytes": 7589888,
"scriptDurationMs": 1370.6490000000001,
"eventListeners": -133,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 17161.649000000012,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 17143.461000000003,
"heapDeltaBytes": -59450348,
"heapUsedBytes": 167188196,
"domNodes": -8312,
"jsHeapTotalBytes": -10952704,
"scriptDurationMs": 588.865,
"eventListeners": -16391,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.77333333333336,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 16549.85399999998,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 16533.498000000003,
"heapDeltaBytes": -35690952,
"heapUsedBytes": 177110476,
"domNodes": -8312,
"jsHeapTotalBytes": -11214848,
"scriptDurationMs": 509.82600000000014,
"eventListeners": -16387,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 20564.899000000027,
"styleRecalcs": 142,
"styleRecalcDurationMs": 19.246999999999957,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 20505.537999999997,
"heapDeltaBytes": -32781444,
"heapUsedBytes": 177307792,
"domNodes": -8312,
"jsHeapTotalBytes": -8925184,
"scriptDurationMs": 874.265,
"eventListeners": -16381,
"totalBlockingTimeMs": 174,
"frameDurationMs": 17.77333333333336,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-pan",
"durationMs": 20585.44800000004,
"styleRecalcs": 141,
"styleRecalcDurationMs": 16.645999999999994,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 20537.396999999997,
"heapDeltaBytes": -35188628,
"heapUsedBytes": 174033556,
"domNodes": -8316,
"jsHeapTotalBytes": -13643776,
"scriptDurationMs": 895.268,
"eventListeners": -16383,
"totalBlockingTimeMs": 233,
"frameDurationMs": 17.780000000000047,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "workflow-execution",
"durationMs": 130.70899999996755,
"styleRecalcs": 8,
"styleRecalcDurationMs": 17.887999999999998,
"layouts": 4,
"layoutDurationMs": 1.517,
"taskDurationMs": 111.39900000000002,
"heapDeltaBytes": -16701060,
"heapUsedBytes": 50917732,
"domNodes": 205,
"jsHeapTotalBytes": 7192576,
"scriptDurationMs": 7.519999999999999,
"eventListeners": 79,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "workflow-execution",
"durationMs": 463.7729999999465,
"styleRecalcs": 14,
"styleRecalcDurationMs": 17.770999999999997,
"layouts": 3,
"layoutDurationMs": 0.4810000000000001,
"taskDurationMs": 115.83699999999999,
"heapDeltaBytes": -15736064,
"heapUsedBytes": 51856980,
"domNodes": 123,
"jsHeapTotalBytes": 6930432,
"scriptDurationMs": 8.642000000000001,
"eventListeners": 97,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
}
]
} |
Codecov Report❌ Patch coverage is
@@ Coverage Diff @@
## cloud/1.49 #14913 +/- ##
=============================================
Coverage ? 79.03%
=============================================
Files ? 1853
Lines ? 109089
Branches ? 34370
=============================================
Hits ? 86216
Misses ? 22428
Partials ? 445
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Backport of #14910 to
cloud/1.49Automatically created by backport workflow.