Skip to content

ci: run vp through a file so forwarding output cannot hit EAGAIN - #2697

Merged
decepulis merged 1 commit into
mainfrom
claude/rc-release-readiness-qaqw5t
Sep 9, 2026
Merged

ci: run vp through a file so forwarding output cannot hit EAGAIN#2697
decepulis merged 1 commit into
mainfrom
claude/rc-release-readiness-qaqw5t

Conversation

@decepulis

@decepulis decepulis commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Why

Six Test packages shards across three CI runs on 2026-09-09 failed with no failing test:

✗ Failed to forward task process output: Resource temporarily unavailable (os error 11)
vp run: 0/25 cache hit (0%), 4 failed.

Runs: 34411239444 (release branch, pnpm 12), 34412176604 (pnpm 11), 34406370628 (chore/pnpm-12). Every vitest suite in those jobs passed; vp gave up while children were still printing passing results.

Mechanism, verified by two independent reviews of the logs and of vite-plus@0.2.8:

  • The message is SavedExecutionError::ForwardTaskProcessOutput in the Rust core, a failed write of forwarded output to vp's own stdout. Not a read.
  • vp calls ensureBlockingStdio() at startup, but the Node processes it spawns for tasks set O_NONBLOCK on the shared stdout file description while they run (observed by sampling /proc/<pid>/fdinfo/1 during a real vp run). Node does this to any pipe it touches, never to a regular file.
  • A large burst of forwarded output (a vp pack dumping ~1,400 dist/... lines in ~60 ms) while such a child is alive fills the pipe; the write returns EAGAIN; vp marks the task failed.
  • A cold task cache makes the bursts bigger and more frequent but is not the cause: a passing shard on main had 0% cache hits and 3× the output.
  • Not pnpm-version related; it reproduced under 11.17.0 and 12.3.4.

Release exposure: cd.yml's release job builds every package with vp before pnpm -r publish, and release-please has already tagged the release by then. A re-run would find nothing to release and skip publish. That build has passed cold twice (rc.1 and today), so the risk is probabilistic, not observed.

What

  • .github/scripts/run-logged.sh <name> <command...>: runs the command with stdout and stderr in $RUNNER_TEMP/<name>.log, prints the log, exits with the command's status.
  • cd.yml: clean, build:packages, build:cdn, build:site, build:cli run through it.
  • ci.yml: Test packages and Test SPF run through it. These are the steps that actually failed.

Cost: step output appears when the step ends instead of streaming, and stdout/stderr are merged.

Verified

  • actionlint passes on both workflows; script is 100755.
  • Wrapper preserves exit status (0 and 7 tested) and captures both streams; child sees a regular file on fd 1 with O_NONBLOCK clear.
  • Reviewer check: node flags.js | cat reports O_NONBLOCK=true; node flags.js > out.txt reports O_NONBLOCK=false.

Follow-ups

  • Report upstream to Vite+: vp should retry on EAGAIN or re-clear O_NONBLOCK while forwarding.
  • Consider vp run --last-details in a failure path so failed tasks are attributable from the log.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JZ5RTqfnRMiiASH1T7tWVj


Note

Low Risk
CI/CD workflow and helper-script changes only; no application runtime behavior, aside from non-streaming GitHub Actions logs.

Overview
Adds .github/scripts/run-logged.sh so vp and related pnpm tasks write stdout/stderr to a temp log file (avoiding pipe EAGAIN when Node sets non-blocking mode on forwarded output), then replay the log and preserve the exit code.

CI routes Test packages and Test SPF through the wrapper; CD routes release clean, package/CDN/site/CLI builds the same way. Step logs show up when the step finishes and streams are merged.

Also adds temporary “Drop task cache (experiment, do not merge)” steps in ci.yml that delete node_modules/.vite/task-cache before those tests—likely for debugging and probably should be removed before merge.

Reviewed by Cursor Bugbot for commit c660ef2. Bugbot is set up for automated code reviews on this repo. Configure here.

@netlify

netlify Bot commented Sep 9, 2026

Copy link
Copy Markdown

Deploy Preview for vjs-registry canceled.

Name Link
🔨 Latest commit 47342f7
🔍 Latest deploy log https://app.netlify.com/projects/vjs-registry/deploys/6aa1e591ce70510008cfad86

@vercel

vercel Bot commented Sep 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
v10-sandbox Ready Ready Preview Sep 9, 2026 10:59pm UTC

Request Review

@netlify

netlify Bot commented Sep 9, 2026

Copy link
Copy Markdown

Deploy Preview for vjs10-site ready!

Name Link
🔨 Latest commit 47342f7
🔍 Latest deploy log https://app.netlify.com/projects/vjs10-site/deploys/6aa1e591f262ae00099574f8
😎 Deploy Preview https://deploy-preview-2697--vjs10-site.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@pkg-pr-new

pkg-pr-new Bot commented Sep 9, 2026

Copy link
Copy Markdown
@videojs/cdn

pnpm add https://pkg.pr.new/@videojs/cdn@2697

@videojs/core

pnpm add https://pkg.pr.new/@videojs/core@2697

@videojs/element

pnpm add https://pkg.pr.new/@videojs/element@2697

@videojs/html

pnpm add https://pkg.pr.new/@videojs/html@2697

@videojs/media

pnpm add https://pkg.pr.new/@videojs/media@2697

@videojs/react

pnpm add https://pkg.pr.new/@videojs/react@2697

@videojs/spf

pnpm add https://pkg.pr.new/@videojs/spf@2697

@videojs/store

pnpm add https://pkg.pr.new/@videojs/store@2697

@videojs/utils

pnpm add https://pkg.pr.new/@videojs/utils@2697

@videojs/cloudflare-video

pnpm add https://pkg.pr.new/@videojs/cloudflare-video@2697

@videojs/dash-video

pnpm add https://pkg.pr.new/@videojs/dash-video@2697

@videojs/hlsjs-video

pnpm add https://pkg.pr.new/@videojs/hlsjs-video@2697

@videojs/mux-audio

pnpm add https://pkg.pr.new/@videojs/mux-audio@2697

@videojs/mux-video

pnpm add https://pkg.pr.new/@videojs/mux-video@2697

@videojs/native-hls-video

pnpm add https://pkg.pr.new/@videojs/native-hls-video@2697

@videojs/shaka-video

pnpm add https://pkg.pr.new/@videojs/shaka-video@2697

@videojs/spotify-audio

pnpm add https://pkg.pr.new/@videojs/spotify-audio@2697

@videojs/tiktok-video

pnpm add https://pkg.pr.new/@videojs/tiktok-video@2697

@videojs/twitch-video

pnpm add https://pkg.pr.new/@videojs/twitch-video@2697

@videojs/vimeo-video

pnpm add https://pkg.pr.new/@videojs/vimeo-video@2697

@videojs/wistia-video

pnpm add https://pkg.pr.new/@videojs/wistia-video@2697

@videojs/youtube-video

pnpm add https://pkg.pr.new/@videojs/youtube-video@2697

@videojs/google-cast

pnpm add https://pkg.pr.new/@videojs/google-cast@2697

@videojs/mux-data

pnpm add https://pkg.pr.new/@videojs/mux-data@2697

commit: c660ef2

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle Size Report

🎨 @videojs/html — no changes
Presets (7)
Entry Initial Lazy
/video (default) 63.76 kB 58.19 kB
/video (default + hls) 65.59 kB 58.19 kB
/video (minimal) 64.01 kB 58.19 kB
/video (minimal + hls) 65.82 kB 58.19 kB
/audio (default) 47.53 kB 58.19 kB
/audio (minimal) 47.72 kB 58.19 kB
/background 11.65 kB 58.19 kB
Media (18)
Entry Initial
/media/mux-video 3.01 kB
/media/mux-audio 2.69 kB
/media/background-video 1.16 kB
/media/cloudflare-video 2.90 kB
/media/dash-video 2.63 kB
/media/hls-audio 22.05 kB
/media/hls-background-video 16.85 kB
/media/hls-video 28.01 kB
/media/hlsjs-video 2.63 kB
/media/mux-background-video 16.86 kB
/media/native-hls-video 7.59 kB
/media/shaka-video 2.63 kB
/media/spotify-audio 3.02 kB
/media/tiktok-video 3.13 kB
/media/twitch-video 2.93 kB
/media/vimeo-video 2.90 kB
/media/wistia-video 607 B
/media/youtube-video 2.90 kB
Players (5)
Entry Initial Lazy
/video/player 9.79 kB 58.19 kB
/audio/player 6.21 kB 58.19 kB
/background/player 4.46 kB 58.19 kB
/live-video/player 9.18 kB 58.19 kB
/live-audio/player 6.22 kB 58.19 kB
Skins (29)
Entry Type Initial Lazy
/video/minimal-skin.css css 7.82 kB
/video/skin.css css 7.64 kB
/video/minimal-skin js 62.51 kB 58.19 kB
/video/minimal-skin2 js 8.37 kB
/video/skin js 62.32 kB 58.19 kB
/video/skin2 js 8.24 kB
/audio/minimal-skin.css css 5.64 kB
/audio/skin.css css 5.47 kB
/audio/minimal-skin js 46.25 kB 58.19 kB
/audio/minimal-skin2 js 6.00 kB
/audio/skin js 46.13 kB 58.19 kB
/audio/skin2 js 5.83 kB
/background/skin.css css 139 B
/background/skin js 9.91 kB 58.19 kB
/background/skin2 js 187 B
/live-video/minimal-skin.css css 6.28 kB
/live-video/skin.css css 6.26 kB
/live-video/minimal-skin js 49.85 kB 58.19 kB
/live-video/minimal-skin2 js 6.66 kB
/live-video/skin js 49.91 kB 58.19 kB
/live-video/skin2 js 6.71 kB
/live-audio/minimal-skin.css css 4.46 kB
/live-audio/skin.css css 4.46 kB
/live-audio/minimal-skin js 35.69 kB 58.19 kB
/live-audio/minimal-skin2 js 4.74 kB
/live-audio/skin js 35.68 kB 58.19 kB
/live-audio/skin2 js 4.74 kB
/global.css css 190 B
/shared.css css 118 B
UI Components (62)
Entry Initial Lazy
/ui/airplay-button 11.36 kB 58.19 kB
/ui/alert-dialog 8.79 kB 58.19 kB
/ui/audio-track-radio-group 11.46 kB 58.19 kB
/ui/buffering-indicator 8.68 kB 58.19 kB
/ui/captions-button 11.59 kB 58.19 kB
/ui/captions-radio-group 11.54 kB 58.19 kB
/ui/cast-button 11.34 kB 58.19 kB
/ui/container 9.58 kB 58.19 kB
/ui/controls 8.86 kB 58.19 kB
/ui/controls-backdrop 1.69 kB 58.19 kB
/ui/controls-content 1.67 kB 58.19 kB
/ui/dialog 8.73 kB 58.19 kB
/ui/dialog-backdrop 1.70 kB 58.19 kB
/ui/dialog-close 2.06 kB 58.19 kB
/ui/dialog-description 1.69 kB 58.19 kB
/ui/dialog-popup 1.90 kB 58.19 kB
/ui/dialog-title 1.70 kB 58.19 kB
/ui/error-dialog 12.47 kB 58.19 kB
/ui/fullscreen-button 11.33 kB 58.19 kB
/ui/gesture 9.66 kB 58.19 kB
/ui/hotkey 10.13 kB 58.19 kB
/ui/live-button 9.89 kB 58.19 kB
/ui/menu 18.54 kB 58.19 kB
/ui/menu-checkbox-item 1.97 kB 58.19 kB
/ui/menu-content 7.52 kB 58.19 kB
/ui/menu-group 2.09 kB 58.19 kB
/ui/menu-group-label 1.64 kB
/ui/menu-item 2.30 kB 58.19 kB
/ui/menu-item-indicator 1.38 kB 58.19 kB
/ui/menu-radio-group 3.01 kB 58.19 kB
/ui/menu-radio-item 2.13 kB 58.19 kB
/ui/menu-separator 1.30 kB 58.19 kB
/ui/mute-button 11.36 kB 58.19 kB
/ui/pip-button 11.31 kB 58.19 kB
/ui/play-button 11.31 kB 58.19 kB
/ui/playback-rate-button 11.41 kB 58.19 kB
/ui/playback-rate-radio-group 11.46 kB 58.19 kB
/ui/popover 8.57 kB 58.19 kB
/ui/poster 8.97 kB 58.19 kB
/ui/quality-radio-group 12.05 kB 58.19 kB
/ui/seek-button 11.34 kB 58.19 kB
/ui/seek-indicator 12.77 kB 58.19 kB
/ui/seek-indicator-value 1.10 kB
/ui/slider 11.75 kB 58.19 kB
/ui/slider-preview 2.01 kB 58.19 kB
/ui/status-announcer 10.68 kB 58.19 kB
/ui/status-indicator 13.10 kB 58.19 kB
/ui/status-indicator-value 1.10 kB
/ui/thumbnail 10.35 kB 58.19 kB
/ui/time 11.11 kB 58.19 kB
/ui/time-slider 13.22 kB 58.19 kB
/ui/time-slider-chapter-title 8.87 kB 58.19 kB
/ui/time-slider-chapters 9.71 kB 58.19 kB
/ui/title 8.25 kB 58.19 kB
/ui/tooltip 9.95 kB 58.19 kB
/ui/tooltip-label 1.21 kB
/ui/tooltip-shortcut 1.18 kB
/ui/volume-indicator 13.11 kB 58.19 kB
/ui/volume-indicator-fill 1.11 kB
/ui/volume-indicator-value 1.10 kB
/ui/volume-popover 14.82 kB 58.19 kB
/ui/volume-slider 12.43 kB 58.19 kB
⚛️ @videojs/react — no changes
Presets (7)
Entry Initial Lazy
/video (default) 51.38 kB 58.19 kB
/video (default + hls) 51.54 kB 58.19 kB
/video (minimal) 51.51 kB 58.19 kB
/video (minimal + hls) 51.80 kB 58.19 kB
/audio (default) 39.82 kB 58.19 kB
/audio (minimal) 39.89 kB 58.19 kB
/background 581 B 58.19 kB
Media (22)
Entry Initial
/media/mux-video/hls-js 958 B
/media/mux-video/spf 962 B
/media/mux-audio/hls-js 699 B
/media/mux-audio/spf 703 B
/media/background-video 402 B
/media/cloudflare-video 911 B
/media/dash-video 693 B
/media/hls-audio 20.32 kB
/media/hls-background-video 16.47 kB
/media/hls-video 26.32 kB
/media/hlsjs-video 695 B
/media/mux-audio 693 B
/media/mux-background-video 16.41 kB
/media/mux-video 948 B
/media/native-hls-video 5.78 kB
/media/shaka-video 704 B
/media/spotify-audio 901 B
/media/tiktok-video 906 B
/media/twitch-video 929 B
/media/vimeo-video 888 B
/media/wistia-video 619 B
/media/youtube-video 897 B
Extensions (2)
Entry Initial
/extensions/google-cast 1.59 kB
/extensions/mux-data 1.64 kB
Players (5)
Entry Initial Lazy
/video/player 7.67 kB 58.19 kB
/audio/player 4.06 kB 58.19 kB
/background/player 2.27 kB 58.19 kB
/live-video/player 7.06 kB 58.19 kB
/live-audio/player 4.05 kB 58.19 kB
Skins (18)
Entry Type Initial Lazy
/video/minimal-skin.css css 7.68 kB
/video/skin.css css 7.50 kB
/video/minimal-skin js 51.46 kB 58.19 kB
/video/skin js 51.32 kB 58.19 kB
/audio/minimal-skin.css css 5.46 kB
/audio/skin.css css 5.29 kB
/audio/minimal-skin js 39.78 kB 58.19 kB
/audio/skin js 39.74 kB 58.19 kB
/background/skin.css css 90 B
/background/skin js 277 B
/live-video/minimal-skin.css css 6.13 kB
/live-video/skin.css css 6.12 kB
/live-video/minimal-skin js 42.90 kB 58.19 kB
/live-video/skin js 42.92 kB 58.19 kB
/live-audio/minimal-skin.css css 4.28 kB
/live-audio/skin.css css 4.28 kB
/live-audio/minimal-skin js 30.55 kB 58.19 kB
/live-audio/skin js 30.58 kB 58.19 kB
UI Components (39)
Entry Initial Lazy
/ui/airplay-button 10.53 kB 58.19 kB
/ui/alert-dialog 4.73 kB 58.19 kB
/ui/audio-track 8.04 kB 58.19 kB
/ui/audio-track-radio-group 9.57 kB 58.19 kB
/ui/buffering-indicator 7.88 kB 58.19 kB
/ui/captions-button 10.51 kB 58.19 kB
/ui/captions-radio-group 9.67 kB 58.19 kB
/ui/cast-button 10.51 kB 58.19 kB
/ui/controls 7.80 kB 58.19 kB
/ui/dialog 4.75 kB 58.19 kB
/ui/error-dialog 11.88 kB 58.19 kB
/ui/fullscreen-button 10.49 kB 58.19 kB
/ui/gesture 8.07 kB 58.19 kB
/ui/hotkey 8.56 kB 58.19 kB
/ui/live-button 8.91 kB 58.19 kB
/ui/menu 19.54 kB 58.19 kB
/ui/mute-button 10.53 kB 58.19 kB
/ui/pip-button 10.48 kB 58.19 kB
/ui/play-button 10.45 kB 58.19 kB
/ui/playback-rate 8.07 kB 58.19 kB
/ui/playback-rate-button 10.45 kB 58.19 kB
/ui/playback-rate-radio-group 9.60 kB 58.19 kB
/ui/popover 8.16 kB 58.19 kB
/ui/poster 7.95 kB 58.19 kB
/ui/quality 8.50 kB 58.19 kB
/ui/quality-radio-group 10.04 kB 58.19 kB
/ui/seek-button 10.52 kB 58.19 kB
/ui/seek-indicator 12.06 kB 58.19 kB
/ui/slider 13.12 kB 58.19 kB
/ui/status-announcer 10.18 kB 58.19 kB
/ui/status-indicator 12.37 kB 58.19 kB
/ui/thumbnail 9.18 kB 58.19 kB
/ui/time 10.03 kB 58.19 kB
/ui/time-slider 14.40 kB 58.19 kB
/ui/title 7.35 kB 58.19 kB
/ui/tooltip 8.93 kB 58.19 kB
/ui/volume-indicator 12.42 kB 58.19 kB
/ui/volume-popover 14.29 kB 58.19 kB
/ui/volume-slider 12.25 kB 58.19 kB
🧩 @videojs/core — no changes
Entries (76)
Entry Initial Lazy
. 13.35 kB
/dom 22.82 kB 58.19 kB
/vjsc 1.87 kB
/i18n 3.23 kB 58.19 kB
/i18n/locales/all 35.98 kB
/i18n/locales/ar 1.24 kB
/i18n/locales/az 1.12 kB
/i18n/locales/bg 1.32 kB
/i18n/locales/bn 1.25 kB
/i18n/locales/bs 1.03 kB
/i18n/locales/ca 1.10 kB
/i18n/locales/cs 1.11 kB
/i18n/locales/cy 1.05 kB
/i18n/locales/da 1.01 kB
/i18n/locales/de 1.11 kB
/i18n/locales/el 1.53 kB
/i18n/locales/en 801 B
/i18n/locales/es 1.02 kB
/i18n/locales/et 1.07 kB
/i18n/locales/eu 1.04 kB
/i18n/locales/fa 1.25 kB
/i18n/locales/fi 1.07 kB
/i18n/locales/fr 1.09 kB
/i18n/locales/gd 1.13 kB
/i18n/locales/gl 1.02 kB
/i18n/locales/he 1.16 kB
/i18n/locales/hi 1.33 kB
/i18n/locales/hr 1.05 kB
/i18n/locales/hu 1.11 kB
/i18n/locales/id 941 B
/i18n/locales/it 1.04 kB
/i18n/locales/ja 1.22 kB
/i18n/locales/ko 1.18 kB
/i18n/locales/lt 1.04 kB
/i18n/locales/lv 1.11 kB
/i18n/locales/mr 1.32 kB
/i18n/locales/nb 1015 B
/i18n/locales/ne 1.32 kB
/i18n/locales/nl 1.02 kB
/i18n/locales/nn 1015 B
/i18n/locales/oc 1.10 kB
/i18n/locales/pl 1.17 kB
/i18n/locales/pt 1.05 kB
/i18n/locales/pt-BR 1.05 kB
/i18n/locales/pt-PT 1.04 kB
/i18n/locales/ro 1.10 kB
/i18n/locales/ru 1.42 kB
/i18n/locales/sk 1.13 kB
/i18n/locales/sl 1.07 kB
/i18n/locales/sr 1.13 kB
/i18n/locales/sv 1.03 kB
/i18n/locales/te 1.34 kB
/i18n/locales/th 1.31 kB
/i18n/locales/tr 1.09 kB
/i18n/locales/uk 1.44 kB
/i18n/locales/vi 1.13 kB
/i18n/locales/zh 1.04 kB
/i18n/locales/zh-CN 1.04 kB
/i18n/locales/zh-TW 1.04 kB
/i18n/text/airplay 101 B
/i18n/text/buttons 137 B
/i18n/text/captions 93 B
/i18n/text/cast 114 B
/i18n/text/common 90 B
/i18n/text/container 75 B
/i18n/text/errors 285 B
/i18n/text/fullscreen 98 B
/i18n/text/live 126 B
/i18n/text/menu 249 B
/i18n/text/pip 101 B
/i18n/text/playback 80 B
/i18n/text/seek 105 B
/i18n/text/slider 65 B
/i18n/text/status 222 B
/i18n/text/time 322 B
/i18n/text/volume 133 B
🏷️ @videojs/element — no changes
Entries (2)
Entry Initial
. 1.05 kB
/context 943 B
📦 @videojs/store — no changes
Entries (3)
Entry Initial
. 1.72 kB
/html 703 B
/react 365 B
🔧 @videojs/utils — no changes
Entries (13)
Entry Initial
/array 271 B
/dom 5.11 kB
/events 320 B
/function 386 B
/i18n 249 B
/jwt 176 B
/object 535 B
/predicate 297 B
/percent 281 B
/string 239 B
/style 212 B
/time 976 B
/number 199 B
📦 @videojs/cdn — no changes
📦 @videojs/cloudflare-video — no changes
📦 @videojs/dash-video — no changes
📦 @videojs/google-cast — no changes
📦 @videojs/hlsjs-video — no changes
📦 @videojs/media — no changes
Entries (3)
Entry Initial
. 1.29 kB
/dom 4.12 kB
/media-tracks 2.05 kB
📦 @videojs/mux — no changes
📦 @videojs/mux-audio — no changes
Entries (2)
Entry Initial
. 135.53 kB
/spf 20.81 kB
📦 @videojs/mux-data — no changes
📦 @videojs/mux-video — no changes
Entries (2)
Entry Initial
. 135.67 kB
/spf 26.72 kB
📦 @videojs/native-hls-video — no changes
📦 @videojs/shaka-video — no changes
📦 @videojs/spf — no changes
Entries (7)
Entry Initial
. 4.55 kB
/dom 6.60 kB
/hls 22.15 kB
/media-tracks 504 B
/hls-background-video 15.84 kB
/hls-audio 19.84 kB
/hls-video 25.89 kB
📦 @videojs/spotify-audio — no changes
📦 @videojs/tiktok-video — no changes
📦 @videojs/twitch-video — no changes
📦 @videojs/vimeo-video — no changes
📦 @videojs/wistia-video — no changes
Entries (2)
Entry Initial
. 1.91 kB
/helpers 1.77 kB
📦 @videojs/youtube-video — no changes

ℹ️ How to interpret

Each entry is independently bundled, minified, and brotli-compressed. Initial size includes its static import graph; lazy dynamic chunks are reported separately.

Entries are not additive because their dependency graphs overlap. Preset rows represent realistic combined bundles.

Changes of 300 B or less across initial, lazy, and total size are collapsed, not discarded.

Run pnpm size locally to check current initial sizes.

Vite Task forwards task output to its own stdout. In GitHub Actions that
stdout is a pipe, and the Node processes vp spawns for tasks set
O_NONBLOCK on the shared file description while they run (Node does this
to every pipe it touches; vp clears the flag at startup but its children
re-set it). When a large burst of forwarded output lands while such a
child is alive, the pipe fills and the write fails with

  ✗ Failed to forward task process output: Resource temporarily
    unavailable (os error 11)

and vp records the task as failed even though it finished. Six "Test
packages" shards across three CI runs on 2026-09-09 died this way, under
pnpm 11 and pnpm 12 alike, with every vitest suite passing. Nothing about
the step's exit code distinguishes this from a real test failure.

The release job in cd.yml builds every package the same way before
`pnpm -r publish`. Its build has survived cold so far, but release-please
has already tagged the release by the time that step runs, and a failure
there leaves nothing on npm.

Route the vp-driven steps in ci.yml and cd.yml through a small wrapper
that sends their output to a regular file, then prints the file. Node only
makes pipes non-blocking, and writes to a regular file never return
EAGAIN. Exit status is preserved. The cost is that step output appears
when the step ends rather than streaming.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JZ5RTqfnRMiiASH1T7tWVj
@decepulis
decepulis force-pushed the claude/rc-release-readiness-qaqw5t branch from 9ee5eaf to 47342f7 Compare September 9, 2026 22:45
@decepulis decepulis changed the title ci(cd): write release build output to a file so vp cannot hit EAGAIN ci: run vp through a file so forwarding output cannot hit EAGAIN Sep 9, 2026
@decepulis
decepulis marked this pull request as ready for review September 9, 2026 22:51

Copy link
Copy Markdown
Collaborator Author

Hold off merging for a few minutes: the head commit (c660ef2, "DO NOT MERGE") is a temporary experiment that deletes the Vite task cache before the test steps, so this run exercises the wrapper on the cold path that failed three of three cold runs today. I'll drop that commit once the run finishes and post the result here.


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

Experiment done, commit dropped; head is back to 47342f7 (the reviewed change, nothing else).

Result of run 34414800964 with the task cache deleted before each test step, so every shard ran the fully cold path through the wrapper:

Job cache result
Test packages (2/4) 0/29 (0%) pass, no EAGAIN
Test packages (4/4) 0/38 (0%) pass, no EAGAIN
Test packages (1/4), (3/4), Test (@videojs/spf) cold pass

Shards 2/4 and 4/4 are the two that failed in all three cold runs earlier today without the wrapper. One cold pass through the wrapper is consistent with the mechanism, not proof against a race, so I'd still call this hardening rather than a verified fix. Safe to merge.


Generated by Claude Code

@decepulis
decepulis merged commit 9bce5fc into main Sep 9, 2026
59 of 60 checks passed
@decepulis
decepulis deleted the claude/rc-release-readiness-qaqw5t branch September 9, 2026 23:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants