Repository navigation
publish: deploy tags via a workflow_dispatch trampoline (fix tag-after-merge wedge) - #13
Merged
Merged
Conversation
coretl
force-pushed
the
fix/pages-deploy-unique-build-version
branch
from
June 25, 2026 14:09
bf50b44 to
e13f5b6
Compare
…r-merge wedge) A release tagged on the merge commit shares the default branch's just-deployed SHA. actions/deploy-pages stamps pages_build_version = GITHUB_SHA, which can't be changed (no input; a custom value 404s, server-validated against the OIDC commit claim — actions/deploy-pages#383). The Pages backend then silently DROPS a second deploy of an already-deployed SHA on a non-workflow_dispatch event: it reports success and flips the deployment record active, but the origin keeps serving the first artifact. So an inline tag deploy "succeeds" while the site stays on the pre-tag build — the recurring tag-after-merge wedge. Confirmed 2026-06-25 + actions/deploy-pages#383's controlled matrix (same SHA, identical pages_build_version): a workflow_dispatch deploy of that SHA is the one event type that FORCES the origin to re-serve. It's event-type, not timing. Fix: tags don't deploy inline. - ci.yml: the `publish` job now excludes tags (ref_type != 'tag'); a new `publish-tag` job (needs [release], actions: write) re-triggers publish.yml via `gh workflow run --ref <default-branch>` (workflow_dispatch). The dispatched run re-gathers from durable sources (incl. the new release) and deploys, re-serving. - publish.yml: revert to stock actions/deploy-pages (the env-override on main was a no-op — GITHUB_SHA is protected; the direct-API custom build version 404s). Keep the post-deploy origin Verify step as the backstop. - main/internal-PR deploys are the first of their SHA, so they serve fine inline and keep PR/commit visibility. Downstream: consumers can't dispatch publish.yml cross-repo, so they trampoline via a small publish-dispatch.yml wrapper (also the fork-preview opt-in). Docs updated: tutorial (required wrapper + publish-tag job), architecture (the mechanism), workflow reference, and CLAUDE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
coretl
force-pushed
the
fix/pages-deploy-unique-build-version
branch
from
June 25, 2026 14:42
e13f5b6 to
10f50f1
Compare
This branch was previously deployed
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.
Problem
Releases tagged shortly after a merge to the default branch deploy "successfully" but never go live — the site stays frozen on the pre-tag build. PRs, plain merges, and manual dispatches all work; only tag-after-merge wedges.
Root cause (diagnosed 2026-06-25, corroborated by actions/deploy-pages#383)
A release tag is cut on the merge commit, so it shares the default branch's just-deployed SHA.
actions/deploy-pagesstamps every deployment withpages_build_version = GITHUB_SHAand there's no way to change it:GITHUB_SHAis a protected default var (env override is ignored), and a custom value sent via the API 404s (server-validated against the OIDC commit claim — so a fork can't fix it either).The Pages backend then silently drops a second deploy of an already-deployed SHA on a non-
workflow_dispatchevent: it reports success and flips the deployment record active, but the origin keeps serving the first artifact.The decisive detail (from #383's controlled matrix — same SHA, identical
pages_build_version): aworkflow_dispatchdeploy of that SHA is the one event type that forces a re-serve. It's event-type, not timing. That also re-explains our own runs: main push #1 served, tag push #2 (same SHA) dropped, manualworkflow_dispatch#3 (same SHA) served.Fix: tags deploy via a
workflow_dispatchtrampolineci.yml— thepublishjob now excludes tags (github.ref_type != 'tag'). A newpublish-tagjob (needs: [release],actions: write) re-triggerspublish.ymlviagh workflow run --ref <default-branch>(aworkflow_dispatch). That run re-gathers from durable sources (incl. the just-created release) and deploys — re-serving because the event isworkflow_dispatch.publish.yml— reverted to stockactions/deploy-pages@v4(the earlier env-override onmainwas a no-op; the direct-API custom build version 404s). The post-deploy origin Verify step stays as the backstop.main/internal-PR deploys are the first of their SHA, so they serve fine inline and keep PR/commit visibility.Downstream consumers
Consumers can't
workflow_dispatcha reusable workflow cross-repo, so they trampoline via a smallpublish-dispatch.ymlwrapper in their own repo — which doubles as the fork-PR preview opt-in (optionalprinput). Docs updated: the tutorial (now-required wrapper +publish-tagjob), the architecture explanation (mechanism), the workflow reference, andCLAUDE.md.Supersedes
This replaces this PR's earlier unique-
pages_build_versionapproach, which is a dead end (the API 404s on any non-SHA build version — see #383).Test plan
Merge, then ~1 min later cut a tag on the merge commit. Expect:
publish-tagdispatchespublish.yml; the dispatchedworkflow_dispatchrun deploys and its Verify step passes; the new version goes live with no manual step. (Theci.ymltrampoline logic must be on the tagged commit, so this is validated post-merge.)🤖 Generated with Claude Code