Skip to content

publish: deploy tags via a workflow_dispatch trampoline (fix tag-after-merge wedge) - #13

Merged
coretl merged 1 commit into
mainfrom
fix/pages-deploy-unique-build-version
Jun 25, 2026
Merged

coretl merged 1 commit into
mainfrom
fix/pages-deploy-unique-build-version

Conversation

@coretl

@coretl coretl commented Jun 25, 2026 •

Copy link
Copy Markdown
Contributor

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-pages stamps every deployment with pages_build_version = GITHUB_SHA and there's no way to change it: GITHUB_SHA is 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_dispatch event: 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): a workflow_dispatch deploy 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, manual workflow_dispatch #3 (same SHA) served.

Fix: tags deploy via a workflow_dispatch trampoline

  • ci.yml — the publish job now excludes tags (github.ref_type != 'tag'). A new publish-tag job (needs: [release], actions: write) re-triggers publish.yml via gh workflow run --ref <default-branch> (a workflow_dispatch). That run re-gathers from durable sources (incl. the just-created release) and deploys — re-serving because the event is workflow_dispatch.
  • publish.yml — reverted to stock actions/deploy-pages@v4 (the earlier env-override on main was 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_dispatch a reusable workflow cross-repo, so they trampoline via a small publish-dispatch.yml wrapper in their own repo — which doubles as the fork-PR preview opt-in (optional pr input). Docs updated: the tutorial (now-required wrapper + publish-tag job), the architecture explanation (mechanism), the workflow reference, and CLAUDE.md.

Supersedes

This replaces this PR's earlier unique-pages_build_version approach, 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-tag dispatches publish.yml; the dispatched workflow_dispatch run deploys and its Verify step passes; the new version goes live with no manual step. (The ci.yml trampoline logic must be on the tagged commit, so this is validated post-merge.)

🤖 Generated with Claude Code

@coretl
coretl force-pushed the fix/pages-deploy-unique-build-version branch from bf50b44 to e13f5b6 Compare June 25, 2026 14:09
…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
coretl force-pushed the fix/pages-deploy-unique-build-version branch from e13f5b6 to 10f50f1 Compare June 25, 2026 14:42
@coretl coretl changed the title publish: deploy Pages with a unique build version (fix tag-after-merge wedge) publish: deploy tags via a workflow_dispatch trampoline (fix tag-after-merge wedge) Jun 25, 2026
@coretl
coretl merged commit f83b814 into main Jun 25, 2026
6 checks passed

This branch was previously deployed

1 inactive deployment
github-pages — 10f50f15 Deployed Jun 25, 2026 by coretl via publish / publish #52
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.

1 participant