fix(ci): derive publish channel from trigger to end 409 race #39

Merged
David merged 1 commit from fix/GOV-14-trigger-derived-publish-channels into main 2026-06-25 10:26:28 +02:00
Owner

Problem

.forgejo/workflows/build-windows.yml triggers on push to BOTH branches: [main] and tags: [v*]. A release commit is simultaneously a push to main and the v* tag push, so both events fire. Both runs resolved their publish tag set from git describe via oci-build/get-tags.nu --joined, which on a tagged commit yields [<version>, latest] for BOTH events. The two runs then raced to DELETE-then-PUT the same immutable generic-package file at the <version> channel, producing intermittent 409 package file already exists (CLAUDE-122 / GOV-13) and red release CI.

Fix

Resolve the publish channel from the workflow TRIGGER instead of git describe, so the two events publish DISJOINT channels. A tag push (github.ref_type == 'tag') publishes the <version> channel (the tag name); a push to main publishes ONLY latest. This removes the concurrent writer on the immutable <version> generic-package file. latest still tracks the release commit because the tag sits on the same SHA pushed to main.

The change is confined to the Get artifact tags step; the downstream publish and print steps that loop over the resolved channels are unchanged. This repo has no release-only channels beyond <version> and latest, so the mapping is exactly tag-push -> <version>, main-push -> latest.

This mirrors the fix proven in CI on the monkey repo (PR #51).

Validation

just pre-commit (fmt + clippy + build + test in the CI builder image) passes. The change is YAML-only; no source code touched.

#GOV-14
#GOV-13
#CLAUDE-122

## Problem `.forgejo/workflows/build-windows.yml` triggers on push to BOTH `branches: [main]` and `tags: [v*]`. A release commit is simultaneously a push to main and the `v*` tag push, so both events fire. Both runs resolved their publish tag set from `git describe` via `oci-build/get-tags.nu --joined`, which on a tagged commit yields `[<version>, latest]` for BOTH events. The two runs then raced to DELETE-then-PUT the same immutable generic-package file at the `<version>` channel, producing intermittent `409 package file already exists` (CLAUDE-122 / GOV-13) and red release CI. ## Fix Resolve the publish channel from the workflow TRIGGER instead of `git describe`, so the two events publish DISJOINT channels. A tag push (`github.ref_type == 'tag'`) publishes the `<version>` channel (the tag name); a push to main publishes ONLY `latest`. This removes the concurrent writer on the immutable `<version>` generic-package file. `latest` still tracks the release commit because the tag sits on the same SHA pushed to main. The change is confined to the `Get artifact tags` step; the downstream publish and print steps that loop over the resolved channels are unchanged. This repo has no release-only channels beyond `<version>` and `latest`, so the mapping is exactly tag-push -> `<version>`, main-push -> `latest`. This mirrors the fix proven in CI on the `monkey` repo (PR #51). ## Validation `just pre-commit` (fmt + clippy + build + test in the CI builder image) passes. The change is YAML-only; no source code touched. #GOV-14 #GOV-13 #CLAUDE-122
fix(ci): derive publish channel from trigger to end 409 race
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 16s
Create release / Create release from merged PR (pull_request) Has been skipped
46c1db4093
The build-windows workflow triggers on push to both branches:[main] and tags:[v*]. A release commit is simultaneously a push to main and the v* tag push, so both events fire. Both runs resolved their publish tag set from git describe via get-tags.nu --joined, which on a tagged commit yields [<version>, latest] for BOTH events. The two runs then raced to DELETE-then-PUT the same immutable generic-package file at the <version> channel, producing intermittent 409 package file already exists (CLAUDE-122 / GOV-13) and red release CI.

Resolve the publish channel from the workflow TRIGGER instead: a tag push (github.ref_type == 'tag') publishes the <version> channel; a push to main publishes only latest. The two events now publish DISJOINT channels, so neither races to write the immutable <version> file. latest still tracks the release commit because the tag sits on the same SHA pushed to main.

#GOV-14

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
David merged commit c20d170faa into main 2026-06-25 10:26:28 +02:00
David deleted branch fix/GOV-14-trigger-derived-publish-channels 2026-06-25 10:26:28 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
pandoras-box/explorer-bookmarks!39
No description provided.