Skip to content

ci: cloud gate runs on a change-gated 3-hour timer, not per commit - #15163

Open
benjcooley wants to merge 1 commit into
nathaniel/custom-node-e2e-suitefrom
benjcooley/cloud-gate-cron
Open

ci: cloud gate runs on a change-gated 3-hour timer, not per commit#15163
benjcooley wants to merge 1 commit into
nathaniel/custom-node-e2e-suitefrom
benjcooley/cloud-gate-cron

Conversation

@benjcooley

Copy link
Copy Markdown
Contributor

Converts the cloud gate from per-push to timer-driven, as decided:

  • schedule: '23 */3 * * *' replaces the push/merge_group triggers. 3 hours sits above the longest observed run (75-160m), so a tick never overlaps its predecessor in the single-slot serial concurrency group - the eviction failure mode (16 of 40 runs cancelled in the per-PR era) cannot recur from the timer.
  • A freshness job change-gates each tick: skips when HEAD has not moved since the last completed run on the ref, or when the delta touches only docs/apps/storybook/markdown (same relevance classes as changes-filter). Quiet days cost zero cloud runs; busy days cost at most 8.
  • workflow_dispatch always runs (freshness passes non-schedule events through).
  • Fork-safety note: with no pull_request trigger every event is same-repo by construction; the old PR-specific guard clause is replaced by the freshness condition.

Scheduled workflows execute only from the default branch, so the timer activates exactly when the suite lands on main - until then, dispatch remains the way to run it (unchanged).

  • js-yaml validates; no test-side changes.

Per-push triggers evicted each other from the single serial concurrency
slot (16 of 40 runs cancelled in the per-PR era; the same eviction
returned with per-merge pushes) and burned the one smoke-account queue on
docs-only merges. The cron ticks every 3 hours - above the longest
observed run so a tick never overlaps its predecessor - and a freshness
job skips ticks where HEAD has not moved since the last completed run or
the delta is only docs/apps/storybook/markdown. Dispatch always runs.
Scheduled workflows execute only from the default branch, so the timer
activates when the suite lands on main.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dosubot dosubot Bot added the size:XS This PR changes 0-9 lines, ignoring generated files. label Aug 12, 2026
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The cloud custom-node workflow now runs on a three-hour schedule or manual dispatch. Scheduled runs use a freshness check to skip commits without relevant source changes. The cloud E2E job requires both change detection and freshness approval.

Changes

Cloud E2E scheduling

Layer / File(s) Summary
Scheduled workflow triggers
.github/workflows/ci-tests-custom-nodes-cloud.yaml
The workflow now uses a three-hour schedule and manual dispatches instead of push and merge-group triggers.
Freshness gate and job wiring
.github/workflows/ci-tests-custom-nodes-cloud.yaml
Scheduled runs compare the latest completed run with the current commit and relevant file changes. The cloud E2E job requires both changes and freshness.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Mergeability Score: 🟡 Moderate · up to 208c4

The workflow may skip the cloud gate for relevant source changes, and failed or cancelled runs may prevent automatic retries. These behaviors can leave required validation undone, so the PR is not merge-ready until they are corrected or explicitly accepted.

Possibly related PRs

Suggested reviewers: codejuggernaut


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
End-To-End Regression Coverage For Fixes ❓ Inconclusive The review context does not provide the PR title or individual commit subjects, so the required bug-fix signal cannot be verified. Provide the PR title and commit subjects, then re-evaluate the explicit failure conditions.
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change from per-commit execution to a change-gated three-hour schedule.
Description check ✅ Passed The description is detailed, on-topic, and explains the workflow changes, rationale, behavior, and validation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Adr Compliance For Entity/Litegraph Changes ✅ Passed The changed-file list contains only .github/workflows/ci-tests-custom-nodes-cloud.yaml, so no litegraph, ECS, or graph-entity files are modified.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch benjcooley/cloud-gate-cron

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.

❤️ Share

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

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

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

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

📦 Bundle Size

⏳ Size data collection in progress…

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 67.0 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 47.9 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 69.7 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 50.8 MB heap
large-graph-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 62.1 MB heap
large-graph-pan: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 57.0 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 81.8 MB heap
minimap-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 64.2 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 51.1 MB heap
subgraph-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 44.7 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 51.0 MB heap
subgraph-transition-enter: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 153ms TBT · 71.0 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 68.4 MB heap
vue-large-graph-idle: · 56.3 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 158.4 MB heap
vue-large-graph-pan: · 56.2 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 206ms TBT · 169.8 MB heap
workflow-execution: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.4 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 8ms
canvas-idle: layout count 0
canvas-idle: style recalc count 10
canvas-idle: task duration 519ms
canvas-idle: script duration 18ms
canvas-idle: TBT 0ms
canvas-idle: heap used 67.0 MB
canvas-idle: DOM nodes 19
canvas-idle: event listeners 5
canvas-mouse-sweep: avg frame time 17ms
canvas-mouse-sweep: p95 frame time 17ms
canvas-mouse-sweep: layout duration 4ms
canvas-mouse-sweep: style recalc duration 36ms
canvas-mouse-sweep: layout count 12
canvas-mouse-sweep: style recalc count 74
canvas-mouse-sweep: task duration 876ms
canvas-mouse-sweep: script duration 123ms
canvas-mouse-sweep: TBT 0ms
canvas-mouse-sweep: heap used 47.9 MB
canvas-mouse-sweep: DOM nodes -281
canvas-mouse-sweep: event listeners -153
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 17ms
canvas-zoom-sweep: layout count 6
canvas-zoom-sweep: style recalc count 32
canvas-zoom-sweep: task duration 382ms
canvas-zoom-sweep: script duration 20ms
canvas-zoom-sweep: TBT 0ms
canvas-zoom-sweep: heap used 69.7 MB
canvas-zoom-sweep: DOM nodes 77
canvas-zoom-sweep: event listeners 19
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 11
dom-widget-clipping: task duration 374ms
dom-widget-clipping: script duration 59ms
dom-widget-clipping: TBT 0ms
dom-widget-clipping: heap used 50.8 MB
dom-widget-clipping: DOM nodes 18
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 8ms
large-graph-idle: layout count 0
large-graph-idle: style recalc count 9
large-graph-idle: task duration 678ms
large-graph-idle: script duration 105ms
large-graph-idle: TBT 0ms
large-graph-idle: heap used 62.1 MB
large-graph-idle: DOM nodes -283
large-graph-idle: event listeners -163
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 13ms
large-graph-pan: layout count 0
large-graph-pan: style recalc count 68
large-graph-pan: task duration 1270ms
large-graph-pan: script duration 423ms
large-graph-pan: TBT 0ms
large-graph-pan: heap used 57.0 MB
large-graph-pan: DOM nodes -285
large-graph-pan: event listeners -163
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 13ms
large-graph-zoom: layout count 60
large-graph-zoom: style recalc count 65
large-graph-zoom: task duration 1460ms
large-graph-zoom: script duration 519ms
large-graph-zoom: TBT 0ms
large-graph-zoom: heap used 81.8 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 8ms
minimap-idle: layout count 0
minimap-idle: style recalc count 8
minimap-idle: task duration 706ms
minimap-idle: script duration 115ms
minimap-idle: TBT 0ms
minimap-idle: heap used 64.2 MB
minimap-idle: DOM nodes -283
minimap-idle: event listeners -148
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 10ms
subgraph-dom-widget-clipping: layout count 0
subgraph-dom-widget-clipping: style recalc count 47
subgraph-dom-widget-clipping: task duration 403ms
subgraph-dom-widget-clipping: script duration 120ms
subgraph-dom-widget-clipping: TBT 0ms
subgraph-dom-widget-clipping: heap used 51.1 MB
subgraph-dom-widget-clipping: DOM nodes 20
subgraph-dom-widget-clipping: event listeners 6
subgraph-idle: avg frame time 17ms
subgraph-idle: p95 frame time 17ms
subgraph-idle: layout duration 0ms
subgraph-idle: style recalc duration 8ms
subgraph-idle: layout count 0
subgraph-idle: style recalc count 9
subgraph-idle: task duration 494ms
subgraph-idle: script duration 14ms
subgraph-idle: TBT 0ms
subgraph-idle: heap used 44.7 MB
subgraph-idle: DOM nodes -282
subgraph-idle: event listeners -153
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 35ms
subgraph-mouse-sweep: layout count 16
subgraph-mouse-sweep: style recalc count 78
subgraph-mouse-sweep: task duration 786ms
subgraph-mouse-sweep: script duration 92ms
subgraph-mouse-sweep: TBT 0ms
subgraph-mouse-sweep: heap used 51.0 MB
subgraph-mouse-sweep: DOM nodes 34
subgraph-mouse-sweep: event listeners -75
subgraph-transition-enter: avg frame time 17ms
subgraph-transition-enter: p95 frame time 17ms
subgraph-transition-enter: layout duration 13ms
subgraph-transition-enter: style recalc duration 30ms
subgraph-transition-enter: layout count 14
subgraph-transition-enter: style recalc count 18
subgraph-transition-enter: task duration 925ms
subgraph-transition-enter: script duration 35ms
subgraph-transition-enter: TBT 153ms
subgraph-transition-enter: heap used 71.0 MB
subgraph-transition-enter: DOM nodes 13673
subgraph-transition-enter: event listeners 2375
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 37ms
viewport-pan-sweep: layout count 0
viewport-pan-sweep: style recalc count 251
viewport-pan-sweep: task duration 4456ms
viewport-pan-sweep: script duration 1376ms
viewport-pan-sweep: TBT 0ms
viewport-pan-sweep: heap used 68.4 MB
viewport-pan-sweep: DOM nodes -282
viewport-pan-sweep: event listeners -132
vue-large-graph-idle: avg frame time 18ms
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 17239ms
vue-large-graph-idle: script duration 591ms
vue-large-graph-idle: TBT 0ms
vue-large-graph-idle: heap used 158.4 MB
vue-large-graph-idle: DOM nodes -8312
vue-large-graph-idle: event listeners -16387
vue-large-graph-pan: avg frame time 18ms
vue-large-graph-pan: p95 frame time 17ms
vue-large-graph-pan: layout duration 0ms
vue-large-graph-pan: style recalc duration 16ms
vue-large-graph-pan: layout count 0
vue-large-graph-pan: style recalc count 140
vue-large-graph-pan: task duration 20586ms
vue-large-graph-pan: script duration 884ms
vue-large-graph-pan: TBT 206ms
vue-large-graph-pan: heap used 169.8 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 17ms
workflow-execution: layout count 3
workflow-execution: style recalc count 13
workflow-execution: task duration 106ms
workflow-execution: script duration 9ms
workflow-execution: TBT 0ms
workflow-execution: heap used 65.4 MB
workflow-execution: DOM nodes 124
workflow-execution: event listeners 98
Raw data
{
  "timestamp": "2026-08-12T23:47:40.994Z",
  "gitSha": "fe93a786edafc1a6accd6410a5426192e85fc7b4",
  "branch": "benjcooley/cloud-gate-cron",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2063.0310000000236,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 7.923000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 547.983,
      "heapDeltaBytes": 5970156,
      "heapUsedBytes": 70306896,
      "domNodes": 20,
      "jsHeapTotalBytes": 24641536,
      "scriptDurationMs": 17.981000000000005,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-idle",
      "durationMs": 2053.9019999999937,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 8.077,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 490.259,
      "heapDeltaBytes": 5916592,
      "heapUsedBytes": 70186996,
      "domNodes": 18,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 17.278999999999996,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1855.2520000000072,
      "styleRecalcs": 74,
      "styleRecalcDurationMs": 36.665000000000006,
      "layouts": 12,
      "layoutDurationMs": 3.496,
      "taskDurationMs": 870.578,
      "heapDeltaBytes": -14133060,
      "heapUsedBytes": 50292348,
      "domNodes": -280,
      "jsHeapTotalBytes": 23830528,
      "scriptDurationMs": 121.378,
      "eventListeners": -153,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1853.5439999999426,
      "styleRecalcs": 73,
      "styleRecalcDurationMs": 35.035,
      "layouts": 12,
      "layoutDurationMs": 3.515,
      "taskDurationMs": 880.962,
      "heapDeltaBytes": -14093868,
      "heapUsedBytes": 50193452,
      "domNodes": -282,
      "jsHeapTotalBytes": 23044096,
      "scriptDurationMs": 124.05900000000001,
      "eventListeners": -153,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1745.9900000000061,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 17.36,
      "layouts": 6,
      "layoutDurationMs": 0.691,
      "taskDurationMs": 391.392,
      "heapDeltaBytes": 8570264,
      "heapUsedBytes": 72974792,
      "domNodes": 76,
      "jsHeapTotalBytes": 24641536,
      "scriptDurationMs": 20.8,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1721.7750000000933,
      "styleRecalcs": 32,
      "styleRecalcDurationMs": 16.569,
      "layouts": 6,
      "layoutDurationMs": 0.544,
      "taskDurationMs": 372.18800000000005,
      "heapDeltaBytes": 8816720,
      "heapUsedBytes": 73235920,
      "domNodes": 77,
      "jsHeapTotalBytes": 24641536,
      "scriptDurationMs": 18.977999999999998,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 589.4579999999792,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 7.575999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 370.985,
      "heapDeltaBytes": -10921232,
      "heapUsedBytes": 53193468,
      "domNodes": 18,
      "jsHeapTotalBytes": 25427968,
      "scriptDurationMs": 58.445,
      "eventListeners": 0,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 569.627999999966,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 7.337999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 376.108,
      "heapDeltaBytes": -11367612,
      "heapUsedBytes": 53264000,
      "domNodes": 18,
      "jsHeapTotalBytes": 25690112,
      "scriptDurationMs": 59.507000000000005,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2010.7429999999908,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 8.327000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 671.843,
      "heapDeltaBytes": 4394964,
      "heapUsedBytes": 63849764,
      "domNodes": -282,
      "jsHeapTotalBytes": 3510272,
      "scriptDurationMs": 101.33300000000001,
      "eventListeners": -179,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2035.180999999966,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 7.822000000000003,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 684.551,
      "heapDeltaBytes": 6584952,
      "heapUsedBytes": 66310492,
      "domNodes": -283,
      "jsHeapTotalBytes": 2985984,
      "scriptDurationMs": 109.19,
      "eventListeners": -147,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2122.2610000000373,
      "styleRecalcs": 68,
      "styleRecalcDurationMs": 12.570000000000006,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1262.957,
      "heapDeltaBytes": -5335036,
      "heapUsedBytes": 55206444,
      "domNodes": -285,
      "jsHeapTotalBytes": 4820992,
      "scriptDurationMs": 420.466,
      "eventListeners": -177,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2199.9100000000453,
      "styleRecalcs": 68,
      "styleRecalcDurationMs": 13.354000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1276.576,
      "heapDeltaBytes": 3843292,
      "heapUsedBytes": 64305436,
      "domNodes": -284,
      "jsHeapTotalBytes": 2654208,
      "scriptDurationMs": 426.522,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3182.288999999969,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 13.743000000000002,
      "layouts": 60,
      "layoutDurationMs": 6.822,
      "taskDurationMs": 1443.793,
      "heapDeltaBytes": 23831960,
      "heapUsedBytes": 86104472,
      "domNodes": 12,
      "jsHeapTotalBytes": 7864320,
      "scriptDurationMs": 516.235,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3194.1710000000967,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 12.607000000000003,
      "layouts": 60,
      "layoutDurationMs": 6.997,
      "taskDurationMs": 1475.59,
      "heapDeltaBytes": 22885220,
      "heapUsedBytes": 85456168,
      "domNodes": 10,
      "jsHeapTotalBytes": 7077888,
      "scriptDurationMs": 521.015,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2028.5400000000777,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.05,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 727.617,
      "heapDeltaBytes": 6569428,
      "heapUsedBytes": 67344076,
      "domNodes": -283,
      "jsHeapTotalBytes": 3248128,
      "scriptDurationMs": 119.87100000000001,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "minimap-idle",
      "durationMs": 2039.6029999999428,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 7.806,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 683.8910000000001,
      "heapDeltaBytes": 6955068,
      "heapUsedBytes": 67297656,
      "domNodes": -283,
      "jsHeapTotalBytes": 4296704,
      "scriptDurationMs": 111.042,
      "eventListeners": -147,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 592.1539999999936,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 11.108,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 406.76,
      "heapDeltaBytes": -10578304,
      "heapUsedBytes": 53753696,
      "domNodes": 20,
      "jsHeapTotalBytes": 25427968,
      "scriptDurationMs": 119.589,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 579.8009999999749,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 9.849,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 400.023,
      "heapDeltaBytes": -10955036,
      "heapUsedBytes": 53488648,
      "domNodes": 20,
      "jsHeapTotalBytes": 26214400,
      "scriptDurationMs": 119.602,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2022.829999999999,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 7.97,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 490.25800000000004,
      "heapDeltaBytes": -17369204,
      "heapUsedBytes": 46820840,
      "domNodes": -281,
      "jsHeapTotalBytes": 23306240,
      "scriptDurationMs": 13.741,
      "eventListeners": -153,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-idle",
      "durationMs": 1993.7780000000203,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 7.861,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 497.969,
      "heapDeltaBytes": -17458432,
      "heapUsedBytes": 46982132,
      "domNodes": -283,
      "jsHeapTotalBytes": 22781952,
      "scriptDurationMs": 13.572000000000001,
      "eventListeners": -153,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1705.0719999999728,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 33.706,
      "layouts": 16,
      "layoutDurationMs": 3.745,
      "taskDurationMs": 761.303,
      "heapDeltaBytes": -3833900,
      "heapUsedBytes": 60746960,
      "domNodes": 65,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 90.827,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1725.1070000000936,
      "styleRecalcs": 78,
      "styleRecalcDurationMs": 36.371,
      "layouts": 16,
      "layoutDurationMs": 3.8470000000000004,
      "taskDurationMs": 810.287,
      "heapDeltaBytes": -18312908,
      "heapUsedBytes": 46122424,
      "domNodes": 3,
      "jsHeapTotalBytes": 23830528,
      "scriptDurationMs": 92.499,
      "eventListeners": -153,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-transition-enter",
      "durationMs": 1417.2800000000052,
      "styleRecalcs": 18,
      "styleRecalcDurationMs": 30.444,
      "layouts": 14,
      "layoutDurationMs": 12.775000000000002,
      "taskDurationMs": 925.174,
      "heapDeltaBytes": 3719940,
      "heapUsedBytes": 74401004,
      "domNodes": 13673,
      "jsHeapTotalBytes": 15466496,
      "scriptDurationMs": 34.676,
      "eventListeners": 2375,
      "totalBlockingTimeMs": 153,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8335.375999999997,
      "styleRecalcs": 251,
      "styleRecalcDurationMs": 37.347,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4421.139,
      "heapDeltaBytes": 11175140,
      "heapUsedBytes": 71090360,
      "domNodes": -281,
      "jsHeapTotalBytes": 5799936,
      "scriptDurationMs": 1370.204,
      "eventListeners": -131,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8299.935000000005,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 35.889,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4490.551999999999,
      "heapDeltaBytes": 12378152,
      "heapUsedBytes": 72402532,
      "domNodes": -283,
      "jsHeapTotalBytes": 5275648,
      "scriptDurationMs": 1382.687,
      "eventListeners": -133,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 17423.96000000008,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 17403.347,
      "heapDeltaBytes": -59352120,
      "heapUsedBytes": 166515396,
      "domNodes": -8312,
      "jsHeapTotalBytes": -8855552,
      "scriptDurationMs": 592.9200000000001,
      "eventListeners": -16389,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 17116.02299999993,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 17075.001,
      "heapDeltaBytes": -45583832,
      "heapUsedBytes": 165589556,
      "domNodes": -8312,
      "jsHeapTotalBytes": -9904128,
      "scriptDurationMs": 588.708,
      "eventListeners": -16385,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 20701.432999999954,
      "styleRecalcs": 140,
      "styleRecalcDurationMs": 16.58599999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 20652.805,
      "heapDeltaBytes": -18168788,
      "heapUsedBytes": 179192480,
      "domNodes": -8312,
      "jsHeapTotalBytes": -9449472,
      "scriptDurationMs": 886.6919999999999,
      "eventListeners": -16385,
      "totalBlockingTimeMs": 244,
      "frameDurationMs": 17.780000000000047,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 20578.963000000043,
      "styleRecalcs": 140,
      "styleRecalcDurationMs": 16.353000000000005,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 20519.345,
      "heapDeltaBytes": -28771520,
      "heapUsedBytes": 176885924,
      "domNodes": -8312,
      "jsHeapTotalBytes": -8663040,
      "scriptDurationMs": 881.5999999999999,
      "eventListeners": -16387,
      "totalBlockingTimeMs": 168,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "workflow-execution",
      "durationMs": 448.5979999999472,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 17.772000000000002,
      "layouts": 3,
      "layoutDurationMs": 0.6330000000000001,
      "taskDurationMs": 106.11900000000001,
      "heapDeltaBytes": 5079928,
      "heapUsedBytes": 68532572,
      "domNodes": 126,
      "jsHeapTotalBytes": 5505024,
      "scriptDurationMs": 8.642,
      "eventListeners": 99,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "workflow-execution",
      "durationMs": 455.581000000052,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 16.898999999999997,
      "layouts": 2,
      "layoutDurationMs": 0.32400000000000007,
      "taskDurationMs": 105.837,
      "heapDeltaBytes": 5040048,
      "heapUsedBytes": 68691828,
      "domNodes": 121,
      "jsHeapTotalBytes": 4718592,
      "scriptDurationMs": 9.402,
      "eventListeners": 97,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    }
  ]
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In @.github/workflows/ci-tests-custom-nodes-cloud.yaml:
- Line 135: Update the changed-files check in the CI workflow so it evaluates
the complete git diff without allowing a short-circuiting grep consumer to
trigger SIGPIPE under pipefail. Preserve the existing path exclusion rules and
ensure any relevant source change still selects the should-run=true branch.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7eebb338-1cf3-423e-b14f-ff0b33d6e0c8

📥 Commits

Reviewing files that changed from the base of the PR and between d02f676 and 208c45e.

📒 Files selected for processing (1)
  • .github/workflows/ci-tests-custom-nodes-cloud.yaml

echo "should-run=false" >> "$GITHUB_OUTPUT"
exit 0
fi
if git diff --name-only "$last" "$GITHUB_SHA" | grep -qvE '^(docs/|apps/|\.storybook/)|\.md$'; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Avoid early exit from the pipefail pipeline.

grep -qvE exits after the first relevant path. For a sufficiently large diff, git diff can receive SIGPIPE. With pipefail, the condition becomes false, so the else branch records should-run=false and skips a relevant source change.

Proposed fix
-          if git diff --name-only "$last" "$GITHUB_SHA" | grep -qvE '^(docs/|apps/|\.storybook/)|\.md$'; then
+          if git diff --name-only "$last" "$GITHUB_SHA" |
+            grep -vE '^(docs/|apps/|\.storybook/)|\.md$' >/dev/null; then
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if git diff --name-only "$last" "$GITHUB_SHA" | grep -qvE '^(docs/|apps/|\.storybook/)|\.md$'; then
if git diff --name-only "$last" "$GITHUB_SHA" |
grep -vE '^(docs/|apps/|\.storybook/)|\.md$' >/dev/null; then
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci-tests-custom-nodes-cloud.yaml at line 135, Update the
changed-files check in the CI workflow so it evaluates the complete git diff
without allowing a short-circuiting grep consumer to trigger SIGPIPE under
pipefail. Preserve the existing path exclusion rules and ensure any relevant
source change still selects the should-run=true branch.

@benjcooley benjcooley left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Automated review — posted by an AI agent (Claude Code)

Swaps push/merge_group for a 3-hour cron plus a freshness job that skips ticks when nothing relevant changed. The idea is sound; the new gate has three independent fail-open paths, and the most severe one gets more likely as the change gets bigger.

Severity Count
BLOCKER 3
SHOULD FIX 1
TRIVIAL 2
Total 6

echo "should-run=false" >> "$GITHUB_OUTPUT"
exit 0
fi
if git diff --name-only "$last" "$GITHUB_SHA" | grep -qvE '^(docs/|apps/|\.storybook/)|\.md$'; then

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

BLOCKERset -o pipefail + grep -q makes this fail open, and it fails open harder the more relevant the change is.

grep -q exits on first match, so git diff gets SIGPIPE and the pipeline returns 141. That isn't 0, so the gate takes the skip branch — on exactly the ticks that had relevant deltas.

I reproduced it locally: a 467-file diff gives pipeline rc=141 → skip. Same at 1516, 3307, 5505 files. Small diffs may finish writing before the pipe closes and behave correctly, which is why this would pass a casual test and then silently drop the big merges.

The log line also misreports the reason, so it looks like a legitimate no-op tick.

Use git diff --quiet <range> -- <paths> and branch on its exit code, or drop -q and capture the output.

Posted by an AI agent (Claude Code).

echo "should-run=true" >> "$GITHUB_OUTPUT"
exit 0
fi
last=$(gh api "repos/${GITHUB_REPOSITORY}/actions/workflows/ci-tests-custom-nodes-cloud.yaml/runs?status=completed&branch=${GITHUB_REF_NAME}&per_page=1" --jq '.workflow_runs[0].head_sha // ""')

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

BLOCKERstatus=completed matches cancelled, failed and timed-out runs, not just successful ones. So the watermark advances past commits that never actually got a Cloud verdict.

Failure mode: a run is cancelled (concurrency eviction — see the group collision below) → watermark moves to its SHA anyway → the next tick diffs from there → a docs-only delta → skip. The commits that never got verified are now permanently behind the watermark and never will be.

Should be conclusion=success.

Posted by an AI agent (Claude Code).

# and this job would have nothing to run, so skip it (a skip counts as
# passing, keeping this required-safe). Non-PR events (push, merge_group,
# workflow_dispatch) are same-repo by construction and fall through the OR.
needs: [changes, freshness]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

BLOCKERneeds: [changes, freshness] with no always() puts a fail-open path in front of a gate whose own header says it must fail closed.

Under set -e, one transient gh api hiccup fails the freshness job → the suite job is skipped → and a skipped job counts as passing for a required check. A network blip silently converts the Cloud gate into a green check.

It also defeats the stated "dispatches always run" intent, since a failed freshness job skips those too.

Default to running on any freshness error rather than skipping.

Posted by an AI agent (Claude Code).

# the timer activates when the suite lands on main; until then dispatch
# drives runs. Minute 23: off the top-of-hour scheduler stampede.
schedule:
- cron: '23 */3 * * *'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

SHOULD FIX — The "a tick never overlaps its predecessor" rationale only considers this workflow, but the custom-nodes-cloud-instance concurrency group is shared with two others.

Concretely: the 08:23 tick collides with the nightly canary's 08:30 cloud job, every day. The canary's own comment notes that an evicted pending job silently loses the night. Record runs (timeout-minutes: 350) span two ticks, so the pending one is evicted as well.

A cron offset that clears the canary window is probably all this needs.

Posted by an AI agent (Claude Code).

# scheduled ticks conditional on a relevant delta. No pull_request
# trigger exists, so every event here is same-repo by construction.
if: >-
needs.changes.outputs.should-run == 'true' &&

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

TRIVIAL — With the pull_request trigger gone, needs.changes.outputs.should-run is now always 'true'. The changes job is a runner plus a checkout, every tick (8/day), to compute a constant. Drop it or fold it into freshness.

Posted by an AI agent (Claude Code).

branches: [main, master, nathaniel/custom-node-e2e-suite]
merge_group:
# Timer-driven, never per-commit. Every automatic run occupies ONE serial
# Cloud resource (the smoke account's queue) for 75-160 minutes, and

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

TRIVIAL — Two doc drifts in the header: the new "75-160 minutes" contradicts both timeout-minutes: 150 and the adjacent "~110m" comment, and the FORK-SAFETY block still documents the same-repo if: guard this PR deletes. The second one matters slightly more, since it describes a safety property that no longer exists.

Posted by an AI agent (Claude Code).

@christian-byrne

Copy link
Copy Markdown
Contributor

suggestion: close this.

It edits one file, .github/workflows/ci-tests-custom-nodes-cloud.yaml, and #15200 deletes that file. The cloud leg is cut per the 2026-08-13 huddle and returns by dockerizing local cloud dev services rather than running against testcloud, so a change-gated 3-hour timer against the live cloud gate has no target left.

The diagnosis in here was right — the single-slot custom-nodes-cloud-instance concurrency group evicting queued runs is what produced the 52% cancellation rate — and it is worth carrying into the dockerized rebuild so the same shape does not get recreated. But that is a note for the follow-up, not a reason to keep this open.

@benjcooley

Copy link
Copy Markdown
Contributor Author

I have read and agree to the Contributor License Agreement

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

Labels

size:XS This PR changes 0-9 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants