Fix: trampoline release deploys through workflow_dispatch + smoke check#96
Merged
JamboChen merged 1 commit intoJun 11, 2026
Merged
Conversation
e43a3c5 to
19bfeed
Compare
The Pages backend silently drops the second deployment of a given SHA *on release events specifically*. push and workflow_dispatch deploys at the same SHA are NOT affected (confirmed independently in actions/deploy-pages#383, by typst-community/dev-builds#1, and in our own fork repro: A1 + A3 master-dispatches at SHA 74b7856 both swapped content correctly, while the release-event run at the same SHA was silently dropped). The dual-trigger workflow PR JamboChen#89 added collides on every release: the bump push and the matching release publish always share a SHA. After the bump push deploys (prod = previous tag), the release deploy of the same SHA is dropped server-side: actions/deploy-pages prints 'Reported success!', the deployments API marks the new deployment active and the prior one inactive, but the origin keeps serving the prior tarball. This was the root cause of v0.8.0's main page never advancing from v0.7.0 (live last-modified = 2026-06-05 04:09:29 = the bump push's deploy time, never the release run's 04:11:01). What this commit changes: * New `redispatch` job that fires only on release events. It uses GITHUB_TOKEN's documented exception to recursive-workflow prevention to re-trigger this same workflow as a workflow_dispatch on the default branch. The dispatched run sees the new tag (it exists at release publish time), builds prod from it, and deploys via the Pages-backend code path that DOES swap content at duplicate SHA. * The `deploy` job gains `if: github.event_name != 'release'` so release events skip it entirely and only the trampoline runs. The dispatched run's event_name is workflow_dispatch, the trampoline's if-guard skips, only the deploy job runs -- no recursion. * A post-deploy smoke check that compares the entry-chunk filename in the just-built dist/index.html and dist/beta/index.html against what the live URLs serve, with backoff for CDN propagation. Demoted to safety-net role: the trampoline is the actual fix. The smoke check is here so any future variant of stale-deploy weirdness (CDN regression, upload-artifact bug, a new SHA-keyed dedup mode, etc) becomes a loud CI failure instead of silent prod drift. Alternatives investigated and ruled out: * Step-level `env: GITHUB_SHA: <unique>` and `echo GITHUB_SHA=... >> $GITHUB_ENV` -- the runner re-injects the real commit SHA at every step start; submitted build_version unchanged in both attempts. Per GitHub Actions docs: 'Default environment variables can't be overridden in $GITHUB_ENV.' * Direct POST /repos/{owner}/{repo}/pages/deployments via curl and via gh CLI with explicit Accept + X-GitHub-Api-Version + Bearer/token auth and an explicit OIDC token in the body -- HTTP 404 in every configuration even with pages: write scope and a GET /pages probe returning 200. Confirmed by the #383 thread author and others; the endpoint refuses plain GITHUB_TOKEN. Effectively only the app-context auth that actions/deploy-pages holds internally works. Recovery procedure if the smoke check ever does fire (NOT the daily workflow -- the trampoline handles releases automatically): `git commit --allow-empty -m 'Redeploy' && git push`. Refs: actions/deploy-pages#383, community#170184, typst-community/dev-builds#1.
19bfeed to
2b74721
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Fixes the silent-stale-prod failure mode of PR #89's dual-trigger workflow by trampolining release events through
workflow_dispatchinstead of deploying directly on the release event. Adds a post-deploy smoke check as a safety net for any future variant of the same class of bug.Why (the v0.8.0 main page)
After v0.8.0 was released on 2026-06-05, prod stayed on v0.7.0. As of writing, https://JamboChen.github.io/endfield-calc/ still serves the v0.7.0 bundle
index-CV_olKzG.jswithlast-modified: Fri, 05 Jun 2026 04:09:29 GMT. That timestamp is the bump-push run's deploy time, not the release run's04:11:01deploy time. Beta updated correctly.Both runs reported success and showed
pages_build_version: 74b7856c6bc1f02d9fc240e35cb524fde3981ac4in their deploy step logs.Root cause:
actions/deploy-pages#383The Pages backend silently drops the second deployment of a given SHA on release events specifically.
actions/deploy-pagesprintsReported success!, the deployments API marks the new deployment active and the prior one inactive, but the origin keeps serving the prior tarball.pushandworkflow_dispatchdeployments at the same SHA are not affected. Per the issue thread and independent repro at typst-community/dev-builds#1:pushthenworkflow_dispatchworkflow_dispatchthenworkflow_dispatchpushthenreleasepushthenreleasethenworkflow_dispatchIndependently confirmed on this fork: two consecutive
workflow_dispatchdeploys of74b7856(with a v0.8.0 tag pushed between them) swapped content correctly; the matchingreleaseevent with74b7856did not.PR #89's dual-trigger design collides on every release: the version-bump push and the matching release publish always share a SHA. So every release silently keeps prod on the previous tag.
The fix: release trampoline
GITHUB_TOKENis explicitly permitted to triggerworkflow_dispatch(documented exception to the recursive-workflow prevention rule). So release events don't deploy directly. They re-trigger this same workflow as aworkflow_dispatchon the default branch:Loop-safety: the dispatched run's
github.event_nameisworkflow_dispatch, so the trampoline'sif:skips and onlydeployruns. Verified on the fork (see "Validation" below).Why not other approaches
I tried what the #383 thread discusses and a few alternatives:
env: GITHUB_SHA: <unique>andecho GITHUB_SHA=... >> $GITHUB_ENV: the runner re-injects the real commit SHA at every step start. Submittedbuild_versionunchanged in both attempts. Per GitHub Actions docs: "Default environment variables can't be overridden in$GITHUB_ENV."POST /repos/{owner}/{repo}/pages/deploymentsviacurlandgh apiwith explicitAccept,X-GitHub-Api-Version,Bearer/tokenauth, OIDC token in body, andenvironment: github-pages: HTTP 404 in every configuration even withpages: writescope and aGET /pagesprobe returning 200. Same outcome reported by the #383 author. The endpoint refuses plainGITHUB_TOKEN.The trampoline is the only mechanism I found that's fully automatic, requires no extra permissions on the
deployjob, and works without empty commits.Smoke check (safety net)
A post-deploy step compares the entry-chunk filename (hash-suffixed by Vite, changes whenever source changes) in the just-built
dist/index.htmlanddist/beta/index.htmlagainst the live URLs, with backoff to absorb CDN propagation. Walltime: ~0 to 2s on the happy path, capped at ~6 min on hard failure.The trampoline is the fix; the smoke check is here so any future variant of stale-deploy weirdness (CDN regression, an
upload-pages-artifactbug, a new SHA-keyed dedup mode, etc.) becomes a loud CI failure instead of silent prod drift.End-to-end validation on fork
Reproduced the bug then proved the fix on lsequeiraa/endfield-calc, at fork master SHA
19bfeed628f897948e363dfdd21a2478a10a30b7:redispatchskipped,deploysucceeded in 55s. Submittedpages_build_version: 19bfeed.... Live = v0.7.0 bundleindex-CV_olKzG.js,last-modified: 13:08:44.redispatchran,deployskipped. The trampoline calledgh workflow runon the default branch.deployran (built prod = v0.8.0),redispatchskipped (no recursion). Submittedpages_build_version: 19bfeed..., identical to step 1. Live = v0.8.0 bundleindex-lcwJ2ad_.js,last-modified: 13:10:53, robots hasDisallow: /endfield-calc/beta/. Smoke check passed.Identical SHA, different content, both swapped. Exactly the case where deploy-pages silently fails today.
Tomorrow's v0.8.1 release walkthrough
workflow_dispatch.Zero empty commits, zero manual steps, zero red runs.
Files
.github/workflows/deploy.yml: adds theredispatchjob, guards thedeployjob withif: github.event_name != 'release', adds theSmoke-test live deploymentstep. Inline comments cite #383 and explain the mechanism, the alternatives that don't work, and the smoke-check role.Refs
actions/deploy-pages#383: root cause and prior workaroundscommunity#170184: discussion ofpages_build_versionoverridestypst-community/dev-builds#1: independent repro of the event matrix