Follow-up to #181. When that npm/Rust race was closed, the maintainer explicitly identified publish-python.yml as a residual instance of the same push pattern. The Python workflow remains unchanged since its introduction in 683fd5f.
In publish-python.yml on current main, PyPI publication runs before Commit and tag. That step makes one git push origin HEAD:main; a rejection stops it before the tag and GitHub release. The always() summary checks only dry-run/branch state, so it still prints that PyPI publication and tag creation succeeded.
I exercised the checked-in commit/tag block in two clones of a local bare repository:
- Clone A contains the three rewritten Python version/lock files.
- Clone B pushes an unrelated commit to
main while A is waiting.
- A resumes the workflow block under
bash -e -o pipefail.
The push returns 1 (fetch first), and no remote tag exists. A local sentinel representing the preceding upload remains. I did not run a PyPI upload or the production workflow.
The complete public history of this workflow through September 10 contains five dispatches: four succeeded, and the only failure, run 26881356991, stopped at tests before publication. Those runs do not show this post-upload race in production; this report is a current source-path reproduction.
Suggested coverage: unrelated branch advance, conflicting version-file advance, push rejection after a successful upload, and rerun with the version already present. Record publication, branch update, tag, and GitHub Release as separate outcomes. Recovery should preserve the source/artifact identity that was actually published; blindly rebasing and tagging can attach the tag to a newly arrived source change that was never built.
The Python concurrency group serializes Python runs, but not normal merges or the other SDK publishers. Shared serialization reduces overlap; it does not recover an ordinary push rejection.
Disclosure: I maintain dispat and found this while testing release-record recovery. The existing workflow can address the issue directly.
Follow-up to #181. When that npm/Rust race was closed, the maintainer explicitly identified
publish-python.ymlas a residual instance of the same push pattern. The Python workflow remains unchanged since its introduction in 683fd5f.In
publish-python.ymlon currentmain, PyPI publication runs beforeCommit and tag. That step makes onegit push origin HEAD:main; a rejection stops it before the tag and GitHub release. Thealways()summary checks only dry-run/branch state, so it still prints that PyPI publication and tag creation succeeded.I exercised the checked-in commit/tag block in two clones of a local bare repository:
mainwhile A is waiting.bash -e -o pipefail.The push returns 1 (
fetch first), and no remote tag exists. A local sentinel representing the preceding upload remains. I did not run a PyPI upload or the production workflow.The complete public history of this workflow through September 10 contains five dispatches: four succeeded, and the only failure, run 26881356991, stopped at tests before publication. Those runs do not show this post-upload race in production; this report is a current source-path reproduction.
Suggested coverage: unrelated branch advance, conflicting version-file advance, push rejection after a successful upload, and rerun with the version already present. Record publication, branch update, tag, and GitHub Release as separate outcomes. Recovery should preserve the source/artifact identity that was actually published; blindly rebasing and tagging can attach the tag to a newly arrived source change that was never built.
The Python concurrency group serializes Python runs, but not normal merges or the other SDK publishers. Shared serialization reduces overlap; it does not recover an ordinary push rejection.
Disclosure: I maintain dispat and found this while testing release-record recovery. The existing workflow can address the issue directly.