ci: cloud gate runs on a change-gated 3-hour timer, not per commit - #15163
ci: cloud gate runs on a change-gated 3-hour timer, not per commit#15163benjcooley wants to merge 1 commit into
Conversation
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>
📝 WalkthroughWalkthroughThe 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. ChangesCloud E2E scheduling
Estimated code review effort: 3 (Moderate) | ~20 minutes Mergeability Score: 🟡 Moderate · up to 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: Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 inconclusive)
✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 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 |
🎭 Playwright: ✅ 1991 passed, 0 failed · 3 flaky📊 Browser Reports
📦 Bundle Size
⚡ Performance Report
Absolute values
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
}
]
} |
There was a problem hiding this comment.
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
📒 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 |
There was a problem hiding this comment.
🎯 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.
| 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
left a comment
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
BLOCKER — set -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 // ""') |
There was a problem hiding this comment.
BLOCKER — status=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] |
There was a problem hiding this comment.
BLOCKER — needs: [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 * * *' |
There was a problem hiding this comment.
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' && |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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).
|
suggestion: close this. It edits one file, The diagnosis in here was right — the single-slot |
|
I have read and agree to the Contributor License Agreement |
Converts the cloud gate from per-push to timer-driven, as decided:
schedule: '23 */3 * * *'replaces thepush/merge_grouptriggers. 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.freshnessjob 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 aschanges-filter). Quiet days cost zero cloud runs; busy days cost at most 8.workflow_dispatchalways runs (freshness passes non-schedule events through).pull_requesttrigger 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-yamlvalidates; no test-side changes.