From b65ef333da0e28c75858d0fdd8c3534cf6df682f Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza Date: Thu, 27 Aug 2026 13:39:29 -0300 Subject: [PATCH] fix(ci): size the install-upgrade gate to a measured run, and log the pack cost (#11776) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v3.8.50 publish died at `Prove clean-install AND upgrade-over-previous both boot` — timed out after 30 minutes. Not a defect found: the gate never got to finish. The log says why, once you read past the first line: 03:42:49 packing v3.8.50… 04:07:28 PHASE A — clean install of the packed tarball 04:13:08 timeout `npm pack` alone took **24m37s**, leaving 5 minutes for two installs and two boots. The budget was never going to hold. Worth naming: this gate landed in #8953 and the 2026-08-27 run was the FIRST to ever reach it. Every earlier publish died upstream — disk exhaustion, a missing dist/BUILD_SHA — so `timeout-minutes: 30` had never been measured against a real execution. It was a guess, and it blew on its debut. Same shape as the rest of this cycle: a gate that had never been allowed to finish speaking. Two changes, and the second is the one that matters next time: - `timeout-minutes: 30` -> `60`, sized to the single measurement available. - the script now times the pack and prints duration + tarball size. Without it the log showed `packing…` and then nothing for 30 minutes, which reads like a hang and is not — raising a limit blind would have been a guess on top of a guess. If 60 also proves short, the next log will say exactly which phase ate it. --- .github/workflows/npm-publish.yml | 7 ++++++- scripts/check/check-install-upgrade.mjs | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 7fa6882a88..f58acff65b 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -287,7 +287,12 @@ jobs: # a staged package that is never approved simply expires, with no `npm deprecate` needed. - name: Prove clean-install AND upgrade-over-previous both boot if: steps.resolve.outputs.skip != 'true' - timeout-minutes: 30 + # 60, not 30. This gate was added in #8953 and the 2026-08-27 v3.8.50 publish + # was the FIRST run to ever reach it — every earlier attempt died upstream, so + # its budget had never been measured against a real run. It then blew the limit + # on its debut: `npm pack` alone took 24m37s, leaving 5 minutes for two installs + # and two boots. 30 was a guess; 60 is sized to the one measurement we have. + timeout-minutes: 60 run: npm run check:install-upgrade # WS1.3 (D2, v3.8.49 plan): STAGED publishing by default — `npm stage publish` diff --git a/scripts/check/check-install-upgrade.mjs b/scripts/check/check-install-upgrade.mjs index 87253c611d..04cb0b4437 100644 --- a/scripts/check/check-install-upgrade.mjs +++ b/scripts/check/check-install-upgrade.mjs @@ -223,6 +223,11 @@ async function main() { const warnings = []; try { + // Timed, because this turned out to be the expensive part: on the 2026-08-27 + // v3.8.50 publish `npm pack` alone took 24m37s, leaving 5 of the step's 30-minute + // budget for two installs and two boots. Without a duration here the log showed + // only "packing…" then a timeout, which reads like a hang and is not. + const packStarted = Date.now(); log(`packing v${version}…`); const packOut = execFileSync("npm", ["pack", "--json", "--pack-destination", tmp], { cwd: ROOT, @@ -230,6 +235,8 @@ async function main() { maxBuffer: 128 * 1024 * 1024, }); const tarball = path.join(tmp, pickTarball(packOut)); + const packMb = (fs.statSync(tarball).size / 1024 / 1024).toFixed(1); + log(`packed in ${Math.round((Date.now() - packStarted) / 1000)}s (${packMb} MB)`); // ---- Phase A: clean install ------------------------------------------------- log("PHASE A — clean install of the packed tarball");