Skip to content

fix(assets): give history cursor recovery epoch ownership#13780

Open
mattmillerai wants to merge 1 commit into
matt/fe-962-fe-adopt-cursor-pagination-in-the-generated-tab-jobs-sourcedfrom
matt/be-3420-history-fetch-epoch-ownership
Open

fix(assets): give history cursor recovery epoch ownership#13780
mattmillerai wants to merge 1 commit into
matt/fe-962-fe-adopt-cursor-pagination-in-the-generated-tab-jobs-sourcedfrom
matt/be-3420-history-fetch-epoch-ownership

Conversation

@mattmillerai

Copy link
Copy Markdown
Contributor

ELI-5

When the history list hits a stale pagination cursor, it throws the list away and starts over from the top. But it forgot to tell everyone else "I just reset — ignore what you were doing." So if a background "check for new items" refresh was mid-flight, it could wake up and scribble on the freshly-cleared list, or trigger a needless full reload. This teaches the recovery path to raise the shared "generation counter" so those concurrent readers correctly bail — while making sure the recovery's own follow-up fetch isn't fooled into discarding its own result.

Summary

Stacked on #12769 (base branch), addressing a review follow-up deferred from it.

The cursor-recovery path (fetchHistoryPageWithCursorRecovery) cleared allHistoryItems/loadedIds/loadedJobIds/historyOffset/historyNextCursor/historyCursorMode without incrementing historyFetchEpoch. Every other reset site (fetchHistoryAssets(false), replaceHistoryWithHeadPage) bumps the epoch, so a concurrent reader that captured the same epoch — notably an in-flight doRefreshHistoryHead, which fetches offset:0 directly and guards on the epoch — could pass its stale-check and act against the just-cleared list.

The clean fix couldn't be a one-liner: bumping the epoch inside recovery also trips loadMoreHistory's own stale-guard (suppressing a legitimate error) and fetchHistoryAssets's discard check (dropping the recovered page). A single counter can't tell self-recovery apart from external supersession without threading the post-recovery epoch back up.

Approach

Recovery now takes ownership of the walk: it bumps historyFetchEpoch and records the new value on a small mutable HistoryWalk holder threaded from loadMoreHistoryfetchHistoryAssets → the recovery fetcher. The caller and loadMoreHistory re-sync to that holder, so they honor their own self-recovery instead of misreading it as an external supersession. The bump + re-stamp happen before the fallback offset:0 fetch (synchronously, no await between), so even if that retry throws, the holder reflects the new epoch and the error still surfaces with the walk resumable from offset 0.

Preserved invariants (all covered by the existing concurrency suite):

  • (a) resumable-after-double-failure: reset before fallback fetch, error still surfaces (isLoadingMore released, next scroll not dropped).
  • (b) no discard of the recovered page.
  • (c) doRefreshHistoryHead now correctly bails when recovery reset the list mid-flight.

Tests

  • New: discards a concurrent head refresh when cursor recovery resets the walk mid-flight — the core regression (fails without the epoch bump: the un-guarded head refresh fires a spurious full reload).
  • New: releases isLoadingMore when the offset-0 recovery retry also fails, so the next scroll is not dropped.
  • Full assetsStore.test.ts suite green (100 tests), including the ~15 cursor/epoch concurrency cases.

Verification

  • vitest run src/stores/assetsStore.test.ts → 100 passed
  • eslint + oxfmt --check clean on both changed files
  • Confirmed the new concurrency test fails when the epoch bump is reverted (5 fetch calls vs the expected 4), proving it guards the regression.

Cursor recovery cleared the history walk state without bumping historyFetchEpoch, so a concurrent reader that captured the same epoch (notably an in-flight head refresh fetching offset:0) could pass its stale-guard and act on the just-cleared list.

Recovery now bumps the epoch and threads the new value through a mutable walk holder so its caller and loadMoreHistory re-sync to the self-recovery epoch instead of misreading their own reset as external supersession. The reset still runs before the fallback fetch, so a failed offset-0 retry leaves the walk resumable and surfaces the error.
@mattmillerai mattmillerai added agent-coded Opened by the agent-work code loop cursor-review Trigger multi-model Cursor agent review on this PR labels Jul 18, 2026
@coderabbitai

coderabbitai Bot commented Jul 18, 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: 1011a84f-4766-4101-8709-e38a6fc8b6a6

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch matt/be-3420-history-fetch-epoch-ownership

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

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 07/18/2026, 01:28:04 AM UTC

Links

🎭 Playwright: ✅ 1687 passed, 0 failed · 3 flaky

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

📦 Bundle Size

⏳ Size data collection in progress…

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.7 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 54.0 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 57.7 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 47.0 MB heap
large-graph-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 57.5 MB heap
large-graph-pan: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 79.0 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 63.4 MB heap
minimap-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 57.7 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.1 MB heap
subgraph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 49.2 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 54.6 MB heap
subgraph-transition-enter: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 126ms TBT · 97.1 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 67.5 MB heap
vue-large-graph-idle: · 59.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 162.4 MB heap
vue-large-graph-pan: · 58.1 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 157.9 MB heap
workflow-execution: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 46.3 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 8
canvas-idle: task duration 354ms
canvas-idle: script duration 14ms
canvas-idle: TBT 0ms
canvas-idle: heap used 61.7 MB
canvas-idle: DOM nodes -273
canvas-idle: event listeners -197
canvas-mouse-sweep: avg frame time 17ms
canvas-mouse-sweep: p95 frame time 17ms
canvas-mouse-sweep: layout duration 3ms
canvas-mouse-sweep: style recalc duration 33ms
canvas-mouse-sweep: layout count 12
canvas-mouse-sweep: style recalc count 73
canvas-mouse-sweep: task duration 699ms
canvas-mouse-sweep: script duration 89ms
canvas-mouse-sweep: TBT 0ms
canvas-mouse-sweep: heap used 54.0 MB
canvas-mouse-sweep: DOM nodes -242
canvas-mouse-sweep: event listeners -198
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 300ms
canvas-zoom-sweep: script duration 15ms
canvas-zoom-sweep: TBT 0ms
canvas-zoom-sweep: heap used 57.7 MB
canvas-zoom-sweep: DOM nodes -231
canvas-zoom-sweep: event listeners -183
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 6ms
dom-widget-clipping: layout count 0
dom-widget-clipping: style recalc count 13
dom-widget-clipping: task duration 299ms
dom-widget-clipping: script duration 41ms
dom-widget-clipping: TBT 0ms
dom-widget-clipping: heap used 47.0 MB
dom-widget-clipping: DOM nodes -126
dom-widget-clipping: event listeners -100
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 7ms
large-graph-idle: layout count 0
large-graph-idle: style recalc count 11
large-graph-idle: task duration 460ms
large-graph-idle: script duration 64ms
large-graph-idle: TBT 0ms
large-graph-idle: heap used 57.5 MB
large-graph-idle: DOM nodes -120
large-graph-idle: event listeners -98
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 14ms
large-graph-pan: layout count 0
large-graph-pan: style recalc count 69
large-graph-pan: task duration 831ms
large-graph-pan: script duration 279ms
large-graph-pan: TBT 0ms
large-graph-pan: heap used 79.0 MB
large-graph-pan: DOM nodes 18
large-graph-pan: event listeners 5
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 15ms
large-graph-zoom: layout count 60
large-graph-zoom: style recalc count 64
large-graph-zoom: task duration 1014ms
large-graph-zoom: script duration 356ms
large-graph-zoom: TBT 0ms
large-graph-zoom: heap used 63.4 MB
large-graph-zoom: DOM nodes 11
large-graph-zoom: event listeners 8
minimap-idle: avg frame time 17ms
minimap-idle: p95 frame time 17ms
minimap-idle: layout duration 0ms
minimap-idle: style recalc duration 6ms
minimap-idle: layout count 0
minimap-idle: style recalc count 9
minimap-idle: task duration 434ms
minimap-idle: script duration 63ms
minimap-idle: TBT 0ms
minimap-idle: heap used 57.7 MB
minimap-idle: DOM nodes -264
minimap-idle: event listeners -199
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 49
subgraph-dom-widget-clipping: task duration 275ms
subgraph-dom-widget-clipping: script duration 85ms
subgraph-dom-widget-clipping: TBT 0ms
subgraph-dom-widget-clipping: heap used 61.1 MB
subgraph-dom-widget-clipping: DOM nodes 23
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 6ms
subgraph-idle: layout count 0
subgraph-idle: style recalc count 11
subgraph-idle: task duration 359ms
subgraph-idle: script duration 12ms
subgraph-idle: TBT 0ms
subgraph-idle: heap used 49.2 MB
subgraph-idle: DOM nodes -288
subgraph-idle: event listeners -197
subgraph-mouse-sweep: avg frame time 17ms
subgraph-mouse-sweep: p95 frame time 17ms
subgraph-mouse-sweep: layout duration 3ms
subgraph-mouse-sweep: style recalc duration 28ms
subgraph-mouse-sweep: layout count 16
subgraph-mouse-sweep: style recalc count 78
subgraph-mouse-sweep: task duration 547ms
subgraph-mouse-sweep: script duration 63ms
subgraph-mouse-sweep: TBT 0ms
subgraph-mouse-sweep: heap used 54.6 MB
subgraph-mouse-sweep: DOM nodes -83
subgraph-mouse-sweep: event listeners -96
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 21ms
subgraph-transition-enter: layout count 5
subgraph-transition-enter: style recalc count 18
subgraph-transition-enter: task duration 583ms
subgraph-transition-enter: script duration 19ms
subgraph-transition-enter: TBT 126ms
subgraph-transition-enter: heap used 97.1 MB
subgraph-transition-enter: DOM nodes 13833
subgraph-transition-enter: event listeners 2531
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 46ms
viewport-pan-sweep: layout count 0
viewport-pan-sweep: style recalc count 251
viewport-pan-sweep: task duration 2993ms
viewport-pan-sweep: script duration 940ms
viewport-pan-sweep: TBT 0ms
viewport-pan-sweep: heap used 67.5 MB
viewport-pan-sweep: DOM nodes -120
viewport-pan-sweep: event listeners -82
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 8419ms
vue-large-graph-idle: script duration 431ms
vue-large-graph-idle: TBT 0ms
vue-large-graph-idle: heap used 162.4 MB
vue-large-graph-idle: DOM nodes -3300
vue-large-graph-idle: event listeners -16369
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 18ms
vue-large-graph-pan: layout count 0
vue-large-graph-pan: style recalc count 64
vue-large-graph-pan: task duration 10084ms
vue-large-graph-pan: script duration 684ms
vue-large-graph-pan: TBT 0ms
vue-large-graph-pan: heap used 157.9 MB
vue-large-graph-pan: DOM nodes -3296
vue-large-graph-pan: event listeners -16365
workflow-execution: avg frame time 17ms
workflow-execution: p95 frame time 17ms
workflow-execution: layout duration 1ms
workflow-execution: style recalc duration 21ms
workflow-execution: layout count 4
workflow-execution: style recalc count 19
workflow-execution: task duration 185ms
workflow-execution: script duration 16ms
workflow-execution: TBT 0ms
workflow-execution: heap used 46.3 MB
workflow-execution: DOM nodes -167
workflow-execution: event listeners -132
Raw data
{
  "timestamp": "2026-07-18T01:37:01.607Z",
  "gitSha": "0dcc1da7df9c279b8355daf8cb4b12dfbd061dca",
  "branch": "matt/be-3420-history-fetch-epoch-ownership",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2014.675000000011,
      "styleRecalcs": 6,
      "styleRecalcDurationMs": 4.675000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 351.651,
      "heapDeltaBytes": 13220832,
      "heapUsedBytes": 65108576,
      "domNodes": -277,
      "jsHeapTotalBytes": 15593472,
      "scriptDurationMs": 14.071,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-idle",
      "durationMs": 2047.2479999999678,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 7.023999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 355.547,
      "heapDeltaBytes": 12047788,
      "heapUsedBytes": 64254872,
      "domNodes": -269,
      "jsHeapTotalBytes": 16904192,
      "scriptDurationMs": 13.113,
      "eventListeners": -195,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1809.5619999999712,
      "styleRecalcs": 73,
      "styleRecalcDurationMs": 38.458,
      "layouts": 12,
      "layoutDurationMs": 2.951,
      "taskDurationMs": 786.841,
      "heapDeltaBytes": -13022024,
      "heapUsedBytes": 56389064,
      "domNodes": -242,
      "jsHeapTotalBytes": 19034112,
      "scriptDurationMs": 97.085,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1716.0020000000031,
      "styleRecalcs": 72,
      "styleRecalcDurationMs": 27.372999999999994,
      "layouts": 12,
      "layoutDurationMs": 2.796,
      "taskDurationMs": 611.6199999999999,
      "heapDeltaBytes": -12590828,
      "heapUsedBytes": 56798556,
      "domNodes": -242,
      "jsHeapTotalBytes": 19034112,
      "scriptDurationMs": 80.751,
      "eventListeners": -197,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1728.1570000000102,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 12.217,
      "layouts": 6,
      "layoutDurationMs": 0.616,
      "taskDurationMs": 291.565,
      "heapDeltaBytes": 2890272,
      "heapUsedBytes": 55160548,
      "domNodes": -239,
      "jsHeapTotalBytes": 5632000,
      "scriptDurationMs": 14.806000000000001,
      "eventListeners": -184,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1754.0520000000015,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 14.044999999999998,
      "layouts": 6,
      "layoutDurationMs": 0.5499999999999999,
      "taskDurationMs": 308.22700000000003,
      "heapDeltaBytes": -3619108,
      "heapUsedBytes": 65774376,
      "domNodes": -223,
      "jsHeapTotalBytes": 12480512,
      "scriptDurationMs": 15.283000000000001,
      "eventListeners": -182,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 460.4529999999727,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 6.550000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 285.379,
      "heapDeltaBytes": -12867668,
      "heapUsedBytes": 53105364,
      "domNodes": 22,
      "jsHeapTotalBytes": 20480000,
      "scriptDurationMs": 41.871,
      "eventListeners": 0,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 468.8780000000179,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 6.037000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 312.054,
      "heapDeltaBytes": -24062392,
      "heapUsedBytes": 45462240,
      "domNodes": -274,
      "jsHeapTotalBytes": 6189056,
      "scriptDurationMs": 39.549,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.663333333333338,
      "p95FrameDurationMs": 16.799999999999727
    },
    {
      "name": "large-graph-idle",
      "durationMs": 1997.032000000047,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 6.879,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 435.66800000000006,
      "heapDeltaBytes": -10459996,
      "heapUsedBytes": 61271272,
      "domNodes": 20,
      "jsHeapTotalBytes": 10366976,
      "scriptDurationMs": 62.102999999999994,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2020.6469999999968,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 6.7139999999999995,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 483.59700000000004,
      "heapDeltaBytes": -24800392,
      "heapUsedBytes": 59241212,
      "domNodes": -260,
      "jsHeapTotalBytes": 2445312,
      "scriptDurationMs": 66.61,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2076.104999999984,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 14.973,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 853.907,
      "heapDeltaBytes": 9772436,
      "heapUsedBytes": 82623012,
      "domNodes": 18,
      "jsHeapTotalBytes": 12640256,
      "scriptDurationMs": 288.311,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2045.7179999999653,
      "styleRecalcs": 68,
      "styleRecalcDurationMs": 12.988999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 807.927,
      "heapDeltaBytes": 8456288,
      "heapUsedBytes": 83145796,
      "domNodes": 18,
      "jsHeapTotalBytes": 10280960,
      "scriptDurationMs": 270.117,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3037.9409999999893,
      "styleRecalcs": 63,
      "styleRecalcDurationMs": 15.466999999999999,
      "layouts": 60,
      "layoutDurationMs": 7.010000000000001,
      "taskDurationMs": 1033.266,
      "heapDeltaBytes": 11729648,
      "heapUsedBytes": 66586872,
      "domNodes": 8,
      "jsHeapTotalBytes": 1835008,
      "scriptDurationMs": 364.874,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3045.363000000009,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 15.034,
      "layouts": 60,
      "layoutDurationMs": 6.111,
      "taskDurationMs": 995.1460000000001,
      "heapDeltaBytes": 11295180,
      "heapUsedBytes": 66375156,
      "domNodes": 14,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 346.175,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2019.7489999999902,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 5.619000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 445.893,
      "heapDeltaBytes": -25982012,
      "heapUsedBytes": 60276352,
      "domNodes": -263,
      "jsHeapTotalBytes": 1396736,
      "scriptDurationMs": 63.351000000000006,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2008.2109999999602,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 5.623999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 422.26900000000006,
      "heapDeltaBytes": 7572628,
      "heapUsedBytes": 60686904,
      "domNodes": -264,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 62.556,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 459.8530000000096,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 7.969,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 271.284,
      "heapDeltaBytes": 8078372,
      "heapUsedBytes": 66931572,
      "domNodes": 22,
      "jsHeapTotalBytes": 17825792,
      "scriptDurationMs": 84.099,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 442.6369999999906,
      "styleRecalcs": 49,
      "styleRecalcDurationMs": 8.513,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 279.298,
      "heapDeltaBytes": 6594952,
      "heapUsedBytes": 61282028,
      "domNodes": 24,
      "jsHeapTotalBytes": 13107200,
      "scriptDurationMs": 86.13299999999998,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2037.6739999999813,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 6.593,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 360.653,
      "heapDeltaBytes": -1234308,
      "heapUsedBytes": 51008812,
      "domNodes": -287,
      "jsHeapTotalBytes": 16904192,
      "scriptDurationMs": 12.285,
      "eventListeners": -197,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2014.806999999962,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 5.819999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 357.84499999999997,
      "heapDeltaBytes": -61264,
      "heapUsedBytes": 52196848,
      "domNodes": -288,
      "jsHeapTotalBytes": 18214912,
      "scriptDurationMs": 11.897000000000002,
      "eventListeners": -197,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1754.0250000000128,
      "styleRecalcs": 78,
      "styleRecalcDurationMs": 31.124000000000002,
      "layouts": 16,
      "layoutDurationMs": 3.585,
      "taskDurationMs": 588.479,
      "heapDeltaBytes": -16504700,
      "heapUsedBytes": 52897860,
      "domNodes": -230,
      "jsHeapTotalBytes": 20344832,
      "scriptDurationMs": 63.775999999999996,
      "eventListeners": -195,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1674.133999999981,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 25.686,
      "layouts": 16,
      "layoutDurationMs": 2.8459999999999996,
      "taskDurationMs": 504.70900000000006,
      "heapDeltaBytes": 11267976,
      "heapUsedBytes": 61508056,
      "domNodes": 65,
      "jsHeapTotalBytes": 19136512,
      "scriptDurationMs": 61.794000000000004,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-transition-enter",
      "durationMs": 832.0999999999685,
      "styleRecalcs": 18,
      "styleRecalcDurationMs": 21.188,
      "layouts": 5,
      "layoutDurationMs": 8.747000000000002,
      "taskDurationMs": 582.56,
      "heapDeltaBytes": 29907224,
      "heapUsedBytes": 101858612,
      "domNodes": 13833,
      "jsHeapTotalBytes": 16515072,
      "scriptDurationMs": 19.354999999999997,
      "eventListeners": 2531,
      "totalBlockingTimeMs": 126,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8070.194999999956,
      "styleRecalcs": 251,
      "styleRecalcDurationMs": 47.29699999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 2943.3759999999997,
      "heapDeltaBytes": 15148544,
      "heapUsedBytes": 68200104,
      "domNodes": -260,
      "jsHeapTotalBytes": 5447680,
      "scriptDurationMs": 912.004,
      "eventListeners": -183,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333338,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8093.021000000022,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 44.752,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 3043.165,
      "heapDeltaBytes": 1251208,
      "heapUsedBytes": 73345824,
      "domNodes": 20,
      "jsHeapTotalBytes": 18931712,
      "scriptDurationMs": 968.117,
      "eventListeners": 20,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333338,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 8494.784000000038,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 8469.601,
      "heapDeltaBytes": -30463164,
      "heapUsedBytes": 169925436,
      "domNodes": -3300,
      "jsHeapTotalBytes": 17825792,
      "scriptDurationMs": 433.631,
      "eventListeners": -16369,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.80000000000109
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 8390.650999999934,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 8369.305,
      "heapDeltaBytes": -28626596,
      "heapUsedBytes": 170751540,
      "domNodes": -3300,
      "jsHeapTotalBytes": 9961472,
      "scriptDurationMs": 428.73,
      "eventListeners": -16368,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.216666666666665,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 9915.200000000026,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 18.122,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 9873.958999999999,
      "heapDeltaBytes": -30253312,
      "heapUsedBytes": 159293848,
      "domNodes": -3291,
      "jsHeapTotalBytes": 20447232,
      "scriptDurationMs": 667.888,
      "eventListeners": -16364,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 10312.904000000002,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 18.05799999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 10294.529,
      "heapDeltaBytes": -23327252,
      "heapUsedBytes": 171864952,
      "domNodes": -3300,
      "jsHeapTotalBytes": 14680064,
      "scriptDurationMs": 699.813,
      "eventListeners": -16366,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333338,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "workflow-execution",
      "durationMs": 468.4869999999819,
      "styleRecalcs": 20,
      "styleRecalcDurationMs": 23.134,
      "layouts": 4,
      "layoutDurationMs": 1.0949999999999998,
      "taskDurationMs": 187.54199999999997,
      "heapDeltaBytes": -21903588,
      "heapUsedBytes": 48672644,
      "domNodes": -163,
      "jsHeapTotalBytes": 5664768,
      "scriptDurationMs": 14.738,
      "eventListeners": -130,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999727
    },
    {
      "name": "workflow-execution",
      "durationMs": 454.0399999999636,
      "styleRecalcs": 18,
      "styleRecalcDurationMs": 19.334,
      "layouts": 4,
      "layoutDurationMs": 0.9160000000000001,
      "taskDurationMs": 182.72899999999998,
      "heapDeltaBytes": -22150704,
      "heapUsedBytes": 48452772,
      "domNodes": -170,
      "jsHeapTotalBytes": 4878336,
      "scriptDurationMs": 17.182999999999996,
      "eventListeners": -134,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.700000000000728
    }
  ]
}

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 Cursor Review — Consolidated panel

Triggered by @mattmillerai.

✅ No high-signal findings.

Panel: 6/8 reviewers contributed findings.

Reviewers that did not contribute: kimi-k2.5:adversarial (empty), kimi-k2.5:edge-case (empty)

@mattmillerai
mattmillerai marked this pull request as ready for review July 18, 2026 01:36
@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Jul 18, 2026
@codecov

codecov Bot commented Jul 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

@@                                             Coverage Diff                                              @@
##           matt/fe-962-fe-adopt-cursor-pagination-in-the-generated-tab-jobs-sourced   #13780      +/-   ##
============================================================================================================
- Coverage                                                                     76.26%   75.80%   -0.47%     
============================================================================================================
  Files                                                                          1687     1637      -50     
  Lines                                                                        116777   110480    -6297     
  Branches                                                                      37481    36522     -959     
============================================================================================================
- Hits                                                                          89063    83747    -5316     
+ Misses                                                                        26969    25852    -1117     
- Partials                                                                        745      881     +136     
Flag Coverage Δ
unit 65.42% <100.00%> (-1.87%) ⬇️

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

Files with missing lines Coverage Δ
src/stores/assetsStore.ts 70.35% <100.00%> (+0.19%) ⬆️

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

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

Labels

agent-coded Opened by the agent-work code loop cursor-review Trigger multi-model Cursor agent review on this PR size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant