Observation
quarto-publish.yml's deploy step sets clean: true and clean-exclude: pr-preview/, but leaves force at JamesIves/github-pages-deploy-action's default, which is true. So every main-site publish force-pushes gh-pages.
clean-exclude preserves whatever pr-preview/ content existed as of the deploy job's own checkout of gh-pages, so the ordinary case is fine. The exposure is a preview deploy landing on gh-pages in the window between that checkout and the force push: a non-force push would be rejected and retried, while a force push discards it silently. The affected PR's preview link then 404s with nothing red anywhere to indicate why.
Nothing serializes the two halves against each other. quarto-publish.yml uses concurrency: gh-pages; preview-deploy.yml uses preview-deploy-<head_repository.id>-<head_branch>. Two different groups, so they can run concurrently by construction.
Why it may not be worth changing
The window is narrow and the consequence is a stale preview rather than a lost main site, which self-heals on the PR's next push. Setting force: false trades that for a deploy that can fail on a genuinely concurrent write, which is arguably worse for the main site.
The cheaper fix, if this is worth fixing at all, is probably to put both workflows in the same concurrency group — gh-pages — with cancel-in-progress: false, so they queue rather than race. That leaves the force push in place and removes the window entirely.
Where this came from
Noticed while migrating d-morrison/macros off a hand-rolled publish.yml that passed force: false explicitly (macros#83). The migration adopts gha's behaviour as-is; this issue records the difference rather than blocking on it.
Observation
quarto-publish.yml's deploy step setsclean: trueandclean-exclude: pr-preview/, but leavesforceatJamesIves/github-pages-deploy-action's default, which istrue. So every main-site publish force-pushesgh-pages.clean-excludepreserves whateverpr-preview/content existed as of the deploy job's own checkout ofgh-pages, so the ordinary case is fine. The exposure is a preview deploy landing ongh-pagesin the window between that checkout and the force push: a non-force push would be rejected and retried, while a force push discards it silently. The affected PR's preview link then 404s with nothing red anywhere to indicate why.Nothing serializes the two halves against each other.
quarto-publish.ymlusesconcurrency: gh-pages;preview-deploy.ymlusespreview-deploy-<head_repository.id>-<head_branch>. Two different groups, so they can run concurrently by construction.Why it may not be worth changing
The window is narrow and the consequence is a stale preview rather than a lost main site, which self-heals on the PR's next push. Setting
force: falsetrades that for a deploy that can fail on a genuinely concurrent write, which is arguably worse for the main site.The cheaper fix, if this is worth fixing at all, is probably to put both workflows in the same concurrency group —
gh-pages— withcancel-in-progress: false, so they queue rather than race. That leaves the force push in place and removes the window entirely.Where this came from
Noticed while migrating
d-morrison/macrosoff a hand-rolledpublish.ymlthat passedforce: falseexplicitly (macros#83). The migration adopts gha's behaviour as-is; this issue records the difference rather than blocking on it.