fix: restart timed-out billing operations - #14396
Conversation
Amp-Thread-ID: https://ampcode.com/threads/T-019fb3d7-7245-7619-bae1-b78ef49a3817 Co-authored-by: Amp <amp@ampcode.com>
📄 Knowledge reviewDosu skipped reviewing this PR because your organization has used its |
🎨 Storybook: ✅ Built — View Storybook🎭 Playwright: ✅ 1769 passed, 0 failed · 1 flaky📊 Browser Reports
📦 Bundle: 8.18 MB gzip 🔴 +57 BDetailsSummary
Category Glance App Entry Points — 3.66 kB (baseline 3.66 kB) • ⚪ 0 BMain entry bundles and manifests
Status: 1 added / 1 removed Graph Workspace — 1.29 MB (baseline 1.29 MB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed / 1 unchanged Views & Navigation — 112 kB (baseline 112 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 12 added / 12 removed / 4 unchanged Panels & Settings — 551 kB (baseline 551 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 11 added / 11 removed / 15 unchanged User & Accounts — 29.1 kB (baseline 29.1 kB) • ⚪ 0 BAuthentication, profile, and account management bundles
Status: 7 added / 7 removed / 3 unchanged Editors & Dialogs — 125 kB (baseline 125 kB) • ⚪ 0 BModals, dialogs, drawers, and in-app editors
Status: 6 added / 6 removed / 1 unchanged UI Components — 70.7 kB (baseline 70.7 kB) • ⚪ 0 BReusable component library chunks
Status: 6 added / 6 removed / 9 unchanged Data & Services — 3.43 MB (baseline 3.43 MB) • 🔴 +71 BStores, services, APIs, and repositories
Status: 14 added / 14 removed / 3 unchanged Utilities & Hooks — 386 kB (baseline 386 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 16 added / 16 removed / 20 unchanged Vendor & Third-Party — 15.7 MB (baseline 15.7 MB) • ⚪ 0 BExternal libraries and shared vendor chunks Status: 16 unchanged Other — 12.6 MB (baseline 12.6 MB) • ⚪ 0 BBundles that do not match a named category
Status: 69 added / 69 removed / 209 unchanged ⚡ Performance Report
Show regressions
All metrics
Historical variance (last 15 runs)
Trend (last 15 commits on main)
Raw data{
"timestamp": "2026-07-30T17:25:07.762Z",
"gitSha": "ae2818682a511c6be2a659249bc212dd14485f3a",
"branch": "agent/fix-billing-timeout-retry",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2136.799999999994,
"styleRecalcs": 9,
"styleRecalcDurationMs": 7.003999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 571.4789999999999,
"heapDeltaBytes": 5157464,
"heapUsedBytes": 73022848,
"domNodes": 18,
"jsHeapTotalBytes": 20312064,
"scriptDurationMs": 26.102999999999998,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-idle",
"durationMs": 2017.9099999999153,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.244000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 469.32699999999994,
"heapDeltaBytes": 5217328,
"heapUsedBytes": 73178100,
"domNodes": 16,
"jsHeapTotalBytes": 20049920,
"scriptDurationMs": 17.189000000000004,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 2052.180999999962,
"styleRecalcs": 81,
"styleRecalcDurationMs": 45.54600000000001,
"layouts": 12,
"layoutDurationMs": 3.9440000000000004,
"taskDurationMs": 982.035,
"heapDeltaBytes": -14601588,
"heapUsedBytes": 53364660,
"domNodes": -278,
"jsHeapTotalBytes": 21487616,
"scriptDurationMs": 121.09100000000001,
"eventListeners": -146,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1889.9020000000064,
"styleRecalcs": 75,
"styleRecalcDurationMs": 39.219,
"layouts": 12,
"layoutDurationMs": 3.673,
"taskDurationMs": 911.865,
"heapDeltaBytes": -15389232,
"heapUsedBytes": 52502204,
"domNodes": -281,
"jsHeapTotalBytes": 20963328,
"scriptDurationMs": 118.411,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1745.065000000011,
"styleRecalcs": 31,
"styleRecalcDurationMs": 15.503,
"layouts": 6,
"layoutDurationMs": 0.6399999999999999,
"taskDurationMs": 367.918,
"heapDeltaBytes": 7896280,
"heapUsedBytes": 75759164,
"domNodes": 76,
"jsHeapTotalBytes": 20836352,
"scriptDurationMs": 18.015000000000004,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1737.790999999902,
"styleRecalcs": 32,
"styleRecalcDurationMs": 17.403000000000002,
"layouts": 6,
"layoutDurationMs": 0.593,
"taskDurationMs": 394.622,
"heapDeltaBytes": 7932848,
"heapUsedBytes": 75699344,
"domNodes": 77,
"jsHeapTotalBytes": 20049920,
"scriptDurationMs": 21.086000000000002,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "dom-widget-clipping",
"durationMs": 578.1509999999912,
"styleRecalcs": 11,
"styleRecalcDurationMs": 8.078,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 382.14599999999996,
"heapDeltaBytes": -11951960,
"heapUsedBytes": 55818492,
"domNodes": 18,
"jsHeapTotalBytes": 22147072,
"scriptDurationMs": 57.214,
"eventListeners": 0,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666682,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "dom-widget-clipping",
"durationMs": 591.2159999999176,
"styleRecalcs": 12,
"styleRecalcDurationMs": 8.322000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 383.164,
"heapDeltaBytes": -12265516,
"heapUsedBytes": 55710816,
"domNodes": 20,
"jsHeapTotalBytes": 21884928,
"scriptDurationMs": 58.015,
"eventListeners": 0,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-idle",
"durationMs": 2035.7779999999934,
"styleRecalcs": 8,
"styleRecalcDurationMs": 6.533999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 687.127,
"heapDeltaBytes": 7769420,
"heapUsedBytes": 66639660,
"domNodes": -282,
"jsHeapTotalBytes": 4780032,
"scriptDurationMs": 100.38600000000001,
"eventListeners": -144,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2052.353000000039,
"styleRecalcs": 7,
"styleRecalcDurationMs": 7.023999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 706.185,
"heapDeltaBytes": 8476708,
"heapUsedBytes": 67352592,
"domNodes": -283,
"jsHeapTotalBytes": 4780032,
"scriptDurationMs": 108.74,
"eventListeners": -142,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2141.1959999999794,
"styleRecalcs": 68,
"styleRecalcDurationMs": 14.726000000000003,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1285.702,
"heapDeltaBytes": 2182232,
"heapUsedBytes": 61960920,
"domNodes": -284,
"jsHeapTotalBytes": 5529600,
"scriptDurationMs": 411.169,
"eventListeners": -142,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-pan",
"durationMs": 2180.894999999964,
"styleRecalcs": 69,
"styleRecalcDurationMs": 15.923000000000004,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1333.7930000000001,
"heapDeltaBytes": 5196980,
"heapUsedBytes": 65808276,
"domNodes": -285,
"jsHeapTotalBytes": 5791744,
"scriptDurationMs": 436.732,
"eventListeners": -144,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3230.3929999999923,
"styleRecalcs": 65,
"styleRecalcDurationMs": 14.895999999999999,
"layouts": 60,
"layoutDurationMs": 8.005,
"taskDurationMs": 1504.1799999999998,
"heapDeltaBytes": -591724,
"heapUsedBytes": 60813308,
"domNodes": -287,
"jsHeapTotalBytes": 8450048,
"scriptDurationMs": 533.1210000000001,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3162.5020000000177,
"styleRecalcs": 62,
"styleRecalcDurationMs": 13.734,
"layouts": 60,
"layoutDurationMs": 8.593,
"taskDurationMs": 1533.8590000000002,
"heapDeltaBytes": 23679340,
"heapUsedBytes": 85327436,
"domNodes": 6,
"jsHeapTotalBytes": 8650752,
"scriptDurationMs": 548.504,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2018.4129999999527,
"styleRecalcs": 7,
"styleRecalcDurationMs": 6.215999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 669.293,
"heapDeltaBytes": 7945668,
"heapUsedBytes": 68830320,
"domNodes": -282,
"jsHeapTotalBytes": 3469312,
"scriptDurationMs": 95.05799999999999,
"eventListeners": -144,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "minimap-idle",
"durationMs": 2037.5159999999823,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.637999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 706.2069999999999,
"heapDeltaBytes": 8284992,
"heapUsedBytes": 69219588,
"domNodes": -284,
"jsHeapTotalBytes": 3993600,
"scriptDurationMs": 107.682,
"eventListeners": -144,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 610.3560000000243,
"styleRecalcs": 47,
"styleRecalcDurationMs": 11.232000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 423.77000000000004,
"heapDeltaBytes": -12096216,
"heapUsedBytes": 55784404,
"domNodes": 20,
"jsHeapTotalBytes": 21884928,
"scriptDurationMs": 126.90299999999999,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 610.6889999999794,
"styleRecalcs": 48,
"styleRecalcDurationMs": 11.556000000000003,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 411.112,
"heapDeltaBytes": -11521340,
"heapUsedBytes": 56580740,
"domNodes": 22,
"jsHeapTotalBytes": 21884928,
"scriptDurationMs": 126.26700000000002,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2047.0659999999725,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.079999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 504.8279999999999,
"heapDeltaBytes": -22177892,
"heapUsedBytes": 45820404,
"domNodes": -279,
"jsHeapTotalBytes": 20439040,
"scriptDurationMs": 13.698,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2031.1719999999696,
"styleRecalcs": 9,
"styleRecalcDurationMs": 7.306,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 486.611,
"heapDeltaBytes": 4603192,
"heapUsedBytes": 72517724,
"domNodes": 18,
"jsHeapTotalBytes": 21098496,
"scriptDurationMs": 13.85,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1703.7970000000087,
"styleRecalcs": 76,
"styleRecalcDurationMs": 36.111,
"layouts": 16,
"layoutDurationMs": 4.557,
"taskDurationMs": 745.56,
"heapDeltaBytes": -4808980,
"heapUsedBytes": 63087196,
"domNodes": 64,
"jsHeapTotalBytes": 21360640,
"scriptDurationMs": 86.01,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1790.6490000000304,
"styleRecalcs": 77,
"styleRecalcDurationMs": 42.922999999999995,
"layouts": 16,
"layoutDurationMs": 4.883,
"taskDurationMs": 880.229,
"heapDeltaBytes": -19677636,
"heapUsedBytes": 48178816,
"domNodes": -278,
"jsHeapTotalBytes": 20439040,
"scriptDurationMs": 97.815,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "subgraph-transition-enter",
"durationMs": 1384.2109999999934,
"styleRecalcs": 19,
"styleRecalcDurationMs": 30.068000000000005,
"layouts": 15,
"layoutDurationMs": 11.720999999999998,
"taskDurationMs": 941.7959999999998,
"heapDeltaBytes": 29184612,
"heapUsedBytes": 98601244,
"domNodes": 13673,
"jsHeapTotalBytes": 16252928,
"scriptDurationMs": 43.681,
"eventListeners": 2371,
"totalBlockingTimeMs": 121,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "viewport-pan-sweep",
"durationMs": 8295.211999999992,
"styleRecalcs": 250,
"styleRecalcDurationMs": 42.198,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4392.768,
"heapDeltaBytes": 11043676,
"heapUsedBytes": 69737612,
"domNodes": -280,
"jsHeapTotalBytes": 7856128,
"scriptDurationMs": 1338.9489999999998,
"eventListeners": -128,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8333.378000000039,
"styleRecalcs": 249,
"styleRecalcDurationMs": 43.068999999999996,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4792.182,
"heapDeltaBytes": 15276892,
"heapUsedBytes": 74103360,
"domNodes": -283,
"jsHeapTotalBytes": 9428992,
"scriptDurationMs": 1491.412,
"eventListeners": -128,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 17805.812,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 17748.926,
"heapDeltaBytes": -36935060,
"heapUsedBytes": 171269076,
"domNodes": -8312,
"jsHeapTotalBytes": -9641984,
"scriptDurationMs": 592.957,
"eventListeners": -16385,
"totalBlockingTimeMs": 0,
"frameDurationMs": 18.333333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 17809.683000000063,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 17788.139000000003,
"heapDeltaBytes": -57672892,
"heapUsedBytes": 165927516,
"domNodes": -8312,
"jsHeapTotalBytes": -15671296,
"scriptDurationMs": 527.2320000000001,
"eventListeners": -16385,
"totalBlockingTimeMs": 0,
"frameDurationMs": 18.333333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-pan",
"durationMs": 22095.260999999995,
"styleRecalcs": 161,
"styleRecalcDurationMs": 23.218000000000018,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 22071.088,
"heapDeltaBytes": -49245436,
"heapUsedBytes": 179946052,
"domNodes": -8312,
"jsHeapTotalBytes": -12853248,
"scriptDurationMs": 867.2159999999999,
"eventListeners": -16381,
"totalBlockingTimeMs": 516,
"frameDurationMs": 18.333333333333332,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 21985.795999999937,
"styleRecalcs": 150,
"styleRecalcDurationMs": 21.47099999999996,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 21950.795,
"heapDeltaBytes": -49503856,
"heapUsedBytes": 177001056,
"domNodes": -8312,
"jsHeapTotalBytes": -12066816,
"scriptDurationMs": 884.4429999999999,
"eventListeners": -16383,
"totalBlockingTimeMs": 399,
"frameDurationMs": 18.886666666666617,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "workflow-execution",
"durationMs": 457.416999999964,
"styleRecalcs": 13,
"styleRecalcDurationMs": 19.102,
"layouts": 3,
"layoutDurationMs": 0.7129999999999999,
"taskDurationMs": 121.192,
"heapDeltaBytes": -15912296,
"heapUsedBytes": 51147556,
"domNodes": 130,
"jsHeapTotalBytes": 7729152,
"scriptDurationMs": 10.262,
"eventListeners": 67,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "workflow-execution",
"durationMs": 117.8620000000592,
"styleRecalcs": 8,
"styleRecalcDurationMs": 12.5,
"layouts": 2,
"layoutDurationMs": 0.6569999999999998,
"taskDurationMs": 73.037,
"heapDeltaBytes": 3021772,
"heapUsedBytes": 69905540,
"domNodes": 108,
"jsHeapTotalBytes": 3145728,
"scriptDurationMs": 5.871999999999999,
"eventListeners": 33,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666682,
"p95FrameDurationMs": 16.700000000000728
}
]
} |
📝 WalkthroughWalkthroughTimed-out billing operations are cleared before restart instead of being reused. Store and browser tests verify subscription retries recreate polling, return to ChangesBilling operation timeout restart
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant User
participant PricingDialog
participant BillingOperationStore
participant BillingAPI
User->>PricingDialog: Re-click subscribe after timeout
PricingDialog->>BillingOperationStore: Start subscription operation
BillingOperationStore->>BillingAPI: Create subscription
BillingAPI-->>BillingOperationStore: Pending operation
BillingOperationStore->>BillingAPI: Poll operation status
BillingAPI-->>BillingOperationStore: Verification-required status
BillingOperationStore-->>PricingDialog: Show Complete verification
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 inconclusive)
✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## main #14396 +/- ##
==========================================
+ Coverage 79.15% 79.31% +0.15%
==========================================
Files 1761 1761
Lines 106143 104154 -1989
Branches 35178 34684 -494
==========================================
- Hits 84015 82606 -1409
+ Misses 21664 21101 -563
+ Partials 464 447 -17
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 45 files with indirect coverage changes 🚀 New features to boost your workflow:
|
Amp-Thread-ID: https://ampcode.com/threads/T-019fb3d7-7245-7619-bae1-b78ef49a3817 Co-authored-by: Amp <amp@ampcode.com>
huang47
left a comment
There was a problem hiding this comment.
I don't see concerns in this PR, however, overall I would advocate to have a state machine to manage states and it's transitions
|
@dante01yoon Successfully backported to #14408 |
|
@dante01yoon Successfully backported to #14409 |
Backport of #14396 to `core/1.48` Automatically created by backport workflow. Co-authored-by: Dante <bunggl@naver.com> Co-authored-by: dante01yoon <6510430+dante01yoon@users.noreply.github.com> Co-authored-by: Amp <amp@ampcode.com>
CodeJuggernaut
left a comment
There was a problem hiding this comment.
Two minor E2E test issues below; the production fix looks correct.
| test('restores pending checkout when retrying a timed-out operation', async ({ | ||
| page | ||
| }) => { | ||
| const subscribeRequests: Request[] = [] |
There was a problem hiding this comment.
Severity: Minor
What: This test declares its request trackers and performs its init script, cloud setup, and route registrations inside test().
Why this is an issue: The binding browser-test guidance requires mock setup and fixture arrangement in beforeEach or fixtures, with test bodies limited to act/assert. This couples stateful setup to the scenario and violates the repository’s required test structure.
Proposed Fix: Put this scenario in a nested test.describe and move the trackers and route setup into test.beforeEach or a custom fixture.
| }) | ||
| const backButton = page.getByRole('button', { name: 'Back', exact: true }) | ||
| await cloudAppExpect(subscribeButton).toBeVisible() | ||
| await page.clock.install({ time: new Date('2026-07-30T00:00:00Z') }) |
There was a problem hiding this comment.
Severity: Minor
What: page.clock.install() runs after page.goto() and after the subscription UI renders.
Why this is an issue: Workspace boot has already used Date.now() and setTimeout() to schedule token refresh. Playwright documents this installation order as undefined behavior, so the timeout regression test has an avoidable reliability hole despite passing CI.
Proposed Fix: Move page.clock.install() immediately before page.goto(), after init scripts and route registration. Keep fastForward() where it is.
Why this is needed
A 3DS/SCA subscription can spend up to five minutes waiting for the billing operation to expose its verification action. If that discovery window timed out, retrying Subscribe opened checkout again but left the confirmation dialog idle: the pending/loading state did not return, polling did not restart, and Complete verification could not appear until the page was refreshed.
This matches the QA report in Slack.
Root cause
billingOperationStore.startOperation()deduplicated every previously-seen operation ID. After the five-minute poll timeout, the timed-out operation stayed cached. The backend intentionally replayed the same billing operation ID on checkout retry, so the store returned that cached terminal operation instead of creating a new pending operation and polling it again.Regression assessment
This is a regression in the new 3DS/SCA retry flow added by #14242. The operation-ID deduplication predates that change and remains correct for in-flight and completed operations, but the newly introduced five-minute action-discovery timeout made a terminal
timeoutoperation retryable. That state was not covered by the original browser scenarios.How this changes
timeoutoperations as restartable.Tests
AS IS
After timeout and retry, checkout remains idle with Subscribe to Creator still available. The timeout toast remains, no loading state starts, and there is no Complete verification action.
TO BE
Retrying the same backend operation ID recreates the pending operation. The CTA returns to loading, polling resumes, and the verification action appears as soon as the operation exposes its action URL.
Retry flow
Review focus
The retry boundary in
startOperation(): only timed-out operations are restarted; pending and other terminal operation deduplication is unchanged.