Move the artifact pair to the exact commits @v3 was resolving to
Some checks failed
check / check (push) Successful in 8s
Build and Deploy to Cloudflare Pages / build (push) Successful in 8s
probe / r1-wrangler-only (push) Failing after 7s
probe / r2a-upload-proven (push) Successful in 12s
probe / r3a-upload-node20 (push) Successful in 8s
Build and Deploy to Cloudflare Pages / deploy (push) Has been skipped
probe / r2b-download-proven (push) Successful in 2s
probe / r3b-download-node20 (push) Successful in 2s

Round 2 (602fd60) put the build job green:

    check / check                        success   6s
    Build and Deploy .../ build          success  20s   <- green
    Build and Deploy .../ deploy         skipped        <- if: guard
    probe / q1-upload-v3-node16          success   7s
    probe / q2-upload-v3-node20          success  22s
    probe / q3-build-for-roundtrip       success  11s
    probe / q4-deploy-dryrun             failure  43s

Every v3 upload works and the build job is fixed. But q4 -- the deploy-side
rehearsal, which downloads the artifact in the pinned node container and
installs the pinned wrangler, stopping short of the publish call -- failed.
That is a break the deploy job would have hit on main, in a job nobody has
ever been able to run.

q4 bundled two things together, so round 3 splits them:

- r1 runs only the wrangler install and invocation. Worth measuring rather
  than assuming: wrangler 4.120.0 declares engines.node >= 22 and the deploy
  container is node 20, though the pre-issue deploy did run an unpinned
  wrangler on node:20 successfully.
- r2a/r2b run the artifact round trip with no wrangler at all.
- r3a/r3b do the same for the newer node20 artifact builds, so the choice
  between the two pairs is made on measurement.

deploy.yml meanwhile moves to the artifact commits that the mutable `@v3`
references were actually resolving to while this site was deploying, rather
than to the newest thing on the v3 line:

- upload-artifact   -> ff15f030 (v3.2.1)
- download-artifact -> 9bc31d5c (v3.0.2)

That is the conservative reading of what this issue is for: pin what is known
to work, do not take a version bump for free on the way past.
This commit is contained in:
2026-08-09 02:55:51 +00:00
parent 602fd609e7
commit 07af755d1e
2 changed files with 84 additions and 70 deletions

View File

@@ -59,11 +59,12 @@ jobs:
# identical to this one but ending in upload-artifact v4 fails, # identical to this one but ending in upload-artifact v4 fails,
# while the same job without that step passes. So this stays on # while the same job without that step passes. So this stays on
# the v3 line, pinned, using the node20 build of it rather than # the v3 line, pinned, using the node20 build of it rather than
# the node16 default. Revisit when the artifact v4 protocol works # here; tracked separately. This is the exact commit the mutable
# here; tracked separately. # `@v3` used to resolve to, i.e. the code that was deploying this
# site before this issue -- now pinned instead of floating.
- name: Upload artifact - name: Upload artifact
# actions/upload-artifact v3.2.2-node20, 2026-08-09 # actions/upload-artifact v3.2.1, 2026-08-09
uses: actions/upload-artifact@c6a3b2bd78b3985e4b2f15397fec357f0fd808de uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5
with: with:
name: site name: site
path: site.tar.gz path: site.tar.gz
@@ -83,9 +84,11 @@ jobs:
steps: steps:
# Must match the upload-artifact major above -- v4 artifacts and # Must match the upload-artifact major above -- v4 artifacts and
# v3 artifacts are different protocols and do not interoperate. # v3 artifacts are different protocols and do not interoperate.
# Like the upload above, this is the exact commit `@v3` used to
# resolve to.
- name: Download artifact - name: Download artifact
# actions/download-artifact v3.1.0-node20, 2026-08-09 # actions/download-artifact v3.0.2, 2026-08-09
uses: actions/download-artifact@ad191675b41f6a5b46da9a048cb6893812da158b uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
with: with:
name: site name: site

View File

@@ -3,11 +3,9 @@
# The Actions jobs/logs API is not readable by this account, so the only # The Actions jobs/logs API is not readable by this account, so the only
# available signal is the commit-status API, which reports one entry per # available signal is the commit-status API, which reports one entry per
# *job*. This file therefore encodes the diagnosis as job topology: each job # *job*. This file therefore encodes the diagnosis as job topology: each job
# below isolates one hypothesis, and each shows up as its own status context, # isolates one hypothesis and surfaces as its own status context.
# so one push tests them all.
# #
# Round 1 result (commit 2d328e7), which is what these round 2 jobs follow up # Round 1 (2d328e7):
# on:
# #
# p1 bare alpine + checkout failure 3s # p1 bare alpine + checkout failure 3s
# p2 alpine + apk nodejs git tar + checkout success 5s # p2 alpine + apk nodejs git tar + checkout success 5s
@@ -16,10 +14,21 @@
# p5 node:20-alpine + checkout success 8s # p5 node:20-alpine + checkout success 8s
# p6 node:20-bookworm-slim + checkout success 11s # p6 node:20-bookworm-slim + checkout success 11s
# #
# So the pinned alpine image and the runner-prerequisite step are fine, the # -> the pinned alpine image, the prerequisite step and the site build are all
# site build inside the Actions container is fine, and the thing that fails is # fine; upload-artifact v4 is what broke the deploy.
# actions/upload-artifact v4 -- the one step this issue changed protocol on. #
# Round 2 checks which pinned v3 build works and rehearses the deploy job. # Round 2 (602fd60):
#
# build (deploy.yml, upload v3.2.2-node20) success 20s
# q1 upload-artifact v3.2.1 (node16) success 7s
# q2 upload-artifact v3.2.1-n20 (node20) success 22s
# q3 full build + upload v3.2.2-node20 success 11s
# q4 download v3.1.0-node20 + wrangler install failure 43s
#
# -> build is green, every v3 upload works, and the remaining failure is
# somewhere in the deploy-side rehearsal. Round 3 splits q4 into its parts:
# wrangler on its own, the artifact pair that was actually deploying this
# site before this issue, and the newer node20 artifact pair.
name: probe name: probe
on: on:
@@ -28,50 +37,24 @@ on:
- pin-deploy-refs-observable - pin-deploy-refs-observable
jobs: jobs:
# Fallback A: the exact v3 the workflow used before this issue (node16 # Isolates the wrangler install and invocation from anything to do with
# runtime), pinned. # artifacts. wrangler 4.120.0 declares engines.node >= 22 while the deploy
q1-upload-v3-node16: # container is node 20, so this needs measuring rather than assuming --
# the pre-issue deploy did run an unpinned wrangler on node:20
# successfully.
r1-wrangler-only:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
# alpine 3.21, 2026-02-28 # node 20.20.2-bookworm, 2026-08-09
image: alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709 image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5
defaults:
run:
shell: sh
steps: steps:
- run: apk add --no-cache nodejs git tar # wrangler 4.120.0, 2026-08-09
# actions/checkout v4.2.2, 2026-02-28 - run: npm install -g wrangler@4.120.0
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - run: wrangler --version
- run: tar -czf probe-a.tar.gz hugo.toml
# actions/upload-artifact v3.2.1, 2026-08-09
- uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5
with:
name: probe-a
path: probe-a.tar.gz
# Fallback B: same release, node20 runtime. # Producer for the pair that `@v3`/`@v3` resolved to before this issue,
q2-upload-v3-node20: # i.e. the code that was actually deploying the site, now pinned.
runs-on: ubuntu-latest r2a-upload-proven:
container:
# alpine 3.21, 2026-02-28
image: alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709
defaults:
run:
shell: sh
steps:
- run: apk add --no-cache nodejs git tar
# actions/checkout v4.2.2, 2026-02-28
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- run: tar -czf probe-b.tar.gz hugo.toml
# actions/upload-artifact v3.2.1-node20, 2026-08-09
- uses: actions/upload-artifact@c24449f33cd45d4826c6702db7e49f7cdb9b551d
with:
name: probe-b
path: probe-b.tar.gz
# Producer half of the round-trip rehearsal: byte-for-byte the build job
# from deploy.yml.
q3-build-for-roundtrip:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
# alpine 3.21, 2026-02-28 # alpine 3.21, 2026-02-28
@@ -88,21 +71,53 @@ jobs:
- run: script/bootstrap - run: script/bootstrap
- run: script/test - run: script/test
- run: tar -czf site.tar.gz public - run: tar -czf site.tar.gz public
# actions/upload-artifact v3.2.1, 2026-08-09
- uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5
with:
name: site-proven
path: site.tar.gz
# Consumer half: the deploy job's artifact handling, with no wrangler, so
# a failure here means the artifact round trip and a pass here means it is
# sound.
r2b-download-proven:
runs-on: ubuntu-latest
needs: r2a-upload-proven
container:
# node 20.20.2-bookworm, 2026-08-09
image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5
steps:
# actions/download-artifact v3.0.2, 2026-08-09
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
with:
name: site-proven
- run: tar -xzf site.tar.gz
- run: test -f public/index.html
# The newer node20 artifact pair, kept in the round so the choice between
# the two pairs rests on measurement rather than preference.
r3a-upload-node20:
runs-on: ubuntu-latest
container:
# alpine 3.21, 2026-02-28
image: alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709
defaults:
run:
shell: sh
steps:
- run: apk add --no-cache nodejs git tar
# actions/checkout v4.2.2, 2026-02-28
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- run: tar -czf alt.tar.gz hugo.toml
# actions/upload-artifact v3.2.2-node20, 2026-08-09 # actions/upload-artifact v3.2.2-node20, 2026-08-09
- uses: actions/upload-artifact@c6a3b2bd78b3985e4b2f15397fec357f0fd808de - uses: actions/upload-artifact@c6a3b2bd78b3985e4b2f15397fec357f0fd808de
with: with:
name: site name: alt-node20
path: site.tar.gz path: alt.tar.gz
# Consumer half: the deploy job with everything except the publish call. r3b-download-node20:
# Same pinned node image, same pinned download action, same pinned
# wrangler version -- it just prints wrangler's version instead of running
# `wrangler pages deploy`, so it touches nothing external and needs no
# token. This is as close to exercising the deploy job as is possible
# without actually deploying.
q4-deploy-dryrun:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: q3-build-for-roundtrip needs: r3a-upload-node20
container: container:
# node 20.20.2-bookworm, 2026-08-09 # node 20.20.2-bookworm, 2026-08-09
image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5 image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5
@@ -110,9 +125,5 @@ jobs:
# actions/download-artifact v3.1.0-node20, 2026-08-09 # actions/download-artifact v3.1.0-node20, 2026-08-09
- uses: actions/download-artifact@ad191675b41f6a5b46da9a048cb6893812da158b - uses: actions/download-artifact@ad191675b41f6a5b46da9a048cb6893812da158b
with: with:
name: site name: alt-node20
- run: tar -xzf site.tar.gz - run: test -f alt.tar.gz
- run: test -f public/index.html
# wrangler 4.120.0, 2026-08-09
- run: npm install -g wrangler@4.120.0
- run: wrangler --version