WORKFLOW.md D4.5, as of #1215, names Re-run all jobs as the recovery for a failed package push whose branch tip has moved. That route re-executes the build leaves, which re-upload their artifacts under fixed names into a run that may still hold artifacts of those names. Whether that succeeds decides whether the documented recovery works, and nothing in the tree settles it.
The collision
Every build leaf uploads under a fixed, branch-suffixed name with actions/upload-artifact pinned at v7.0.1, and none sets overwrite:
.github/actions/nuget-build-default/action.yml uploads nuget-build-<branch> and release-asset-<branch>-nuget
.github/actions/pypi-build-default/action.yml uploads pypi-build-<branch>
.github/actions/dotnet-publish-default/action.yml uploads release-asset-<branch>-dotnet-publish
That action's own README states the default: "If false, the action will fail if an artifact for the given name already exists." Artifacts belong to the run rather than to one attempt, so a re-run of a run that still holds the name would hit it.
Why the recovery reaches that case
D5.2 gates the package-artifact delete on !cancelled() && steps.<download-step-id>.outcome == 'success', so on the ordinary failed-push path the delete runs and the name is free. Two paths leave it occupied:
- D5.3 leaves the delete best-effort.
continue-on-error: true plus a script that turns a failed DELETE into a ::warning:: means a failed delete is silent, and the artifact survives.
- On a re-run replaying a push event with the tag already cut, D4.4's no-op leg skips the release-create, and D5.2 skips the paired
release-asset-* delete with it. That one is deterministic rather than a best-effort failure, so a second full re-run meets an occupied name by design.
retention-days: 1 (D5.4) bounds the window to roughly a day, which is exactly when an operator reaches for the recovery.
The contradictory evidence in the tree
.github/workflows/build-release-task.yml's asset-delete step comments "It deletes every matching id, because a rerun can upload duplicates". That asserts a re-run does upload a duplicate name, which reads as pre-v4 upload-artifact behaviour that the pinned v7 no longer has. D5.3's "deletes all matching ids" rule exists for that same older reading. One of the two is stale and the contract now leans on which.
What needs deciding
- Set
overwrite: true on the build leaves' uploads. Dissolves the collision, makes the recovery unconditional, and retires the "a rerun can upload duplicates" comment and D5.3's all-ids rationale if they are indeed stale.
- Leave it and document the bound. D4.5 gains a fourth qualification saying the full re-run reds at the upload where an artifact survived, and that
--failed is the route in exactly that case.
- The collision does not occur for a reason not yet identified, in which case the comment above is stale and should say so.
Verification owed
GitHub documents nothing about artifact visibility across run attempts, in either the action README or the re-run docs. Settling this needs a real run: fail a package push, let the delete fail or take the skipped-delete path, then Re-run all jobs and observe whether the leaf's upload succeeds. That is a real publish against a real registry, so it is the maintainer's to run rather than an agent's.
Related
Found by the adversarial passes on #1215, which documented the recovery this bears on. Related to #1200 and #1212, which carry the other section 4 and condensed-catalog defects.
WORKFLOW.mdD4.5, as of #1215, names Re-run all jobs as the recovery for a failed package push whose branch tip has moved. That route re-executes the build leaves, which re-upload their artifacts under fixed names into a run that may still hold artifacts of those names. Whether that succeeds decides whether the documented recovery works, and nothing in the tree settles it.The collision
Every build leaf uploads under a fixed, branch-suffixed name with
actions/upload-artifactpinned at v7.0.1, and none setsoverwrite:.github/actions/nuget-build-default/action.ymluploadsnuget-build-<branch>andrelease-asset-<branch>-nuget.github/actions/pypi-build-default/action.ymluploadspypi-build-<branch>.github/actions/dotnet-publish-default/action.ymluploadsrelease-asset-<branch>-dotnet-publishThat action's own README states the default: "If false, the action will fail if an artifact for the given name already exists." Artifacts belong to the run rather than to one attempt, so a re-run of a run that still holds the name would hit it.
Why the recovery reaches that case
D5.2 gates the package-artifact delete on
!cancelled() && steps.<download-step-id>.outcome == 'success', so on the ordinary failed-push path the delete runs and the name is free. Two paths leave it occupied:continue-on-error: trueplus a script that turns a failedDELETEinto a::warning::means a failed delete is silent, and the artifact survives.release-asset-*delete with it. That one is deterministic rather than a best-effort failure, so a second full re-run meets an occupied name by design.retention-days: 1(D5.4) bounds the window to roughly a day, which is exactly when an operator reaches for the recovery.The contradictory evidence in the tree
.github/workflows/build-release-task.yml's asset-delete step comments "It deletes every matching id, because a rerun can upload duplicates". That asserts a re-run does upload a duplicate name, which reads as pre-v4upload-artifactbehaviour that the pinned v7 no longer has. D5.3's "deletes all matching ids" rule exists for that same older reading. One of the two is stale and the contract now leans on which.What needs deciding
overwrite: trueon the build leaves' uploads. Dissolves the collision, makes the recovery unconditional, and retires the "a rerun can upload duplicates" comment and D5.3's all-ids rationale if they are indeed stale.--failedis the route in exactly that case.Verification owed
GitHub documents nothing about artifact visibility across run attempts, in either the action README or the re-run docs. Settling this needs a real run: fail a package push, let the delete fail or take the skipped-delete path, then Re-run all jobs and observe whether the leaf's upload succeeds. That is a real publish against a real registry, so it is the maintainer's to run rather than an agent's.
Related
Found by the adversarial passes on #1215, which documented the recovery this bears on. Related to #1200 and #1212, which carry the other section 4 and condensed-catalog defects.